ThreadEntry.avt

Переключить прокрутку окна
Загрузить этот исходный код

/*
    Исходный код среды исполнения ПВТ-ОО.

    Этот исходный код является частью проекта ПВТ-ОО.

    Copyright © 2021 Малик Разработчик

    Это свободная программа: вы можете перераспространять её и/или
    изменять её на условиях Меньшей Стандартной общественной лицензии GNU в том виде,
    в каком она была опубликована Фондом свободного программного обеспечения;
    либо версии 3 лицензии, либо (по вашему выбору) любой более поздней версии.

    Эта программа распространяется в надежде, что она может быть полезна,
    но БЕЗО ВСЯКИХ ГАРАНТИЙ; даже без неявной гарантии ТОВАРНОГО ВИДА
    или ПРИГОДНОСТИ ДЛЯ ОПРЕДЕЛЁННЫХ ЦЕЛЕЙ. Подробнее см. в Меньшей Стандартной
    общественной лицензии GNU.

    Вы должны были получить копию Меньшей Стандартной общественной лицензии GNU
    вместе с этой программой. Если это не так, см.
    <http://www.gnu.org/licenses/>.
*/

package platform.dependent;

public class ThreadEntry(Object)
{
    private static final long STACK_CONTEXT_SIZE = 0x1000L;

    public static void yield() { Kernel32.switchToThread(); }

    public static void startThread(long threadId) {
        if(threadId < Int.MIN_VALUE || threadId > Int.MAX_VALUE)
        {
            throw new IllegalArgumentException("аргумент threadId имеет недопустимое значение");
        }
        long hThread = Kernel32.openThread(Kernel32.THREAD_SUSPEND_RESUME, false, (int) threadId);
        if(hThread == Kernel32.INVALID_HANDLE_VALUE)
        {
            throw new IllegalArgumentException("аргумент threadId имеет недопустимое значение");
        }
        try
        {
            Kernel32.resumeThread(hThread);
        }
        finally
        {
            Kernel32.closeHandle(hThread);
        }
    }

    public static void setThreadPriority(long threadId, int threadPriority) {
        if(threadId < Int.MIN_VALUE || threadId > Int.MAX_VALUE)
        {
            throw new IllegalArgumentException("аргумент threadId имеет недопустимое значение");
        }
        long hThread = Kernel32.openThread(Kernel32.THREAD_SET_LIMITED_INFORMATION, false, (int) threadId);
        if(hThread == Kernel32.INVALID_HANDLE_VALUE)
        {
            throw new IllegalArgumentException("аргумент threadId имеет недопустимое значение");
        }
        try
        {
            Kernel32.setThreadPriority(hThread, toPlatformPriority(threadPriority));
        }
        finally
        {
            Kernel32.closeHandle(hThread);
        }
    }

    public static boolean isAliveThread(long threadId) {
        if(threadId < Int.MIN_VALUE || threadId > Int.MAX_VALUE)
        {
            throw new IllegalArgumentException("аргумент threadId имеет недопустимое значение");
        }
        long hThread = Kernel32.openThread(Kernel32.THREAD_QUERY_LIMITED_INFORMATION, false, (int) threadId);
        if(hThread == Kernel32.INVALID_HANDLE_VALUE)
        {
            throw new IllegalArgumentException("аргумент threadId имеет недопустимое значение");
        }
        try
        {
            int2 result = Kernel32.getExitCodeThread(hThread);
            return result[0] != 0 && result[1] == Kernel32.STILL_ACTIVE;
        }
        finally
        {
            Kernel32.closeHandle(hThread);
        }
    }

    public static int getThreadPriority(long threadId) {
        if(threadId < Int.MIN_VALUE || threadId > Int.MAX_VALUE)
        {
            throw new IllegalArgumentException("аргумент threadId имеет недопустимое значение");
        }
        long hThread = Kernel32.openThread(Kernel32.THREAD_QUERY_LIMITED_INFORMATION, false, (int) threadId);
        if(hThread == Kernel32.INVALID_HANDLE_VALUE)
        {
            throw new IllegalArgumentException("аргумент threadId имеет недопустимое значение");
        }
        try
        {
            return toSystemPriority(Kernel32.getThreadPriority(hThread));
        }
        finally
        {
            Kernel32.closeHandle(hThread);
        }
    }

