/*
Компилятор языка программирования
Объектно-ориентированный продвинутый векторный транслятор
Copyright © 2021, 2024 Малик Разработчик
Это свободная программа: вы можете перераспространять ее и/или изменять
ее на условиях Стандартной общественной лицензии GNU в том виде,
в каком она была опубликована Фондом свободного программного обеспечения;
либо версии 3 лицензии, либо (по вашему выбору) любой более поздней версии.
Эта программа распространяется в надежде, что она будет полезной,
но БЕЗО ВСЯКИХ ГАРАНТИЙ; даже без неявной гарантии ТОВАРНОГО ВИДА
или ПРИГОДНОСТИ ДЛЯ ОПРЕДЕЛЕННЫХ ЦЕЛЕЙ. Подробнее см. в Стандартной
общественной лицензии GNU.
Вы должны были получить копию Стандартной общественной лицензии GNU
вместе с этой программой. Если это не так, см.
<https://www.gnu.org/licenses/>.
*/
package ru.malik.elaborarer.avtoo.compiler;
import avt.io.*;
import avt.lang.array.*;
import avt.util.*;
import ru.malik.elaborarer.avtoo.lang.*;
public class CompilerParallelWorker(Object)
{
private int fldIndex;
private int fldTerminates;
private Exception fldException;
private ObjectArray fldTargets;
private final int fldMaxThreads;
private final Thread fldContext;
private final Object fldMonitor;
private final Hashtable fldObjects;
public (int maxThreads) {
fldMaxThreads = maxThreads < 1 ? 1 : maxThreads;
fldContext = Thread.current();
fldMonitor = new Object();
fldObjects = new Hashtable();
}
public void run(CompilerRunnable handler) throws IOException, CompilerException {
if(fldContext != Thread.current())
{
throw new IllegalParallelWorkerState(package.getResourceString("parallelworker.run"));
}
int maxThreads = fldMaxThreads;
int count = Platform.instance.processorNumberOfCores;
Runnable runnable = new CompilerParallelWorkerRunnable(this, handler);
if((count = (count >> 1) + (count & 1)) > maxThreads) count = maxThreads;
fldIndex = 0;
fldException = null;
fldTerminates = count;
Hashtable objects = fldObjects;
objects.clear();
if(!(handler instanceof CompilerThreadObjectCreator))
{
while(count-- > 0)
{
(new Thread(runnable)).start();
}
} else
{
for(CompilerThreadObjectCreator creator = (CompilerThreadObjectCreator) handler; count-- > 0; )
{
Thread thread = new Thread(runnable);
objects[thread] = creator.createThreadObject();
thread.start();
}
}
synchronized with(fldMonitor)
{
do
{
try
{
wait();
}
catch(InterruptedException exception)
{
exception.printStackTrace();
}
} while(fldTerminates > 0);
}
Exception exception = fldException;
if(exception instanceof IOException)
{
throw (IOException) exception;
}
if(exception instanceof CompilerException)
{
throw (CompilerException) exception;
}
if(exception instanceof RuntimeException)
{
throw (RuntimeException) exception;
}
}
public final Object threadObject() {
Hashtable objects = fldObjects;
return objects == null ? null : objects.operator [](Thread.current());
}
public final int maxThreads { read = fldMaxThreads }
public final ObjectArray targets { read = fldTargets, write = setTargets }
protected void setTargets(ObjectArray newTargets) {
if(fldContext != Thread.current())
{
throw new IllegalParallelWorkerState(package.getResourceString("parallelworker.modify"));
}
fldIndex = 0;
fldTargets = newTargets;
}
final void terminate(Exception exception) {
synchronized with(fldMonitor)
{
if(fldException == null) fldException = exception;
if(--fldTerminates <= 0) notify();
}
}
final Object nextTarget() {
Object result = null;
synchronized(fldMonitor)
{
if(fldException == null)
{
int index = fldIndex;
ObjectArray targets = fldTargets;
if(index < (targets == null ? 0 : targets.length))
{
result = targets[index++];
fldIndex = index;
}
}
}
return result;
}
}
final class CompilerParallelWorkerRunnable(Object, Runnable)
{
private final CompilerParallelWorker fldParentWorker;
private final CompilerRunnable fldHandler;
public (CompilerParallelWorker parentWorker, CompilerRunnable handler) {
fldParentWorker = parentWorker;
fldHandler = handler;
}
public void run() {
with(fldParentWorker) for(CompilerRunnable handler = fldHandler; ; )
{
Object target = nextTarget();
if(target == null)
{
terminate(null);
break;
}
if(handler != null) try
{
handler.run(target);
}
catch(Exception exception)
{
terminate(exception);
break;
}
}
}
}