Showing the changes to player/system.cpp (1 of 6 files). Show all
Unified · Split
| @@ -0,0 +1,473 @@ | |||
| 1 | #include "system.h" | ||
| 2 | |||
| 3 | #ifndef _WIN32 | ||
| 4 | |||
| 5 | #include <stdlib.h> | ||
| 6 | #include <time.h> | ||
| 7 | #include <errno.h> | ||
| 8 | #include <unistd.h> | ||
| 9 | #if defined(__linux) || defined(__linux__) | ||
| 10 | #include <sys/prctl.h> | ||
| 11 | #endif | ||
| 12 | |||
| 13 | #define nullptr 0 | ||
| 14 | |||
| 15 | struct Event | ||
| 16 | { | ||
| 17 | Event * volatile pMultipleCond; | ||
| 18 | pthread_mutex_t mutex; | ||
| 19 | pthread_cond_t cond; | ||
| 20 | volatile bool signaled; | ||
| 21 | bool manual_reset; | ||
| 22 | }; | ||
| 23 | |||
| 24 | static bool InitEvent(Event *e) | ||
| 25 | { | ||
| 26 | #if (defined(ANDROID) && !defined(__LP64__)) || defined(__APPLE__) | ||
| 27 | if (pthread_cond_init(&e->cond, NULL)) | ||
| 28 | return false; | ||
| 29 | #else | ||
| 30 | pthread_condattr_t attr; | ||
| 31 | if (pthread_condattr_init(&attr)) | ||
| 32 | return false; | ||
| 33 | if (pthread_condattr_setclock(&attr, CLOCK_MONOTONIC)) | ||
| 34 | { | ||
| 35 | pthread_condattr_destroy(&attr); | ||
| 36 | return false; | ||
| 37 | } | ||
| 38 | if (pthread_cond_init(&e->cond, &attr)) | ||
| 39 | { | ||
| 40 | pthread_condattr_destroy(&attr); | ||
| 41 | return false; | ||
| 42 | } | ||
| 43 | pthread_condattr_destroy(&attr); | ||
| 44 | #endif | ||
| 45 | if (pthread_mutex_init(&e->mutex, NULL)) | ||
| 46 | { | ||
| 47 | pthread_cond_destroy(&e->cond); | ||
| 48 | return false; | ||
| 49 | } | ||
| 50 | e->pMultipleCond = NULL; | ||
| 51 | return true; | ||
| 52 | } | ||
| 53 | |||
| 54 | #ifdef __APPLE__ | ||
| 55 | #include <mach/mach_time.h> | ||
| 56 | static inline uint64_t GetAbsTimeInNanoseconds() | ||
| 57 | { | ||
| 58 | static mach_timebase_info_data_t g_timebase_info; | ||
| 59 | if (g_timebase_info.denom == 0) | ||
| 60 | mach_timebase_info(&g_timebase_info); | ||
| 61 | return mach_absolute_time()*g_timebase_info.numer/g_timebase_info.denom; | ||
| 62 | } | ||
| 63 | #endif | ||
| 64 | |||
| 65 | static inline void GetAbsTime(timespec *ts, uint32_t timeout) | ||
| 66 | { | ||
| 67 | #if defined(__APPLE__) | ||
| 68 | uint64_t cur_time = GetAbsTimeInNanoseconds(); | ||
| 69 | ts->tv_sec = cur_time/1000000000u + timeout/1000u; | ||
| 70 | ts->tv_nsec = (cur_time % 1000000000u) + (timeout % 1000u)*1000000u; | ||
| 71 | #else | ||
| 72 | clock_gettime(CLOCK_MONOTONIC, ts); | ||
| 73 | ts->tv_sec += timeout/1000u; | ||
| 74 | ts->tv_nsec += (timeout % 1000u)*1000000u; | ||
| 75 | #endif | ||
| 76 | if (ts->tv_nsec >= 1000000000) | ||
| 77 | { | ||
| 78 | ts->tv_nsec -= 1000000000; | ||
| 79 | ts->tv_sec++; | ||
| 80 | } | ||
| 81 | } | ||
| 82 | |||
| 83 | static inline int CondTimedWait(pthread_cond_t *cond, pthread_mutex_t *mutex, const struct timespec *abstime) | ||
| 84 | { | ||
| 85 | #if defined(ANDROID) && !defined(__LP64__) | ||
| 86 | return pthread_cond_timedwait_monotonic_np(cond, mutex, abstime); | ||
| 87 | #elif defined(__APPLE__) | ||
| 88 | timespec reltime; | ||
| 89 | uint64_t cur_time = GetAbsTimeInNanoseconds(); | ||
| 90 | reltime.tv_sec = abstime->tv_sec - cur_time/1000000000u; | ||
| 91 | reltime.tv_nsec = abstime->tv_nsec - (cur_time % 1000000000u); | ||
| 92 | if (reltime.tv_nsec < 0) | ||
| 93 | { | ||
| 94 | reltime.tv_nsec += 1000000000; | ||
| 95 | reltime.tv_sec--; | ||
| 96 | } | ||
| 97 | if ((reltime.tv_sec < 0) || ((reltime.tv_sec == 0) && (reltime.tv_nsec == 0))) | ||
| 98 | return ETIMEDOUT; | ||
| 99 | return pthread_cond_timedwait_relative_np(cond, mutex, &reltime); | ||
| 100 | #else | ||
| 101 | return pthread_cond_timedwait(cond, mutex, abstime); | ||
| 102 | #endif | ||
| 103 | } | ||
| 104 | |||
| 105 | static bool WaitForEvent(Event *e, uint32_t timeout, bool *signaled) | ||
| 106 | { | ||
| 107 | if (pthread_mutex_lock(&e->mutex)) | ||
| 108 | return false; | ||
| 109 | |||
| 110 | if (timeout == INFINITE) | ||
| 111 | { | ||
| 112 | while (!e->signaled) | ||
| 113 | pthread_cond_wait(&e->cond, &e->mutex); | ||
| 114 | } else if (timeout != 0) | ||
| 115 | { | ||
| 116 | timespec t; | ||
| 117 | GetAbsTime(&t, timeout); | ||
| 118 | while (!e->signaled) | ||
| 119 | { | ||
| 120 | if (CondTimedWait(&e->cond, &e->mutex, &t)) | ||
| 121 | break; | ||
| 122 | } | ||
| 123 | } | ||
| 124 | *signaled = e->signaled; | ||
| 125 | if (!e->manual_reset) | ||
| 126 | e->signaled = false; | ||
| 127 | |||
| 128 | if (pthread_mutex_unlock(&e->mutex)) | ||
| 129 | return false; | ||
| 130 | return true; | ||
| 131 | } | ||
| 132 | |||
| 133 | static bool WaitForMultipleEvents(Event **e, uint32_t count, uint32_t timeout, bool waitAll, int *signaled_num) | ||
| 134 | { | ||
| 135 | uint32_t i; | ||
| 136 | #define PTHR(func, num) for (i = num; i < count; i++)\ | ||
| 137 | if (func(&e[i]->mutex))\ | ||
| 138 | return false; | ||
| 139 | PTHR(pthread_mutex_lock, 0); | ||
| 140 | |||
| 141 | int sig_num = -1; | ||
| 142 | if (timeout == 0) | ||
| 143 | { | ||
| 144 | #define CHECK_SIGNALED \ | ||
| 145 | if (waitAll)\ | ||
| 146 | {\ | ||
| 147 | for (i = 0; i < count; i++)\ | ||
| 148 | if (!e[i]->signaled)\ | ||
| 149 | break;\ | ||
| 150 | if (i == count)\ | ||
| 151 | for (i = 0; i < count; i++)\ | ||
| 152 | {\ | ||
| 153 | if (sig_num < 0 && e[i]->signaled)\ | ||
| 154 | sig_num = (int)i;\ | ||
| 155 | if (!e[i]->manual_reset)\ | ||
| 156 | e[i]->signaled = false;\ | ||
| 157 | }\ | ||
| 158 | } else\ | ||
| 159 | {\ | ||
| 160 | for (i = 0; i < count; i++)\ | ||
| 161 | if (e[i]->signaled)\ | ||
| 162 | {\ | ||
| 163 | sig_num = (int)i;\ | ||
| 164 | if (!e[i]->manual_reset)\ | ||
| 165 | e[i]->signaled = false;\ | ||
| 166 | break;\ | ||
| 167 | }\ | ||
| 168 | } | ||
| 169 | CHECK_SIGNALED; | ||
| 170 | } else | ||
| 171 | if (timeout == INFINITE) | ||
| 172 | { | ||
| 173 | #define SET_MULTIPLE(val) for (i = 1; i < count; i++)\ | ||
| 174 | e[i]->pMultipleCond = val; | ||
| 175 | SET_MULTIPLE(e[0]); | ||
| 176 | for (;;) | ||
| 177 | { | ||
| 178 | CHECK_SIGNALED; | ||
| 179 | if (sig_num >= 0) | ||
| 180 | break; | ||
| 181 | PTHR(pthread_mutex_unlock, 1); | ||
| 182 | pthread_cond_wait(&e[0]->cond, &e[0]->mutex); | ||
| 183 | PTHR(pthread_mutex_lock, 1); | ||
| 184 | } | ||
| 185 | SET_MULTIPLE(0); | ||
| 186 | } else | ||
| 187 | { | ||
| 188 | SET_MULTIPLE(e[0]); | ||
| 189 | timespec t; | ||
| 190 | GetAbsTime(&t, timeout); | ||
| 191 | for (;;) | ||
| 192 | { | ||
| 193 | CHECK_SIGNALED; | ||
| 194 | if (sig_num >= 0) | ||
| 195 | break; | ||
| 196 | PTHR(pthread_mutex_unlock, 1); | ||
| 197 | int res = CondTimedWait(&e[0]->cond, &e[0]->mutex, &t); | ||
| 198 | PTHR(pthread_mutex_lock, 1); | ||
| 199 | if (res) | ||
| 200 | break; | ||
| 201 | } | ||
| 202 | SET_MULTIPLE(0); | ||
| 203 | } | ||
| 204 | PTHR(pthread_mutex_unlock, 0); | ||
| 205 | *signaled_num = sig_num; | ||
| 206 | return true; | ||
| 207 | } | ||
| 208 | |||
| 209 | static bool SignalEvent(Event *e) | ||
| 210 | { | ||
| 211 | if (pthread_mutex_lock(&e->mutex)) | ||
| 212 | return false; | ||
| 213 | |||
| 214 | Event *pMultipleCond = e->pMultipleCond; | ||
| 215 | e->signaled = true; | ||
| 216 | if (pthread_cond_signal(&e->cond)) | ||
| 217 | return false; | ||
| 218 | |||
| 219 | if (pthread_mutex_unlock(&e->mutex)) | ||
| 220 | return false; | ||
| 221 | |||
| 222 | if (pMultipleCond && pMultipleCond != e) | ||
| 223 | { | ||
| 224 | if (pthread_mutex_lock(&pMultipleCond->mutex)) | ||
| 225 | return false; | ||
| 226 | if (pthread_cond_signal(&pMultipleCond->cond)) | ||
| 227 | return false; | ||
| 228 | if (pthread_mutex_unlock(&pMultipleCond->mutex)) | ||
| 229 | return false; | ||
| 230 | } | ||
| 231 | return true; | ||
| 232 | } | ||
| 233 | |||
| 234 | static bool ResetEvent(Event *e) | ||
| 235 | { | ||
| 236 | if (pthread_mutex_lock(&e->mutex)) | ||
| 237 | return false; | ||
| 238 | e->signaled = false; | ||
| 239 | if (pthread_mutex_unlock(&e->mutex)) | ||
| 240 | return false; | ||
| 241 | return true; | ||
| 242 | } | ||
| 243 | |||
| 244 | HANDLE event_create(bool manualReset, bool initialState) | ||
| 245 | { | ||
| 246 | Event *e = (Event *)malloc(sizeof(*e)); | ||
| 247 | if (!e) | ||
| 248 | return NULL; | ||
| 249 | if (!InitEvent(e)) | ||
| 250 | { | ||
| 251 | free(e); | ||
| 252 | return NULL; | ||
| 253 | } | ||
| 254 | e->manual_reset = manualReset; | ||
| 255 | e->signaled = initialState; | ||
| 256 | return (HANDLE)e; | ||
| 257 | } | ||
| 258 | |||
| 259 | bool event_destroy(HANDLE event) | ||
| 260 | { | ||
| 261 | Event *e = (Event *)event; | ||
| 262 | if (!e) | ||
| 263 | return false; | ||
| 264 | if (pthread_cond_destroy(&e->cond)) | ||
| 265 | return false; | ||
| 266 | if (pthread_mutex_destroy(&e->mutex)) | ||
| 267 | return false; | ||
| 268 | free((void *)e); | ||
| 269 | return true; | ||
| 270 | } | ||
| 271 | |||
| 272 | bool event_set(HANDLE event) | ||
| 273 | { | ||
| 274 | return SignalEvent((Event *)event); | ||
| 275 | } | ||
| 276 | |||
| 277 | bool event_reset(HANDLE event) | ||
| 278 | { | ||
| 279 | return ResetEvent((Event *)event); | ||
| 280 | } | ||
| 281 | |||
| 282 | int event_wait(HANDLE event, uint32_t milliseconds) | ||
| 283 | { | ||
| 284 | bool signaled; | ||
| 285 | if (!WaitForEvent((Event *)event, milliseconds, &signaled)) | ||
| 286 | return WAIT_FAILED; | ||
| 287 | return signaled ? WAIT_OBJECT : WAIT_TIMEOUT; | ||
| 288 | } | ||
| 289 | |||
| 290 | int event_wait_multiple(uint32_t count, const HANDLE *events, bool waitAll, uint32_t milliseconds) | ||
| 291 | { | ||
| 292 | if (count == 1) | ||
| 293 | return event_wait(events[0], milliseconds); | ||
| 294 | int signaled_num = -1; | ||
| 295 | if (!WaitForMultipleEvents((Event **)events, count, milliseconds, waitAll, &signaled_num)) | ||
| 296 | return WAIT_FAILED; | ||
| 297 | return (signaled_num < 0) ? WAIT_TIMEOUT : (WAIT_OBJECT_0 + signaled_num); | ||
| 298 | } | ||
| 299 | |||
| 300 | bool InitializeCriticalSection(LPCRITICAL_SECTION lpCriticalSection) | ||
| 301 | { | ||
| 302 | pthread_mutexattr_t ma; | ||
| 303 | if (pthread_mutexattr_init(&ma)) | ||
| 304 | return false; | ||
| 305 | if (pthread_mutexattr_settype(&ma, PTHREAD_MUTEX_RECURSIVE)) | ||
| 306 | { | ||
| 307 | pthread_mutexattr_destroy(&ma); | ||
| 308 | return false; | ||
| 309 | } | ||
| 310 | if (pthread_mutex_init((pthread_mutex_t *)lpCriticalSection, &ma)) | ||
| 311 | { | ||
| 312 | pthread_mutexattr_destroy(&ma); | ||
| 313 | return false; | ||
| 314 | } | ||
| 315 | if (pthread_mutexattr_destroy(&ma)) | ||
| 316 | return false; | ||
| 317 | return true; | ||
| 318 | } | ||
| 319 | |||
| 320 | bool DeleteCriticalSection(LPCRITICAL_SECTION lpCriticalSection) | ||
| 321 | { | ||
| 322 | if (pthread_mutex_destroy((pthread_mutex_t *)lpCriticalSection)) | ||
| 323 | return false; | ||
| 324 | return true; | ||
| 325 | } | ||
| 326 | |||
| 327 | bool EnterCriticalSection(LPCRITICAL_SECTION lpCriticalSection) | ||
| 328 | { | ||
| 329 | if (pthread_mutex_lock((pthread_mutex_t *)lpCriticalSection)) | ||
| 330 | return false; | ||
| 331 | return true; | ||
| 332 | } | ||
| 333 | |||
| 334 | bool LeaveCriticalSection(LPCRITICAL_SECTION lpCriticalSection) | ||
| 335 | { | ||
| 336 | if (pthread_mutex_unlock((pthread_mutex_t *)lpCriticalSection)) | ||
| 337 | return false; | ||
| 338 | return true; | ||
| 339 | } | ||
| 340 | |||
| 341 | HANDLE thread_create(LPTHREAD_START_ROUTINE lpStartAddress, void *lpParameter) | ||
| 342 | { | ||
| 343 | pthread_t *t = (pthread_t *)malloc(sizeof(*t)); | ||
| 344 | if (!t) | ||
| 345 | return nullptr; | ||
| 346 | if (pthread_create(t, 0, lpStartAddress, lpParameter)) | ||
| 347 | { | ||
| 348 | free(t); | ||
| 349 | return nullptr; | ||
| 350 | } | ||
| 351 | //if (lpThreadId) | ||
| 352 | // *lpThreadId = (uint32_t)*t; | ||
| 353 | return (HANDLE)t; | ||
| 354 | } | ||
| 355 | |||
| 356 | bool thread_close(HANDLE thread) | ||
| 357 | { | ||
| 358 | if (!thread) | ||
| 359 | return false; | ||
| 360 | pthread_t *t = (pthread_t *)thread; | ||
| 361 | if (*t) | ||
| 362 | pthread_detach(*t); | ||
| 363 | free(t); | ||
| 364 | return true; | ||
| 365 | } | ||
| 366 | |||
| 367 | void *thread_wait(HANDLE thread) | ||
| 368 | { | ||
| 369 | if (!thread) | ||
| 370 | return (void*)-1; | ||
| 371 | void *ret = 0; | ||
| 372 | pthread_t *t = (pthread_t *)thread; | ||
| 373 | if (!*t) | ||
| 374 | return ret; | ||
| 375 | int res = pthread_join(*t, &ret); | ||
| 376 | if (res) | ||
| 377 | return (void*)-1; | ||
| 378 | #if 0 | ||
| 379 | if (timeout == 0) | ||
| 380 | { | ||
| 381 | int res = pthread_tryjoin_np(*t, &ret); | ||
| 382 | if (res) | ||
| 383 | return false; | ||
| 384 | } else | ||
| 385 | if (timeout == INFINITE) | ||
| 386 | { | ||
| 387 | int res = pthread_join(*t, &ret); | ||
| 388 | if (res) | ||
| 389 | return false; | ||
| 390 | } else | ||
| 391 | { | ||
| 392 | timespec ts; | ||
| 393 | GetAbsTime(&ts, timeout); | ||
| 394 | int res = pthread_timedjoin_np(*t, &ret, &ts); | ||
| 395 | if (res) | ||
| 396 | return false; | ||
| 397 | } | ||
| 398 | #endif | ||
| 399 | *t = 0; // thread joined - no need to detach | ||
| 400 | return ret; | ||
| 401 | } | ||
| 402 | |||
| 403 | #else //_WIN32 | ||
| 404 | |||
| 405 | bool event_destroy(HANDLE event) | ||
| 406 | { | ||
| 407 | CloseHandle(event); | ||
| 408 | return true; | ||
| 409 | } | ||
| 410 | |||
| 411 | bool thread_close(HANDLE thread) | ||
| 412 | { | ||
| 413 | CloseHandle(thread); | ||
| 414 | return true; | ||
| 415 | } | ||
| 416 | |||
| 417 | bool thread_wait(HANDLE thread) | ||
| 418 | { | ||
| 419 | return WaitForSingleObject(thread, INFINITE) == WAIT_OBJECT_0; | ||
| 420 | } | ||
| 421 | |||
| 422 | #endif //_WIN32 | ||
| 423 | |||
| 424 | bool thread_name(const char *name) | ||
| 425 | { | ||
| 426 | #ifdef _WIN32 | ||
| 427 | struct tagTHREADNAME_INFO | ||
| 428 | { | ||
| 429 | DWORD dwType; | ||
| 430 | LPCSTR szName; | ||
| 431 | DWORD dwThreadID; | ||
| 432 | DWORD dwFlags; | ||
| 433 | } info = { 0x1000, name, (DWORD)-1, 0 }; | ||
| 434 | __try | ||
| 435 | { | ||
| 436 | RaiseException(0x406D1388, 0, sizeof(info)/sizeof(ULONG_PTR), (ULONG_PTR*)&info); | ||
| 437 | } | ||
| 438 | __except(EXCEPTION_EXECUTE_HANDLER) | ||
| 439 | { | ||
| 440 | } | ||
| 441 | return true; | ||
| 442 | #elif defined(__linux) || defined(__linux__) | ||
| 443 | return (0 == prctl(PR_SET_NAME, name, 0, 0, 0)); | ||
| 444 | //return (0 == pthread_setname_np(pthread_self(), name)); | ||
| 445 | #else // macos, ios | ||
| 446 | return (0 == pthread_setname_np(name)); | ||
| 447 | #endif | ||
| 448 | } | ||
| 449 | |||
| 450 | bool thread_sleep(uint32_t milliseconds) | ||
| 451 | { | ||
| 452 | #ifdef _WIN32 | ||
| 453 | Sleep(milliseconds); | ||
| 454 | #else | ||
| 455 | usleep((useconds_t)milliseconds*1000); | ||
| 456 | #endif | ||
| 457 | } | ||
| 458 | |||
| 459 | uint64_t GetTime() | ||
| 460 | { | ||
| 461 | uint64_t time; | ||
| 462 | #ifdef _WIN32 | ||
| 463 | QueryPerformanceCounter((LARGE_INTEGER*)&time); | ||
| 464 | #elif defined(__APPLE__) | ||
| 465 | time = GetAbsTimeInNanoseconds() / 1000u; | ||
| 466 | #else | ||
| 467 | timespec ts; | ||
| 468 | // CLOCK_PROCESS_CPUTIME_ID CLOCK_THREAD_CPUTIME_ID | ||
| 469 | clock_gettime(CLOCK_MONOTONIC, &ts); | ||
| 470 | time = (uint64_t)ts.tv_sec * 1000000u + ts.tv_nsec / 1000u; | ||
| 471 | #endif | ||
| 472 | return time; | ||
| 473 | } | ||