    public static int countActiveThreads() {
        int result = 0;
        int processId = Kernel32.getCurrentProcessId();
        long hSnapshot = Kernel32.createToolHelp32Snapshot(Kernel32.TH32CS_SNAPTHREAD, 0);
        try
        {
            ThreadEntry32 thrdinfo = new ThreadEntry32() { dwSize = ThreadEntry32.class.structSize };
            long thrdinfoPointer = thrdinfo.getPointer();
            if(Kernel32.thread32First(hSnapshot, thrdinfoPointer) != 0) do
            {
                if(thrdinfo.th32OwnerProcessID == processId) result++;
            } while(Kernel32.thread32Next(hSnapshot, thrdinfoPointer) != 0);
        }
        finally
        {
            Kernel32.closeHandle(hSnapshot);
        }
        return result;
    }

    public static long getCurrentThreadId() { return Kernel32.getCurrentThreadId(); }

    public static native long getCurrentThreadContext();

    public static long2 createThread(Runnable target, int threadPriority) {
        if(target == null)
        {
            throw new NullPointerException("аргумент target равен нулевой ссылке");
        }
        long stackDataSize = getThreadStackDataSize();
        long stackTagsSize = stackDataSize >> 4;
        long stackTotalSize = stackDataSize + stackTagsSize + STACK_CONTEXT_SIZE;
        long startPointer = getThreadProcedurePointer();
        long argumentPointer = getInstancePointer(target);
        long threadContext;
        long threadId = Kernel32.createThread(Kernel32.NULL, stackTotalSize, startPointer, argumentPointer, Kernel32.CREATE_SUSPENDED)[1];
        long hThread = Kernel32.openThread(Kernel32.THREAD_GET_CONTEXT | Kernel32.THREAD_SET_CONTEXT | Kernel32.THREAD_SET_LIMITED_INFORMATION, false, (int) threadId);
        try
        {
            Kernel32.setThreadPriority(hThread, toPlatformPriority(threadPriority));
            ContextX8664 registers = new ContextX8664() { contextFlags = Kernel32.CONTEXT_ALL };
            long registersPointer = registers.getPointer();
            Kernel32.getThreadContext(hThread, registersPointer);
            long stackPointer = registers.rsp;
            stackPointer += (-stackPointer & 0x0fffL) - stackTotalSize;
            threadContext = stackPointer + stackDataSize + stackTagsSize;
            int tags = (int) (stackDataSize >> 4);
            int context = (int) (stackDataSize + stackTagsSize >> 4);
            try
            {
                long2[] stack = (long2[]) long2[].class.newArrayAt(stackPointer, (int) (stackTotalSize >> 4));
                stack[tags - 1] = new long2 { argumentPointer, 0L };
                stack[context - 1] = new long2 { 0L, 0x88L << 56 };
                addref(target);
                stack[context] = new long2 { 0L, stackPointer + 0x1000L };
                stack[context + 1] = new long2 { stackPointer, stackDataSize };
                stack[context + 2] = new long2 { stackPointer + stackDataSize, 0L };
                stack[context + 3] = new long2 { stackPointer + stackDataSize + stackTagsSize - 1L, 0L };
                for(int offset = 4; offset < 0x0100; offset++) stack[context + offset] = 0L;
                registers.r0 = 0L;
                registers.r1 = 0L;
                registers.r2 = 0L;
                registers.r3 = threadContext;
                registers.rsp = stackPointer + stackDataSize - 0x18L;
                registers.rbp = 0L;
                registers.r6 = 0L;
                registers.r7 = 0L;
                registers.r8 = 0L;
                registers.r9 = 0L;
                registers.r10 = 0L;
                registers.r11 = 0L;
                registers.r12 = 0L;
                registers.r13 = 0L;
                registers.r14 = 0L;
                registers.r15 = 0L;
                registers.rip = startPointer;
                registers.mxcsr = 0x1f80;
                registers.fpuMxcsr = 0x1f80;
                registers.fpuMxcsrMask = 0xffff;
                registers.fpuControlWord = 0x037f;
            }
            catch(Exception e)
            {
                e.printStackTrace();
            }
            Kernel32.setThreadContext(hThread, registersPointer);
        }
        finally
        {
            Kernel32.closeHandle(hThread);
        }
        return new long2 { threadId, threadContext };
    }

