/*
Исходный код среды исполнения ПВТ-ОО.
Этот исходный код является частью проекта ПВТ-ОО.
Copyright © 2021 Малик Разработчик
Это свободная программа: вы можете перераспространять её и/или
изменять её на условиях Меньшей Стандартной общественной лицензии GNU в том виде,
в каком она была опубликована Фондом свободного программного обеспечения;
либо версии 3 лицензии, либо (по вашему выбору) любой более поздней версии.
Эта программа распространяется в надежде, что она может быть полезна,
но БЕЗО ВСЯКИХ ГАРАНТИЙ; даже без неявной гарантии ТОВАРНОГО ВИДА
или ПРИГОДНОСТИ ДЛЯ ОПРЕДЕЛЁННЫХ ЦЕЛЕЙ. Подробнее см. в Меньшей Стандартной
общественной лицензии GNU.
Вы должны были получить копию Меньшей Стандартной общественной лицензии GNU
вместе с этой программой. Если это не так, см.
<http://www.gnu.org/licenses/>.
*/
package avt.lang;
import platform.dependent.*;
public class Thread(Object, Runnable)
{
public static final int MIN_PRIORITY = 1;
public static final int LOW_PRIORITY = 3;
public static final int NORM_PRIORITY = 5;
public static final int HIGH_PRIORITY = 7;
public static final int MAX_PRIORITY = 9;
private static int count;
private static Thread[] threads;
private static Mutex threadsMutex;
private static EventSet sleepEvents;
private static UncaughtExceptionHandler systemUncaughtExceptionHandler;
private static UncaughtExceptionHandler defaultUncaughtExceptionHandler;
public static void yield() { ThreadEntry.yield(); }
public static void sleep(long timeInMillis) throws InterruptedException {
if(timeInMillis < 0L)
{
throw new IllegalArgumentException("аргумент timeInMillis не может быть отрицательным");
}
if(timeInMillis > 0L)
{
sleepEvents.wait(timeInMillis, current().waitableHandler);
}
}
public static void sleep(long timeInMillis, int timeInNanos) throws InterruptedException {
if(timeInMillis < 0L)
{
throw new IllegalArgumentException("аргумент timeInMillis не может быть отрицательным");
}
if(timeInNanos < 0 || timeInNanos > 999999)
{
throw new IllegalArgumentException("аргумент timeInNanos выходит из диапазона");
}
if(timeInMillis > 0L || timeInNanos > 0)
{
sleepEvents.wait(timeInMillis, timeInNanos, current().waitableHandler);
}
}
public static void setDefaultUncaughtExceptionHandler(UncaughtExceptionHandler handler) { defaultUncaughtExceptionHandler = handler == null ? systemUncaughtExceptionHandler : handler; }
public static boolean holdsLock(Object instance) {
if(instance == null)
{
throw new NullPointerException("аргумент instance равен нулевой ссылке");
}
Mutex reference = instance.monitor;
return reference != null && reference.isHold();
}
public static boolean interrupted() { return current().isInterrupted(); }
public static int activeCount() { return ThreadEntry.countActiveThreads(); }
public static StackTraceElement[] stackTrace() {
StackTraceElement[] result = null;
try
{
int tagsLength = CallStack.getTagsLength();
long dataPointer = CallStack.getDataPointer();
long tagsPointer = CallStack.getTagsPointer();
long2[] stackData = (long2[]) long2[].class.newArrayAt(dataPointer, tagsLength);
byte[] stackTags = (byte[]) byte[].class.newArrayAt(tagsPointer, tagsLength);
int stackPointer = (int) ((CallStack.getPointer() - dataPointer) >> 4);
int returnPointer = Array.indexOf(CallStack.TAG_MLEAVE >>> 8, stackTags, stackPointer, 0);
if(returnPointer >= 0) returnPointer = Array.indexOf(CallStack.TAG_MLEAVE >>> 8, stackTags, returnPointer + 1, 0);
if(returnPointer < 0)
{
result = new StackTraceElement[0];
} else
{
int length = 0;
int limitPointer = Array.indexOf(CallStack.TAG_ILEAVE >>> 24, stackTags, returnPointer + 1, 0);
if(limitPointer < 0) limitPointer = tagsLength;
result = new StackTraceElement[15];
do
{
StackTraceElement element = DebugInfo.createStackTraceElement(stackData[returnPointer][1] - 1L);
if(element != null)
{
if(length == result.length) Array.copy(result, 0, result = new StackTraceElement[(length << 1) + 1], 0, length);
result[length++] = element;
}
} while((returnPointer = Array.indexOf(CallStack.TAG_MLEAVE >>> 8, stackTags, returnPointer + 1, 0)) >= 0 && returnPointer < limitPointer);
if(length < result.length) Array.copy(result, 0, result = new StackTraceElement[length], 0, length);
}
}
catch(Exception e) { }
return result;
}
public static Thread[] enumerate() {
int length = 0;
long[] activeIds = ThreadEntry.enumerateActiveThreadIds();
Thread[] result = new Thread[15];
Mutex globmutex = threadsMutex;
globmutex.lock();
try
{
for(int i = activeIds.length; i-- > 0; )
{
Thread active = query(activeIds[i]);
if(length == result.length)
{
Array.copy(result, 0, result = new Thread[(length << 1) + 1], 0, length);
}
result[length++] = active;
}
}
finally
{
globmutex.unlock();
}
if(length != result.length)
{
Array.copy(result, 0, result = new Thread[length], 0, length);
}
return result;
}
public static StackTraceElement callerTrace() {
StackTraceElement result = null;
try
{
int tagsLength = CallStack.getTagsLength();
long dataPointer = CallStack.getDataPointer();
long tagsPointer = CallStack.getTagsPointer();
long2[] stackData = (long2[]) long2[].class.newArrayAt(dataPointer, tagsLength);
byte[] stackTags = (byte[]) byte[].class.newArrayAt(tagsPointer, tagsLength);
int stackPointer = (int) ((CallStack.getPointer() - dataPointer) >> 4);
int returnPointer = Array.indexOf(CallStack.TAG_MLEAVE >>> 8, stackTags, stackPointer, 0);
if(returnPointer >= 0) returnPointer = Array.indexOf(CallStack.TAG_MLEAVE >>> 8, stackTags, returnPointer + 1, 0);
if(returnPointer >= 0) result = DebugInfo.createStackTraceElement(stackData[returnPointer][1] - 1L);
}
catch(Exception e) { }
return result;
}
public static Thread current() {
long threadId = ThreadEntry.getCurrentThreadId();
Mutex globmutex = threadsMutex;
Thread result;
globmutex.lock();
try
{
result = query(threadId);
}
finally
{
globmutex.unlock();
}
return result;
}
public static native Throwable suppressedThrowable();
public static UncaughtExceptionHandler getDefaultUncaughtExceptionHandler() { return defaultUncaughtExceptionHandler; }
package static void initialize() {
count = 1;
(threads = new Thread[15])[0] = new Thread(ThreadEntry.getCurrentThreadId(), false);
threadsMutex = new Mutex();
sleepEvents = new EventSet();
systemUncaughtExceptionHandler = defaultUncaughtExceptionHandler = new SystemUncaughtExceptionHandler();
}
package static void clean() {
Mutex globmutex = threadsMutex;
globmutex.lock();
try
{
for(int index = count; index-- > 0; ) if(!ThreadEntry.isAliveThread(threads[index].threadId))
{
remove(index);
}
}
finally
{
globmutex.unlock();
}
}
package static StackTraceElement[] stackTrace(long codePointerOverride) {
StackTraceElement[] result = null;
try
{
int tagsLength = CallStack.getTagsLength();
long dataPointer = CallStack.getDataPointer();
long tagsPointer = CallStack.getTagsPointer();
long2[] stackData = (long2[]) long2[].class.newArrayAt(dataPointer, tagsLength);
byte[] stackTags = (byte[]) byte[].class.newArrayAt(tagsPointer, tagsLength);
int stackPointer = (int) ((CallStack.getPointer() - dataPointer) >> 4);
int returnPointer = Array.indexOf(CallStack.TAG_MLEAVE >>> 8, stackTags, stackPointer, 0);
if(returnPointer >= 0) returnPointer = Array.indexOf(CallStack.TAG_MLEAVE >>> 8, stackTags, returnPointer + 1, 0);
if(returnPointer < 0)
{
result = new StackTraceElement[0];
} else
{
boolean first = true;
int length = 0;
int limitPointer = Array.indexOf(CallStack.TAG_ILEAVE >>> 24, stackTags, returnPointer + 1, 0);
if(limitPointer < 0) limitPointer = tagsLength;
result = new StackTraceElement[15];
do
{
StackTraceElement element = DebugInfo.createStackTraceElement((first ? codePointerOverride : stackData[returnPointer][1]) - 1L);
first = false;
if(element != null)
{
if(length == result.length) Array.copy(result, 0, result = new StackTraceElement[(length << 1) + 1], 0, length);
result[length++] = element;
}
} while((returnPointer = Array.indexOf(CallStack.TAG_MLEAVE >>> 8, stackTags, returnPointer + 1, 0)) >= 0 && returnPointer < limitPointer);
if(length < result.length) Array.copy(result, 0, result = new StackTraceElement[length], 0, length);
}
}
catch(Exception e) { }
return result;
}
static void finish(ThreadAuxiliary auxiliary) {
Mutex globmutex = threadsMutex;
globmutex.lock();
try
{
for(int index = count; index-- > 0; ) if(threads[index].fldAuxiliary == auxiliary)
{
remove(index);
break;
}
}
finally
{
globmutex.unlock();
}
}
private static void append(Thread thread) {
if(count == threads.length)
{
Array.copy(threads, 0, threads = new Thread[(count << 1) + 1], 0, count);
}
threads[count++] = thread;
}
private static void remove(int index) {
Array.copy(threads, index + 1, threads, index, --count - index);
threads[count] = null;
}
private static int indexOf(long threadId) {
for(int index = 0; index < count; index++)
{
if(threads[index].threadId == threadId) return index;
}
return -1;
}
private static Thread query(long threadId) {
int index = indexOf(threadId);
if(index >= 0) return threads[index];
Thread result = new Thread(threadId, true);
append(result);
return result;
}
private boolean fldStarted;
private int fldPriority;
private final boolean fldExternal;
private final ThreadAuxiliary fldAuxiliary;
public (Runnable target) {
fldPriority = NORM_PRIORITY;
fldExternal = false;
fldAuxiliary = new ThreadAuxiliary(target == null ? this : target);
}
protected (): this(null) { }
private (long threadId, boolean external) {
fldStarted = true;
fldPriority = ThreadEntry.getThreadPriority(threadId);
fldExternal = external;
fldAuxiliary = new ThreadAuxiliary() { fldThreadId = threadId };
}
public void run() { }
public void start() {
if(isStarted())
{
throw new IllegalThreadStateException("поток исполнения уже был запущен раннее");
}
Runtime.getInstance().setMultiThreaded();
ThreadAuxiliary auxiliary = fldAuxiliary;
Mutex globmutex = threadsMutex;
globmutex.lock();
try
{
append(this);
long2 newThreadAttributes = ThreadEntry.createThread(auxiliary, fldPriority);
long threadId = auxiliary.fldThreadId = newThreadAttributes[0];
ThreadEntry.startThread(threadId);
}
finally
{
globmutex.unlock();
}
}
public void interruptio() {
checkAccess();
fldAuxiliary.interruptio();
}
public boolean isInterrupted() { return fldAuxiliary.isInterrupted(); }
public final void checkAccess() {
if(fldExternal)
{
throw new SecurityException("внешний поток исполнения недоступен для модифицирования");
}
}
public final void join() throws InterruptedException { join(0L, 0); }
public final void join(long timeInMillis) throws InterruptedException { join(timeInMillis, 0); }
public final void join(long timeInMillis, int timeInNanos) throws InterruptedException {
if(fldExternal)
{
throw new IllegalThreadStateException("к внешнему потоку исполнения нельзя присоединиться");
}
if(timeInMillis < 0L)
{
throw new IllegalArgumentException("аргумент timeInMillis не может быть отрицательным");
}
if(timeInNanos < 0 || timeInNanos > 999999)
{
throw new IllegalArgumentException("аргумент timeInNanos выходит из диапазона");
}
fldAuxiliary.join(timeInMillis, timeInNanos);
}
public final boolean isAlive() {
long id = fldAuxiliary.fldThreadId;
return id != 0L && ThreadEntry.isAliveThread(id);
}
public final boolean isExternal() { return fldExternal; }
public final int priority { read = fldPriority, write = setPriority }
public final UncaughtExceptionHandler uncaughtExceptionHandler { read = getUncaughtExceptionHandler, write = setUncaughtExceptionHandler }
protected void setPriority(int priority) {
checkAccess();
if(priority < MIN_PRIORITY) priority = MIN_PRIORITY;
if(priority > MAX_PRIORITY) priority = MAX_PRIORITY;
fldPriority = priority;
long threadId = fldAuxiliary.fldThreadId;
if(threadId != 0L) ThreadEntry.setThreadPriority(threadId, priority);
}
package final long threadId { read = getThreadId }
package final WaitableHandler waitableHandler { read = fldAuxiliary }
private void setUncaughtExceptionHandler(UncaughtExceptionHandler exceptionHandler) { fldAuxiliary.fldExceptionHandler = exceptionHandler; }
private native boolean isStarted();
private long getThreadId() { return fldAuxiliary.fldThreadId; }
private UncaughtExceptionHandler getUncaughtExceptionHandler() { return fldAuxiliary.fldExceptionHandler; }
}
final class ThreadAuxiliary(Object, Runnable, WaitableHandler)
{
long fldThreadId;
UncaughtExceptionHandler fldExceptionHandler;
private boolean fldInterruptedStatus;
private boolean fldJoinable;
private Runnable fldTarget;
private Waitable fldWaitable;
private Object fldJoinMonitor;
private final Mutex fldInterruptedMutex;
public (): this(null) { }
public (Runnable target) {
fldTarget = target;
fldInterruptedMutex = new Mutex();
}
public void run() {
Runnable target;
try
{
try
{
target = fldTarget;
fldTarget = null;
target.run();
}
catch(Throwable exception)
{
UncaughtExceptionHandler handler = fldExceptionHandler;
if(handler == null) handler = Thread.getDefaultUncaughtExceptionHandler();
handler.uncaughtException(Thread.current(), exception);
}
}
finally
{
target = null;
notifyJoined();
Thread.finish(this);
}
}
public void setWaitable(Waitable reference) {
Mutex intrmutex = fldInterruptedMutex;
intrmutex.lock();
try
{
fldWaitable = reference;
if(reference == null)
{
fldInterruptedStatus = false;
} else
{
if(fldInterruptedStatus) reference.interruptio(fldThreadId);
}
}
finally
{
intrmutex.unlock();
}
}
public void join(long timeInMillis, int timeInNanos) throws InterruptedException { synchronized with(getJoinMonitor()) { wait(timeInMillis, timeInNanos); } }
public void interruptio() {
Mutex intrmutex = fldInterruptedMutex;
intrmutex.lock();
try
{
fldInterruptedStatus = true;
Waitable reference = fldWaitable;
if(reference != null) reference.interruptio(fldThreadId);
}
finally
{
intrmutex.unlock();
}
}
public boolean isInterrupted() {
boolean result;
Mutex intrmutex = fldInterruptedMutex;
intrmutex.lock();
try
{
result = fldInterruptedStatus;
fldInterruptedStatus = false;
}
finally
{
intrmutex.unlock();
}
return result;
}
private void notifyJoined() { synchronized with(getJoinMonitor()) { notifyAll(); } }
private native boolean isJoinable();
private Object getJoinMonitor() {
if(isJoinable())
{
Object result;
while((result = fldJoinMonitor) == null) Thread.yield();
return result;
}
return fldJoinMonitor = new Object();
}
}
final class CallStack(Object)
{
public static final int TAG_EMPTY = 0x00;
public static final int TAG_INT = 0x01;
public static final int TAG_INT2 = 0x12;
public static final int TAG_INT4 = 0x14;
public static final int TAG_INT8 = 0x1918;
public static final int TAG_LONG = 0x02;
public static final int TAG_LONG2 = 0x22;
public static final int TAG_LONG4 = 0x2524;
public static final int TAG_LONG8 = 0x2b2a2928;
public static final int TAG_FLOAT = 0x0f;
public static final int TAG_FLOAT2 = 0xf2;
public static final int TAG_FLOAT4 = 0xf4;
public static final int TAG_FLOAT8 = 0xf9f8;
public static final int TAG_DOUBLE = 0x0d;
public static final int TAG_DOUBLE2 = 0xd2;
public static final int TAG_DOUBLE4 = 0xd5d4;
public static final int TAG_DOUBLE8 = 0xdbdad9d8;
public static final int TAG_BYTE2 = 0xb2;
public static final int TAG_BYTE4 = 0xb4;
public static final int TAG_BYTE8 = 0xb8;
public static final int TAG_SHORT2 = 0x52;
public static final int TAG_SHORT4 = 0x54;
public static final int TAG_SHORT8 = 0x58;
public static final int TAG_REAL = 0x07;
public static final int TAG_SUPPRESS = 0x99;
public static final int TAG_OBJECT = 0x88;
public static final int TAG_FLEAVE = 0xef;
public static final int TAG_MLEAVE = 0xcfca;
public static final int TAG_ILEAVE = 0xafaeacaa;
public static native int getTagsLength();
public static native long getPointer();
public static native long getDataPointer();
public static native long getTagsPointer();
private () { }
}
service SystemUncaughtExceptionHandler(Object, UncaughtExceptionHandler)
{
public void uncaughtException(Thread thread, Throwable exception) {
exception.printStackTrace();
Runtime.getInstance().exit(1);
}
}