platform/windows/thread-helpers-win32.h
| Line | Branch | Exec | Source |
|---|---|---|---|
| 1 | #pragma once | ||
| 2 | |||
| 3 | #if defined(_WIN32) | ||
| 4 | |||
| 5 | #include <windows.h> | ||
| 6 | |||
| 7 | struct function_pointer_wrapper /*have this struct at global level*/ | ||
| 8 | { | ||
| 9 | static void (*fiber_callback)(void *); | ||
| 10 | static void __stdcall execute_fiber(void* parameter) { return fiber_callback(parameter); } | ||
| 11 | |||
| 12 | static unsigned long (*thread_callback)(void*); | ||
| 13 | 129 | static unsigned long __stdcall execute_thread(void* parameter) { return thread_callback(parameter); } | |
| 14 | }; | ||
| 15 | |||
| 16 | void (*function_pointer_wrapper::fiber_callback)(void*) = nullptr; | ||
| 17 | unsigned long (*function_pointer_wrapper::thread_callback)(void*) = nullptr; | ||
| 18 | |||
| 19 | template <typename functor> | ||
| 20 | bool run_as_fiber(functor &&callback) { | ||
| 21 | struct fiber_wrapper { | ||
| 22 | functor &callback; | ||
| 23 | void *original; | ||
| 24 | bool result; | ||
| 25 | |||
| 26 | void execute() { | ||
| 27 | result = callback(); | ||
| 28 | SwitchToFiber(original); | ||
| 29 | } | ||
| 30 | |||
| 31 | } wrapper{callback, nullptr, false}; | ||
| 32 | |||
| 33 | function_pointer_wrapper::fiber_callback = [](void *parameter){ | ||
| 34 | reinterpret_cast<fiber_wrapper*>(parameter)->execute(); | ||
| 35 | }; | ||
| 36 | auto fiber = CreateFiberEx(16*1024*1024, 16*1024*1024, 0, &function_pointer_wrapper::execute_fiber, &wrapper); | ||
| 37 | |||
| 38 | if (!fiber) { | ||
| 39 | return callback(); | ||
| 40 | } | ||
| 41 | |||
| 42 | void* main_thread = ConvertThreadToFiber(nullptr); | ||
| 43 | if (!main_thread && GetLastError() != ERROR_ALREADY_FIBER) { | ||
| 44 | return callback(); | ||
| 45 | } | ||
| 46 | wrapper.original = GetCurrentFiber(); | ||
| 47 | SwitchToFiber(fiber); | ||
| 48 | DeleteFiber(fiber); | ||
| 49 | if (main_thread) { | ||
| 50 | ConvertFiberToThread(); | ||
| 51 | } | ||
| 52 | return wrapper.result; | ||
| 53 | } | ||
| 54 | |||
| 55 | |||
| 56 | template <typename functor> | ||
| 57 | 129 | bool run_as_thread(functor&& callback) { | |
| 58 | struct thread_wrapper { | ||
| 59 | functor& callback; | ||
| 60 | bool result; | ||
| 61 | |||
| 62 | 129 | unsigned long execute() { | |
| 63 | 129 | result = callback(); | |
| 64 | 129 | return (result ? 0 : -1); | |
| 65 | } | ||
| 66 | |||
| 67 | 129 | } wrapper{ callback, false }; | |
| 68 | |||
| 69 | 129 | function_pointer_wrapper::thread_callback = [](void* parameter) { | |
| 70 | 129 | return reinterpret_cast<thread_wrapper*>(parameter)->execute(); | |
| 71 | }; | ||
| 72 | |||
| 73 | 129 | auto thread = CreateThread(NULL, 16 * 1024 * 1024, &function_pointer_wrapper::execute_thread, &wrapper, 0, NULL); | |
| 74 | |||
| 75 | 129 | if (!thread) { | |
| 76 | ✗ | return callback(); | |
| 77 | } | ||
| 78 | |||
| 79 | 129 | WaitForSingleObject(thread, INFINITE); | |
| 80 | |||
| 81 | 129 | CloseHandle(thread); | |
| 82 | |||
| 83 | 129 | return wrapper.result; | |
| 84 | } | ||
| 85 | |||
| 86 | char* stack_bottom = nullptr; | ||
| 87 | 377 | void init_stack_use_check() { | |
| 88 | MEMORY_BASIC_INFORMATION mbi; | ||
| 89 | 377 | char stackvar = 0; | |
| 90 | 377 | VirtualQuery(&stackvar, &mbi, sizeof(mbi)); | |
| 91 | 377 | stack_bottom = (char*)mbi.AllocationBase; | |
| 92 | 377 | } | |
| 93 | 372 | void deinit_stack_use_check() { | |
| 94 | 372 | stack_bottom = nullptr; | |
| 95 | 372 | } | |
| 96 | 72302 | bool have_enough_stack_left() { | |
| 97 | char stackvar; | ||
| 98 | 72302 | return stack_bottom == nullptr || (&stackvar - stack_bottom) >= 32768; | |
| 99 | } | ||
| 100 | #endif | ||
| 101 |