    public static long[] enumerateActiveThreadIds() {
        int length = 0;
        int processId = Kernel32.getCurrentProcessId();
        long[] result = new long[15];
        long hSnapshot = Kernel32.createToolHelp32Snapshot(Kernel32.TH32CS_SNAPTHREAD, 0);
        try
        {
            ThreadEntry32 thrdinfo = new ThreadEntry32() { dwSize = ThreadEntry32.class.structSize };
            long thrdinfoPointer = thrdinfo.getPointer();
            if(Kernel32.thread32First(hSnapshot, thrdinfoPointer) != 0) do
            {
                if(thrdinfo.th32OwnerProcessID == processId)
                {
                    if(length == result.length)
                    {
                        Array.copy(result, 0, result = new long[(length << 1) + 1], 0, length);
                    }
                    result[length++] = thrdinfo.th32ThreadID;
                }
            } while(Kernel32.thread32Next(hSnapshot, thrdinfoPointer) != 0);
        }
        finally
        {
            Kernel32.closeHandle(hSnapshot);
        }
        if(length != result.length)
        {
            Array.copy(result, 0, result = new long[length], 0, length);
        }
        return result;
    }

    private static native void addref(Object instance);

    private static native void release(Object instance);

    private static void threadProcedure(Runnable target) {
        try { target.run(); } catch(Throwable e) {  }
        release(target);
        Kernel32.exitThread(0);
    }

    private static int toSystemPriority(int platformPriority) {
        switch(platformPriority)
        {
        case Kernel32.THREAD_PRIORITY_IDLE:
            return Thread.MIN_PRIORITY;
        case Kernel32.THREAD_PRIORITY_LOWEST:
            return Thread.LOW_PRIORITY - 1;
        case Kernel32.THREAD_PRIORITY_BELOW_NORMAL:
            return Thread.LOW_PRIORITY;
        default:
            return Thread.NORM_PRIORITY;
        case Kernel32.THREAD_PRIORITY_ABOVE_NORMAL:
            return Thread.HIGH_PRIORITY;
        case Kernel32.THREAD_PRIORITY_HIGHEST:
            return Thread.HIGH_PRIORITY + 1;
        case Kernel32.THREAD_PRIORITY_TIME_CRITICAL:
            return Thread.MAX_PRIORITY;
        }
    }

    private static int toPlatformPriority(int systemPriority) {
        switch(systemPriority)
        {
        case Thread.MIN_PRIORITY:
            return Kernel32.THREAD_PRIORITY_IDLE;
        case Thread.LOW_PRIORITY - 1:
            return Kernel32.THREAD_PRIORITY_LOWEST;
        case Thread.LOW_PRIORITY:
            return Kernel32.THREAD_PRIORITY_BELOW_NORMAL;
        case Thread.NORM_PRIORITY - 1:
        case Thread.NORM_PRIORITY:
        case Thread.NORM_PRIORITY + 1:
            return Kernel32.THREAD_PRIORITY_NORMAL;
        case Thread.HIGH_PRIORITY:
            return Kernel32.THREAD_PRIORITY_ABOVE_NORMAL;
        case Thread.HIGH_PRIORITY + 1:
            return Kernel32.THREAD_PRIORITY_HIGHEST;
        case Thread.MAX_PRIORITY:
            return Kernel32.THREAD_PRIORITY_TIME_CRITICAL;
        default:
            return systemPriority < Thread.MIN_PRIORITY ? Kernel32.THREAD_PRIORITY_IDLE : Kernel32.THREAD_PRIORITY_TIME_CRITICAL;
        }
    }

    private static native long getInstancePointer(Object instance);

    private static native long getThreadProcedurePointer();

    private static native long getThreadStackDataSize();


    private final long fldThreadId;

    public () { fldThreadId = getCurrentThreadId(); }

    public (long threadId) { fldThreadId = threadId; }

    public boolean equals(Object anot) { return anot == this || anot instanceof ThreadEntry && fldThreadId == ((ThreadEntry) anot).fldThreadId; }

    public long hashCodeAsLong() { return fldThreadId; }

    public final long threadId { read = fldThreadId }
}