| |
| #include <thread.h> |
| |
| #ifdef _MSC_VER |
| # define ATTRIBUTE_NORETURN |
| #else |
| # define ATTRIBUTE_NORETURN __attribute__((noreturn)) |
| #endif |
| |
| #ifdef _WIN32 |
| # include <Windows.h> |
| # include <process.h> |
| |
| static unsigned __stdcall |
| thread_entry(void* argptr) { |
| thread_arg* arg = argptr; |
| arg->fn(arg->arg); |
| return 0; |
| } |
| |
| #else |
| # include <time.h> |
| # include <pthread.h> |
| # include <sched.h> |
| |
| static void* |
| thread_entry(void* argptr) { |
| thread_arg* arg = argptr; |
| arg->fn(arg->arg); |
| return 0; |
| } |
| |
| #endif |
| |
| uintptr_t |
| thread_run(thread_arg* arg) { |
| #ifdef _WIN32 |
| return _beginthreadex(0, 0, thread_entry, arg, 0, 0); |
| #else |
| pthread_t id = 0; |
| int err = pthread_create(&id, 0, thread_entry, arg); |
| if (err) |
| return 0; |
| return (uintptr_t)id; |
| #endif |
| } |
| |
| void ATTRIBUTE_NORETURN |
| thread_exit(uintptr_t value) { |
| #ifdef _WIN32 |
| _endthreadex((unsigned)value); |
| #else |
| pthread_exit((void*)value); |
| #endif |
| } |
| |
| uintptr_t |
| thread_join(uintptr_t handle) { |
| if (!handle) |
| return (uintptr_t)-1; |
| uintptr_t ret; |
| #ifdef _WIN32 |
| DWORD exit_code = 0; |
| WaitForSingleObject((HANDLE)handle, INFINITE); |
| GetExitCodeThread((HANDLE)handle, &exit_code); |
| CloseHandle((HANDLE)handle); |
| ret = exit_code; |
| #else |
| void* result = 0; |
| pthread_join((pthread_t)handle, &result); |
| ret = (uintptr_t)result; |
| #endif |
| return ret; |
| } |
| |
| void |
| thread_sleep(int milliseconds) { |
| #ifdef _WIN32 |
| SleepEx((DWORD)milliseconds, 0); |
| #else |
| struct timespec ts; |
| ts.tv_sec = milliseconds / 1000; |
| ts.tv_nsec = (long)(milliseconds % 1000) * 1000000L; |
| nanosleep(&ts, 0); |
| #endif |
| } |
| |
| void |
| thread_yield(void) { |
| #ifdef _WIN32 |
| SleepEx(0, 1); |
| #else |
| sched_yield(); |
| #endif |
| } |