mirror of https://gitlab.com/nakst/essence
introduce EsWorkQueue
This commit is contained in:
parent
be09af9014
commit
069eb7754f
|
@ -247,12 +247,6 @@ Array<String> bookmarks;
|
||||||
Array<FolderViewSettingsEntry> folderViewSettings;
|
Array<FolderViewSettingsEntry> folderViewSettings;
|
||||||
HashStore<uint64_t, Thumbnail> thumbnailCache;
|
HashStore<uint64_t, Thumbnail> thumbnailCache;
|
||||||
|
|
||||||
// Non-blocking task thread.
|
|
||||||
|
|
||||||
EsHandle nonBlockingTaskWorkAvailable;
|
|
||||||
EsMutex nonBlockingTaskMutex;
|
|
||||||
Array<Task *> nonBlockingTasks;
|
|
||||||
|
|
||||||
// Styles.
|
// Styles.
|
||||||
|
|
||||||
const EsStyle styleFolderView = {
|
const EsStyle styleFolderView = {
|
||||||
|
@ -346,41 +340,20 @@ void BlockingTaskQueue(Instance *instance, Task task) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void NonBlockingTaskThread(EsGeneric) {
|
void NonBlockingTaskWrapper(EsGeneric _task) {
|
||||||
while (true) {
|
Task *task = (Task *) _task.p;
|
||||||
EsWait(&nonBlockingTaskWorkAvailable, 1, ES_WAIT_NO_TIMEOUT);
|
task->callback(nullptr, task);
|
||||||
|
EsMessage m = { MESSAGE_NON_BLOCKING_TASK_COMPLETE };
|
||||||
while (true) {
|
m.user.context2.p = task;
|
||||||
EsMutexAcquire(&nonBlockingTaskMutex);
|
EsMessagePost(nullptr, &m);
|
||||||
|
|
||||||
if (!nonBlockingTasks.Length()) {
|
|
||||||
EsMutexRelease(&nonBlockingTaskMutex);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
Task *task = nonBlockingTasks[0];
|
|
||||||
nonBlockingTasks.Delete(0);
|
|
||||||
EsMutexRelease(&nonBlockingTaskMutex);
|
|
||||||
|
|
||||||
task->callback(nullptr, task);
|
|
||||||
|
|
||||||
EsMessage m = { MESSAGE_NON_BLOCKING_TASK_COMPLETE };
|
|
||||||
m.user.context2.p = task;
|
|
||||||
EsMessagePost(nullptr, &m);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void NonBlockingTaskQueue(Task _task) {
|
void NonBlockingTaskQueue(Task _task) {
|
||||||
// NOTE We can't store instances in tasks on the non-blocking queue thread,
|
// NOTE We can't store instances in tasks on the non-blocking queue thread,
|
||||||
// because the instances might be destroyed while the task is in progress!
|
// because the instances might be destroyed while the task is in progress!
|
||||||
|
|
||||||
Task *task = (Task *) EsHeapAllocate(sizeof(Task), false);
|
Task *task = (Task *) EsHeapAllocate(sizeof(Task), false);
|
||||||
EsMemoryCopy(task, &_task, sizeof(Task));
|
EsMemoryCopy(task, &_task, sizeof(Task));
|
||||||
EsMutexAcquire(&nonBlockingTaskMutex);
|
EsWorkQueue(NonBlockingTaskWrapper, task);
|
||||||
nonBlockingTasks.Add(task);
|
|
||||||
EsMutexRelease(&nonBlockingTaskMutex);
|
|
||||||
EsEventSet(nonBlockingTaskWorkAvailable);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void NonBlockingTaskComplete(EsMessage *message) {
|
void NonBlockingTaskComplete(EsMessage *message) {
|
||||||
|
@ -515,15 +488,6 @@ void _start() {
|
||||||
DriveAdd(prefix, prefixBytes);
|
DriveAdd(prefix, prefixBytes);
|
||||||
}, 0);
|
}, 0);
|
||||||
|
|
||||||
// Start the non-blocking task threads.
|
|
||||||
|
|
||||||
nonBlockingTaskWorkAvailable = EsEventCreate(true /* autoReset */);
|
|
||||||
EsThreadInformation _nonBlockingTaskThread = {};
|
|
||||||
|
|
||||||
for (uintptr_t i = 0; i < EsSystemGetOptimalWorkQueueThreadCount(); i++) {
|
|
||||||
EsThreadCreate(NonBlockingTaskThread, &_nonBlockingTaskThread, nullptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Process messages.
|
// Process messages.
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
|
@ -557,7 +521,6 @@ void _start() {
|
||||||
}
|
}
|
||||||
|
|
||||||
EsAssert(!instances.Length());
|
EsAssert(!instances.Length());
|
||||||
EsHandleClose(nonBlockingTaskWorkAvailable);
|
|
||||||
EsHeapFree(fileTypesBuffer.out);
|
EsHeapFree(fileTypesBuffer.out);
|
||||||
|
|
||||||
bookmarks.Free();
|
bookmarks.Free();
|
||||||
|
@ -568,7 +531,6 @@ void _start() {
|
||||||
knownFileTypes.Free();
|
knownFileTypes.Free();
|
||||||
knownFileTypesByExtension.Free();
|
knownFileTypesByExtension.Free();
|
||||||
loadedFolders.Free();
|
loadedFolders.Free();
|
||||||
nonBlockingTasks.Free();
|
|
||||||
thumbnailCache.Free();
|
thumbnailCache.Free();
|
||||||
#endif
|
#endif
|
||||||
} else if (message->type == ES_MSG_REGISTER_FILE_SYSTEM) {
|
} else if (message->type == ES_MSG_REGISTER_FILE_SYSTEM) {
|
||||||
|
|
|
@ -94,7 +94,7 @@ struct ThreadLocalStorage {
|
||||||
// This must be the first field.
|
// This must be the first field.
|
||||||
ThreadLocalStorage *self;
|
ThreadLocalStorage *self;
|
||||||
|
|
||||||
uint64_t id;
|
EsObjectID id;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct MountPoint : EsMountPoint {
|
struct MountPoint : EsMountPoint {
|
||||||
|
@ -109,6 +109,11 @@ struct Timer {
|
||||||
EsGeneric argument;
|
EsGeneric argument;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct Work {
|
||||||
|
EsWorkCallback callback;
|
||||||
|
EsGeneric context;
|
||||||
|
};
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
Array<EsSystemConfigurationGroup> systemConfigurationGroups;
|
Array<EsSystemConfigurationGroup> systemConfigurationGroups;
|
||||||
EsMutex systemConfigurationMutex;
|
EsMutex systemConfigurationMutex;
|
||||||
|
@ -136,6 +141,10 @@ struct {
|
||||||
uintptr_t performanceTimerStackCount;
|
uintptr_t performanceTimerStackCount;
|
||||||
|
|
||||||
ThreadLocalStorage firstThreadLocalStorage;
|
ThreadLocalStorage firstThreadLocalStorage;
|
||||||
|
|
||||||
|
EsHandle workAvailable;
|
||||||
|
EsMutex workMutex;
|
||||||
|
Array<Work> workQueue;
|
||||||
} api;
|
} api;
|
||||||
|
|
||||||
ptrdiff_t tlsStorageOffset;
|
ptrdiff_t tlsStorageOffset;
|
||||||
|
@ -866,6 +875,9 @@ EsMessage *EsMessageReceive() {
|
||||||
gui.allWindows.Free();
|
gui.allWindows.Free();
|
||||||
calculator.Free();
|
calculator.Free();
|
||||||
HashTableFree(&gui.keyboardShortcutNames, false);
|
HashTableFree(&gui.keyboardShortcutNames, false);
|
||||||
|
EsHandleClose(api.workAvailable); // TODO Waiting for all work to finish.
|
||||||
|
EsAssert(!api.workQueue.Length());
|
||||||
|
api.workQueue.Free();
|
||||||
MemoryLeakDetectorCheckpoint(&heap);
|
MemoryLeakDetectorCheckpoint(&heap);
|
||||||
EsPrint("ES_MSG_APPLICATION_EXIT - Heap allocation count: %d (%d from malloc).\n", heap.allocationsCount, mallocCount);
|
EsPrint("ES_MSG_APPLICATION_EXIT - Heap allocation count: %d (%d from malloc).\n", heap.allocationsCount, mallocCount);
|
||||||
#endif
|
#endif
|
||||||
|
@ -1259,7 +1271,7 @@ uintptr_t EsSystemGetOptimalWorkQueueThreadCount() {
|
||||||
|
|
||||||
void ThreadInitialise(ThreadLocalStorage *local) {
|
void ThreadInitialise(ThreadLocalStorage *local) {
|
||||||
EsMemoryZero(local, sizeof(ThreadLocalStorage));
|
EsMemoryZero(local, sizeof(ThreadLocalStorage));
|
||||||
local->id = EsSyscall(ES_SYSCALL_THREAD_GET_ID, ES_CURRENT_THREAD, 0, 0, 0);
|
EsSyscall(ES_SYSCALL_THREAD_GET_ID, ES_CURRENT_THREAD, (uintptr_t) &local->id, 0, 0);
|
||||||
local->self = local;
|
local->self = local;
|
||||||
EsSyscall(ES_SYSCALL_PROCESS_SET_TLS, (uintptr_t) local - tlsStorageOffset, 0, 0, 0);
|
EsSyscall(ES_SYSCALL_PROCESS_SET_TLS, (uintptr_t) local - tlsStorageOffset, 0, 0, 0);
|
||||||
}
|
}
|
||||||
|
@ -1881,6 +1893,44 @@ void EsTimerCancel(EsTimer id) {
|
||||||
EsMutexRelease(&api.timersMutex);
|
EsMutexRelease(&api.timersMutex);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void WorkThread(EsGeneric) {
|
||||||
|
while (true) {
|
||||||
|
EsWait(&api.workAvailable, 1, ES_WAIT_NO_TIMEOUT);
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
EsMutexAcquire(&api.workMutex);
|
||||||
|
|
||||||
|
if (api.workQueue.Length()) {
|
||||||
|
Work work = api.workQueue[0];
|
||||||
|
api.workQueue.Delete(0);
|
||||||
|
EsMutexRelease(&api.workMutex);
|
||||||
|
work.callback(work.context);
|
||||||
|
} else {
|
||||||
|
EsMutexRelease(&api.workMutex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void EsWorkQueue(EsWorkCallback callback, EsGeneric context) {
|
||||||
|
EsMutexAcquire(&api.workMutex);
|
||||||
|
|
||||||
|
if (!api.workAvailable) {
|
||||||
|
api.workAvailable = EsEventCreate(true /* autoReset */);
|
||||||
|
EsThreadInformation thread = {};
|
||||||
|
|
||||||
|
for (uintptr_t i = 0; i < EsSystemGetOptimalWorkQueueThreadCount(); i++) {
|
||||||
|
EsThreadCreate(WorkThread, &thread, nullptr);
|
||||||
|
EsHandleClose(thread.handle);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Work work = { callback, context };
|
||||||
|
api.workQueue.Add(work);
|
||||||
|
EsMutexRelease(&api.workMutex);
|
||||||
|
EsEventSet(api.workAvailable);
|
||||||
|
}
|
||||||
|
|
||||||
#ifndef ENABLE_POSIX_SUBSYSTEM
|
#ifndef ENABLE_POSIX_SUBSYSTEM
|
||||||
void EsPOSIXInitialise(int *, char ***) {
|
void EsPOSIXInitialise(int *, char ***) {
|
||||||
while (true) {
|
while (true) {
|
||||||
|
|
|
@ -1905,6 +1905,7 @@ function_pointer void EsListViewEnumerateVisibleItemsCallback(EsListView *view,
|
||||||
function_pointer void EsFontEnumerationCallback(const EsFontInformation *information, EsGeneric context);
|
function_pointer void EsFontEnumerationCallback(const EsFontInformation *information, EsGeneric context);
|
||||||
function_pointer void EsUserTaskCallback(EsUserTask *task, EsGeneric data);
|
function_pointer void EsUserTaskCallback(EsUserTask *task, EsGeneric data);
|
||||||
function_pointer bool EsFileCopyCallback(EsFileOffset bytesCopied, EsFileOffset totalBytes, EsGeneric data); // Return false to cancel.
|
function_pointer bool EsFileCopyCallback(EsFileOffset bytesCopied, EsFileOffset totalBytes, EsGeneric data); // Return false to cancel.
|
||||||
|
function_pointer void EsWorkCallback(EsGeneric context);
|
||||||
|
|
||||||
// System.
|
// System.
|
||||||
|
|
||||||
|
@ -1985,16 +1986,19 @@ function EsError EsDeviceControl(EsHandle handle, EsDeviceControlType type, void
|
||||||
|
|
||||||
function EsError EsProcessCreate(EsProcessCreationArguments *arguments, EsProcessInformation *information);
|
function EsError EsProcessCreate(EsProcessCreationArguments *arguments, EsProcessInformation *information);
|
||||||
function int EsProcessGetExitStatus(EsHandle process);
|
function int EsProcessGetExitStatus(EsHandle process);
|
||||||
function EsObjectID EsProcessGetID(EsHandle process);
|
function EsObjectID EsProcessGetID(EsHandle process);
|
||||||
function void EsProcessGetState(EsHandle process, EsProcessState *state);
|
function void EsProcessGetState(EsHandle process, EsProcessState *state);
|
||||||
function EsHandle EsProcessOpen(EsObjectID pid);
|
function EsHandle EsProcessOpen(EsObjectID pid);
|
||||||
function void EsProcessPause(EsHandle process, bool resume);
|
function void EsProcessPause(EsHandle process, bool resume);
|
||||||
function void EsProcessTerminate(EsHandle process, int status);
|
function void EsProcessTerminate(EsHandle process, int status);
|
||||||
function void EsProcessTerminateCurrent();
|
function void EsProcessTerminateCurrent();
|
||||||
|
|
||||||
function EsError EsThreadCreate(EsThreadEntryCallback entryFunction, EsThreadInformation *information, EsGeneric argument);
|
function EsError EsThreadCreate(EsThreadEntryCallback entryFunction, EsThreadInformation *information, EsGeneric argument);
|
||||||
function EsObjectID EsThreadGetID(EsHandle thread); // TODO Make this 64-bit.
|
function EsObjectID EsThreadGetID(EsHandle thread);
|
||||||
function void EsThreadTerminate(EsHandle thread);
|
function void EsThreadTerminate(EsHandle thread);
|
||||||
|
|
||||||
|
function void EsWorkQueue(EsWorkCallback callback, EsGeneric context);
|
||||||
|
|
||||||
// Memory.
|
// Memory.
|
||||||
|
|
||||||
function void *EsArenaAllocate(EsArena *arena, bool zero); // Not thread-safe.
|
function void *EsArenaAllocate(EsArena *arena, bool zero); // Not thread-safe.
|
||||||
|
|
|
@ -257,7 +257,9 @@ long EsPOSIXSystemCall(long n, long a1, long a2, long a3, long a4, long a5, long
|
||||||
|
|
||||||
case SYS_getpid: {
|
case SYS_getpid: {
|
||||||
// Run the system call directly, so that the kernel can handle the vfork()'d case.
|
// Run the system call directly, so that the kernel can handle the vfork()'d case.
|
||||||
returnValue = EsSyscall(ES_SYSCALL_THREAD_GET_ID, ES_CURRENT_PROCESS, 0, 0, 0);
|
EsObjectID id;
|
||||||
|
EsSyscall(ES_SYSCALL_THREAD_GET_ID, ES_CURRENT_PROCESS, (uintptr_t) &id, 0, 0);
|
||||||
|
returnValue = id;
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case SYS_gettid: {
|
case SYS_gettid: {
|
||||||
|
@ -484,7 +486,7 @@ long EsPOSIXSystemCall(long n, long a1, long a2, long a3, long a4, long a5, long
|
||||||
|
|
||||||
case SYS_prlimit64: {
|
case SYS_prlimit64: {
|
||||||
// You can't access other process's resources.
|
// You can't access other process's resources.
|
||||||
if (a1 && a1 != (long) EsSyscall(ES_SYSCALL_THREAD_GET_ID, ES_CURRENT_PROCESS, 0, 0, 0)) {
|
if (a1 && a1 != (long) EsProcessGetID(ES_CURRENT_PROCESS)) {
|
||||||
returnValue = -EPERM;
|
returnValue = -EPERM;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -436,16 +436,20 @@ void EsProcessPause(EsHandle process, bool resume) {
|
||||||
EsSyscall(ES_SYSCALL_PROCESS_PAUSE, process, resume, 0, 0);
|
EsSyscall(ES_SYSCALL_PROCESS_PAUSE, process, resume, 0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint64_t EsThreadGetID(EsHandle thread) {
|
EsObjectID EsThreadGetID(EsHandle thread) {
|
||||||
if (thread == ES_CURRENT_THREAD) {
|
if (thread == ES_CURRENT_THREAD) {
|
||||||
return GetThreadLocalStorage()->id;
|
return GetThreadLocalStorage()->id;
|
||||||
} else {
|
} else {
|
||||||
return EsSyscall(ES_SYSCALL_THREAD_GET_ID, thread, 0, 0, 0);
|
EsObjectID id;
|
||||||
|
EsSyscall(ES_SYSCALL_THREAD_GET_ID, thread, (uintptr_t) &id, 0, 0);
|
||||||
|
return id;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
uintptr_t EsProcessGetID(EsHandle process) {
|
EsObjectID EsProcessGetID(EsHandle process) {
|
||||||
return EsSyscall(ES_SYSCALL_THREAD_GET_ID, process, 0, 0, 0);
|
EsObjectID id;
|
||||||
|
EsSyscall(ES_SYSCALL_THREAD_GET_ID, process, (uintptr_t) &id, 0, 0);
|
||||||
|
return id;
|
||||||
}
|
}
|
||||||
|
|
||||||
ptrdiff_t EsDirectoryEnumerateChildrenFromHandle(EsHandle directory, EsDirectoryChild *buffer, size_t size) {
|
ptrdiff_t EsDirectoryEnumerateChildrenFromHandle(EsHandle directory, EsDirectoryChild *buffer, size_t size) {
|
||||||
|
|
|
@ -164,6 +164,8 @@ EsError KLoadELF(KNode *node, KLoadedExecutable *executable) {
|
||||||
|
|
||||||
#ifdef ARCH_X86_64
|
#ifdef ARCH_X86_64
|
||||||
uint64_t name = CalculateCRC64(EsLiteral("$Executables/x86_64"));
|
uint64_t name = CalculateCRC64(EsLiteral("$Executables/x86_64"));
|
||||||
|
#else
|
||||||
|
#error Unimplemented.
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
BundleFile *files = (BundleFile *) ((BundleHeader *) header.mapAddress + 1);
|
BundleFile *files = (BundleFile *) ((BundleHeader *) header.mapAddress + 1);
|
||||||
|
|
|
@ -1253,20 +1253,20 @@ SYSCALL_IMPLEMENT(ES_SYSCALL_THREAD_GET_ID) {
|
||||||
SYSCALL_HANDLE_2(argument0, KERNEL_OBJECT_THREAD | KERNEL_OBJECT_PROCESS, object);
|
SYSCALL_HANDLE_2(argument0, KERNEL_OBJECT_THREAD | KERNEL_OBJECT_PROCESS, object);
|
||||||
|
|
||||||
if (object.type == KERNEL_OBJECT_THREAD) {
|
if (object.type == KERNEL_OBJECT_THREAD) {
|
||||||
SYSCALL_RETURN(((Thread *) object.object)->id, false);
|
SYSCALL_WRITE(argument1, &((Thread *) object.object)->id, sizeof(EsObjectID));
|
||||||
} else if (object.type == KERNEL_OBJECT_PROCESS) {
|
} else if (object.type == KERNEL_OBJECT_PROCESS) {
|
||||||
Process *process = (Process *) object.object;
|
Process *process = (Process *) object.object;
|
||||||
|
EsObjectID id = process->id;
|
||||||
|
|
||||||
#ifdef ENABLE_POSIX_SUBSYSTEM
|
#ifdef ENABLE_POSIX_SUBSYSTEM
|
||||||
if (currentThread->posixData && currentThread->posixData->forkProcess) {
|
if (currentThread->posixData && currentThread->posixData->forkProcess) {
|
||||||
SYSCALL_RETURN(currentThread->posixData->forkProcess->id, false);
|
id = currentThread->posixData->forkProcess->id;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
SYSCALL_RETURN(process->id, false);
|
SYSCALL_WRITE(argument1, &id, sizeof(EsObjectID));
|
||||||
}
|
}
|
||||||
|
|
||||||
KernelPanic("ES_SYSCALL_THREAD_GET_ID - Unhandled case.\n");
|
|
||||||
SYSCALL_RETURN(ES_SUCCESS, false);
|
SYSCALL_RETURN(ES_SUCCESS, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -453,3 +453,4 @@ EsIconDisplaySetIcon=451
|
||||||
EsFontDatabaseLookupByName=452
|
EsFontDatabaseLookupByName=452
|
||||||
_EsWindowGetHandle=453
|
_EsWindowGetHandle=453
|
||||||
_EsUISetFont=454
|
_EsUISetFont=454
|
||||||
|
EsWorkQueue=455
|
||||||
|
|
Loading…
Reference in New Issue