# HG changeset patch # User Olaf Wintermann # Date 1706471260 -3600 # Node ID 83263002816fa3affdd62b85cd4e94908ec482c7 # Parent 31137432bea8723516f8ec15bef021fd9038b52d update toolkit (job/threadpool) diff -r 31137432bea8 -r 83263002816f application/application.c --- a/application/application.c Sun Jan 28 17:05:46 2024 +0100 +++ b/application/application.c Sun Jan 28 20:47:40 2024 +0100 @@ -85,7 +85,6 @@ ui_toolbar_add_default("LocalBrowser", UI_TOOLBAR_RIGHT); ui_toolbar_add_default("PreviewPane", UI_TOOLBAR_RIGHT); - ui_toolbar_add_default("PreviewPane", UI_TOOLBAR_RIGHT); } diff -r 31137432bea8 -r 83263002816f ui/ui/toolkit.h --- a/ui/ui/toolkit.h Sun Jan 28 17:05:46 2024 +0100 +++ b/ui/ui/toolkit.h Sun Jan 28 20:47:40 2024 +0100 @@ -163,6 +163,8 @@ typedef struct UiImage UiImage; typedef struct UiDnD UiDnD; + +typedef struct UiThreadpool UiThreadpool; /* end opaque types */ typedef struct UiTabbedPane UiTabbedPane; @@ -371,6 +373,10 @@ UIEXPORT void ui_close(UiObject *obj); UIEXPORT void ui_job(UiObject *obj, ui_threadfunc tf, void *td, ui_callback f, void *fd); +UIEXPORT void ui_call_mainthread(ui_threadfunc tf, void* td); +UIEXPORT UiThreadpool* ui_threadpool_create(int nthreads); +UIEXPORT void ui_threadpool_destroy(UiThreadpool* pool); +UIEXPORT void ui_threadpool_job(UiThreadpool* pool, UiObject* obj, ui_threadfunc tf, void* td, ui_callback f, void* fd); UIEXPORT void* ui_document_new(size_t size); UIEXPORT void ui_document_destroy(void *doc); diff -r 31137432bea8 -r 83263002816f ui/winui/pch.h --- a/ui/winui/pch.h Sun Jan 28 17:05:46 2024 +0100 +++ b/ui/winui/pch.h Sun Jan 28 20:47:40 2024 +0100 @@ -33,6 +33,7 @@ #include #include #include +#include #include diff -r 31137432bea8 -r 83263002816f ui/winui/toolkit.cpp --- a/ui/winui/toolkit.cpp Sun Jan 28 17:05:46 2024 +0100 +++ b/ui/winui/toolkit.cpp Sun Jan 28 20:47:40 2024 +0100 @@ -50,6 +50,7 @@ using namespace Microsoft::UI::Xaml::Markup; using namespace Windows::UI::Xaml::Interop; using namespace winrt::Windows::Foundation; +using namespace Windows::UI::Core; static const char* application_name; @@ -69,7 +70,11 @@ static UiObject* active_window; +static winrt::Microsoft::UI::Dispatching::DispatcherQueue uiDispatcherQueue = { nullptr }; + void ui_app_run_startup() { + uiDispatcherQueue = winrt::Microsoft::UI::Dispatching::DispatcherQueue::GetForCurrentThread(); + if (startup_func) { startup_func(NULL, startup_data); } @@ -233,3 +238,125 @@ } +static void ui_job_finished(UiJob *job) { + UiEvent event; + event.obj = job->obj; + event.window = job->obj->window; + event.document = job->obj->ctx->document; + event.intval = 0; + event.eventdata = NULL; + job->finish_callback(&event, job->finish_data); +} + +static void ui_job_thread(UiJob* job) { + if (!job->job_func(job->job_data) && job->finish_callback) { + bool isQueued = uiDispatcherQueue.TryEnqueue([job]() + { + UiEvent event; + event.obj = job->obj; + event.window = job->obj->window; + event.document = job->obj->ctx->document; + event.intval = 0; + event.eventdata = NULL; + job->finish_callback(&event, job->finish_data); + delete job; + }); + if (!isQueued) { + // TODO: error or try again? + exit(-1); + } + } + else { + delete job; + } +} + +UIEXPORT void ui_job(UiObject* obj, ui_threadfunc tf, void* td, ui_callback f, void* fd) { + UiJob* job = new UiJob; + job->obj = obj; + job->job_func = tf; + job->job_data = td; + job->finish_callback = f; + job->finish_data = fd; + + std::thread jobThread(ui_job_thread, job); + jobThread.detach(); +} + +UIEXPORT void ui_call_mainthread(ui_threadfunc tf, void* td) { + bool isQueued = uiDispatcherQueue.TryEnqueue([tf, td]() + { + (void)tf(td); + }); + if (!isQueued) { + // TODO: error or try again? + exit(-1); + } +} + +static UiJob kill_job; // &kill_job indicates to stop the thread + +static void ui_threadpool_run(UiThreadpool* pool) { + for (;;) { + UiJob* job = pool->GetJob(); + if (job == &kill_job) { + return; + } + else if (job) { + ui_job_thread(job); + } + } +} + +UiThreadpool::UiThreadpool(int nthreads) { + for (int i = 0; i < nthreads; i++) { + std::thread thread(ui_threadpool_run, this); + thread.detach(); + } +} + +void UiThreadpool::EnqueueJob(UiJob* job) +{ + std::unique_lock lock(mutex); + queue.push(job); + lock.unlock(); + condition.notify_one(); +} + +UiJob* UiThreadpool::GetJob() { + std::unique_lock lock(mutex); + + UiJob* job = nullptr; + while (!job) { + if (queue.empty()) { + condition.wait(lock); + continue; + } + else + { + job = queue.front(); + queue.pop(); + } + } + + return job; +} + +UIEXPORT UiThreadpool* ui_threadpool_create(int nthreads) { + return new UiThreadpool(nthreads); +} + +UIEXPORT void ui_threadpool_destroy(UiThreadpool* pool) { + // TODO +} + +UIEXPORT void ui_threadpool_job(UiThreadpool* pool, UiObject* obj, ui_threadfunc tf, void* td, ui_callback f, void* fd) { + UiJob* job = new UiJob; + job->obj = obj; + job->job_func = tf; + job->job_data = td; + job->finish_callback = f; + job->finish_data = fd; + pool->EnqueueJob(job); +} + diff -r 31137432bea8 -r 83263002816f ui/winui/toolkit.h --- a/ui/winui/toolkit.h Sun Jan 28 17:05:46 2024 +0100 +++ b/ui/winui/toolkit.h Sun Jan 28 20:47:40 2024 +0100 @@ -30,6 +30,31 @@ #include "../ui/toolkit.h" +#include +#include +#include + +typedef struct UiJob { + UiObject* obj; + ui_threadfunc job_func; + void* job_data; + ui_callback finish_callback; + void* finish_data; +} UiJob; + +struct UiThreadpool +{ + std::queue queue; + std::mutex mutex; + std::condition_variable condition; + + UiThreadpool(int nthreads); + + void EnqueueJob(UiJob* job); + + UiJob* GetJob(); +}; + typedef void(*ui_eventfunc)(void*, void*); void ui_app_run_startup();