Merge pull request #728 from pcercuei/libretro-wiiu-v4
[pcsx_rearmed.git] / deps / libretro-common / rthreads / rthreads.c
1 /* Copyright  (C) 2010-2020 The RetroArch team
2  *
3  * ---------------------------------------------------------------------------------------
4  * The following license statement only applies to this file (rthreads.c).
5  * ---------------------------------------------------------------------------------------
6  *
7  * Permission is hereby granted, free of charge,
8  * to any person obtaining a copy of this software and associated documentation files (the "Software"),
9  * to deal in the Software without restriction, including without limitation the rights to
10  * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
11  * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
12  *
13  * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
16  * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
18  * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
19  * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21  */
22
23 #ifdef __unix__
24 #ifndef __sun__
25 #define _POSIX_C_SOURCE 199309
26 #endif
27 #endif
28
29 #include <stdlib.h>
30 #include <string.h>
31
32 #include <boolean.h>
33 #include <rthreads/rthreads.h>
34
35 /* with RETRO_WIN32_USE_PTHREADS, pthreads can be used even on win32. Maybe only supported in MSVC>=2005  */
36
37 #if defined(_WIN32) && !defined(RETRO_WIN32_USE_PTHREADS)
38 #define USE_WIN32_THREADS
39 #ifdef _XBOX
40 #include <xtl.h>
41 #else
42 #define WIN32_LEAN_AND_MEAN
43 #ifndef _WIN32_WINNT
44 #define _WIN32_WINNT 0x0500 /*_WIN32_WINNT_WIN2K */
45 #endif
46 #include <windows.h>
47 #include <mmsystem.h>
48 #endif
49 #elif defined(GEKKO)
50 #include <ogc/lwp_watchdog.h>
51 #include "gx_pthread.h"
52 #elif defined(_3DS)
53 #include "ctr_pthread.h"
54 #else
55 #include <pthread.h>
56 #include <time.h>
57 #endif
58
59 #if defined(VITA) || defined(BSD) || defined(ORBIS) || defined(__mips__) || defined(_3DS)
60 #include <sys/time.h>
61 #endif
62
63 #ifdef __MACH__
64 #include <mach/clock.h>
65 #include <mach/mach.h>
66 #endif
67
68 struct thread_data
69 {
70    void (*func)(void*);
71    void *userdata;
72 };
73
74 struct sthread
75 {
76 #ifdef USE_WIN32_THREADS
77    HANDLE thread;
78    DWORD id;
79 #else
80    pthread_t id;
81 #endif
82 };
83
84 struct slock
85 {
86 #ifdef USE_WIN32_THREADS
87    CRITICAL_SECTION lock;
88 #else
89    pthread_mutex_t lock;
90 #endif
91 };
92
93 #ifdef USE_WIN32_THREADS
94 /* The syntax we'll use is mind-bending unless we use a struct. Plus, we might want to store more info later */
95 /* This will be used as a linked list immplementing a queue of waiting threads */
96 struct queue_entry
97 {
98    struct queue_entry *next;
99 };
100 #endif
101
102 struct scond
103 {
104 #ifdef USE_WIN32_THREADS
105    /* With this implementation of scond, we don't have any way of waking
106     * (or even identifying) specific threads
107     * But we need to wake them in the order indicated by the queue.
108     * This potato token will get get passed around every waiter.
109     * The bearer can test whether he's next, and hold onto the potato if he is.
110     * When he's done he can then put it back into play to progress
111     * the queue further */
112    HANDLE hot_potato;
113
114    /* The primary signalled event. Hot potatoes are passed until this is set. */
115    HANDLE event;
116
117    /* the head of the queue; NULL if queue is empty */
118    struct queue_entry *head;
119
120    /* equivalent to the queue length */
121    int waiters;
122
123    /* how many waiters in the queue have been conceptually wakened by signals
124     * (even if we haven't managed to actually wake them yet) */
125    int wakens;
126
127    /* used to control access to this scond, in case the user fails */
128    CRITICAL_SECTION cs;
129
130 #else
131    pthread_cond_t cond;
132 #endif
133 };
134
135 #ifdef USE_WIN32_THREADS
136 static DWORD CALLBACK thread_wrap(void *data_)
137 #else
138 static void *thread_wrap(void *data_)
139 #endif
140 {
141    struct thread_data *data = (struct thread_data*)data_;
142    if (!data)
143            return 0;
144    data->func(data->userdata);
145    free(data);
146    return 0;
147 }
148
149 /**
150  * sthread_create:
151  * @start_routine           : thread entry callback function
152  * @userdata                : pointer to userdata that will be made
153  *                            available in thread entry callback function
154  *
155  * Create a new thread.
156  *
157  * Returns: pointer to new thread if successful, otherwise NULL.
158  */
159 sthread_t *sthread_create(void (*thread_func)(void*), void *userdata)
160 {
161         return sthread_create_with_priority(thread_func, userdata, 0);
162 }
163
164 /* TODO/FIXME - this needs to be implemented for Switch/3DS */
165 #if !defined(SWITCH) && !defined(USE_WIN32_THREADS) && !defined(_3DS) && !defined(GEKKO) && !defined(__HAIKU__) && !defined(EMSCRIPTEN)
166 #define HAVE_THREAD_ATTR
167 #endif
168
169 /**
170  * sthread_create_with_priority:
171  * @start_routine           : thread entry callback function
172  * @userdata                : pointer to userdata that will be made
173  *                            available in thread entry callback function
174  * @thread_priority         : thread priority hint value from [1-100]
175  *
176  * Create a new thread. It is possible for the caller to give a hint
177  * for the thread's priority from [1-100]. Any passed in @thread_priority
178  * values that are outside of this range will cause sthread_create() to
179  * create a new thread using the operating system's default thread
180  * priority.
181  *
182  * Returns: pointer to new thread if successful, otherwise NULL.
183  */
184 sthread_t *sthread_create_with_priority(void (*thread_func)(void*), void *userdata, int thread_priority)
185 {
186 #ifdef HAVE_THREAD_ATTR
187    pthread_attr_t thread_attr;
188    bool thread_attr_needed  = false;
189 #endif
190    bool thread_created      = false;
191    struct thread_data *data = NULL;
192    sthread_t *thread        = (sthread_t*)malloc(sizeof(*thread));
193
194    if (!thread)
195       return NULL;
196
197    if (!(data = (struct thread_data*)malloc(sizeof(*data))))
198    {
199       free(thread);
200       return NULL;
201    }
202
203    data->func               = thread_func;
204    data->userdata           = userdata;
205
206    thread->id               = 0;
207 #ifdef USE_WIN32_THREADS
208    thread->thread           = CreateThread(NULL, 0, thread_wrap,
209          data, 0, &thread->id);
210    thread_created           = !!thread->thread;
211 #else
212 #ifdef HAVE_THREAD_ATTR
213    pthread_attr_init(&thread_attr);
214
215    if ((thread_priority >= 1) && (thread_priority <= 100))
216    {
217       struct sched_param sp;
218       memset(&sp, 0, sizeof(struct sched_param));
219       sp.sched_priority = thread_priority;
220       pthread_attr_setschedpolicy(&thread_attr, SCHED_RR);
221       pthread_attr_setschedparam(&thread_attr, &sp);
222
223       thread_attr_needed = true;
224    }
225
226 #if defined(VITA)
227    pthread_attr_setstacksize(&thread_attr , 0x10000 );
228    thread_attr_needed = true;
229 #elif defined(__APPLE__)
230    /* Default stack size on Apple is 512Kb; 
231     * for PS2 disc scanning and other reasons, we'd like 2MB. */
232    pthread_attr_setstacksize(&thread_attr , 0x200000 );
233    thread_attr_needed = true;
234 #endif
235
236    if (thread_attr_needed)
237       thread_created = pthread_create(&thread->id, &thread_attr, thread_wrap, data) == 0;
238    else
239       thread_created = pthread_create(&thread->id, NULL, thread_wrap, data) == 0;
240
241    pthread_attr_destroy(&thread_attr);
242 #else
243    thread_created    = pthread_create(&thread->id, NULL, thread_wrap, data) == 0;
244 #endif
245
246 #endif
247
248    if (thread_created)
249       return thread;
250    free(data);
251    free(thread);
252    return NULL;
253 }
254
255 /**
256  * sthread_detach:
257  * @thread                  : pointer to thread object
258  *
259  * Detach a thread. When a detached thread terminates, its
260  * resources are automatically released back to the system
261  * without the need for another thread to join with the
262  * terminated thread.
263  *
264  * Returns: 0 on success, otherwise it returns a non-zero error number.
265  */
266 int sthread_detach(sthread_t *thread)
267 {
268 #ifdef USE_WIN32_THREADS
269    CloseHandle(thread->thread);
270    free(thread);
271    return 0;
272 #else
273    int ret = pthread_detach(thread->id);
274    free(thread);
275    return ret;
276 #endif
277 }
278
279 /**
280  * sthread_join:
281  * @thread                  : pointer to thread object
282  *
283  * Join with a terminated thread. Waits for the thread specified by
284  * @thread to terminate. If that thread has already terminated, then
285  * it will return immediately. The thread specified by @thread must
286  * be joinable.
287  *
288  * Returns: 0 on success, otherwise it returns a non-zero error number.
289  */
290 void sthread_join(sthread_t *thread)
291 {
292    if (!thread)
293       return;
294 #ifdef USE_WIN32_THREADS
295    WaitForSingleObject(thread->thread, INFINITE);
296    CloseHandle(thread->thread);
297 #else
298    pthread_join(thread->id, NULL);
299 #endif
300    free(thread);
301 }
302
303 #if !defined(GEKKO)
304 /**
305  * sthread_isself:
306  * @thread                  : pointer to thread object
307  *
308  * Returns: true (1) if calling thread is the specified thread
309  */
310 bool sthread_isself(sthread_t *thread)
311 {
312 #ifdef USE_WIN32_THREADS
313    return thread ? GetCurrentThreadId() == thread->id        : false;
314 #else
315    return thread ? pthread_equal(pthread_self(), thread->id) : false;
316 #endif
317 }
318 #endif
319
320 /**
321  * slock_new:
322  *
323  * Create and initialize a new mutex. Must be manually
324  * freed.
325  *
326  * Returns: pointer to a new mutex if successful, otherwise NULL.
327  **/
328 slock_t *slock_new(void)
329 {
330    slock_t      *lock = (slock_t*)calloc(1, sizeof(*lock));
331    if (!lock)
332       return NULL;
333 #ifdef USE_WIN32_THREADS
334    InitializeCriticalSection(&lock->lock);
335 #else
336    if (pthread_mutex_init(&lock->lock, NULL) != 0)
337    {
338       free(lock);
339       return NULL;
340    }
341 #endif
342    return lock;
343 }
344
345 /**
346  * slock_free:
347  * @lock                    : pointer to mutex object
348  *
349  * Frees a mutex.
350  **/
351 void slock_free(slock_t *lock)
352 {
353    if (!lock)
354       return;
355
356 #ifdef USE_WIN32_THREADS
357    DeleteCriticalSection(&lock->lock);
358 #else
359    pthread_mutex_destroy(&lock->lock);
360 #endif
361    free(lock);
362 }
363
364 /**
365  * slock_lock:
366  * @lock                    : pointer to mutex object
367  *
368  * Locks a mutex. If a mutex is already locked by
369  * another thread, the calling thread shall block until
370  * the mutex becomes available.
371 **/
372 void slock_lock(slock_t *lock)
373 {
374    if (!lock)
375       return;
376 #ifdef USE_WIN32_THREADS
377    EnterCriticalSection(&lock->lock);
378 #else
379    pthread_mutex_lock(&lock->lock);
380 #endif
381 }
382
383 /**
384  * slock_try_lock:
385  * @lock                    : pointer to mutex object
386  *
387  * Attempts to lock a mutex. If a mutex is already locked by
388  * another thread, return false.  If the lock is acquired, return true.
389 **/
390 bool slock_try_lock(slock_t *lock)
391 {
392 #ifdef USE_WIN32_THREADS
393    return lock && TryEnterCriticalSection(&lock->lock);
394 #else
395    return lock && (pthread_mutex_trylock(&lock->lock) == 0);
396 #endif
397 }
398
399 /**
400  * slock_unlock:
401  * @lock                    : pointer to mutex object
402  *
403  * Unlocks a mutex.
404  **/
405 void slock_unlock(slock_t *lock)
406 {
407    if (!lock)
408       return;
409 #ifdef USE_WIN32_THREADS
410    LeaveCriticalSection(&lock->lock);
411 #else
412    pthread_mutex_unlock(&lock->lock);
413 #endif
414 }
415
416 /**
417  * scond_new:
418  *
419  * Creates and initializes a condition variable. Must
420  * be manually freed.
421  *
422  * Returns: pointer to new condition variable on success,
423  * otherwise NULL.
424  **/
425 scond_t *scond_new(void)
426 {
427    scond_t      *cond = (scond_t*)calloc(1, sizeof(*cond));
428
429    if (!cond)
430       return NULL;
431
432 #ifdef USE_WIN32_THREADS
433    /* This is very complex because recreating condition variable semantics
434     * with Win32 parts is not easy.
435     *
436     * The main problem is that a condition variable can't be used to
437     * "pre-wake" a thread (it will get wakened only after it's waited).
438     *
439     * Whereas a win32 event can pre-wake a thread (the event will be set
440     * in advance, so a 'waiter' won't even have to wait on it).
441     *
442     * Keep in mind a condition variable can apparently pre-wake a thread,
443     * insofar as spurious wakeups are always possible,
444     * but nobody will be expecting this and it does not need to be simulated.
445     *
446     * Moreover, we won't be doing this, because it counts as a spurious wakeup
447     * -- someone else with a genuine claim must get wakened, in any case.
448     *
449     * Therefore we choose to wake only one of the correct waiting threads.
450     * So at the very least, we need to do something clever. But there's
451     * bigger problems.
452     * We don't even have a straightforward way in win32 to satisfy
453     * pthread_cond_wait's atomicity requirement. The bulk of this
454     * algorithm is solving that.
455     *
456     * Note: We might could simplify this using vista+ condition variables,
457     * but we wanted an XP compatible solution. */
458    if (!(cond->event      = CreateEvent(NULL, FALSE, FALSE, NULL)))
459       goto error;
460    if (!(cond->hot_potato = CreateEvent(NULL, FALSE, FALSE, NULL)))
461    {
462       CloseHandle(cond->event);
463       goto error;
464    }
465
466    InitializeCriticalSection(&cond->cs);
467 #else
468    if (pthread_cond_init(&cond->cond, NULL) != 0)
469       goto error;
470 #endif
471
472    return cond;
473
474 error:
475    free(cond);
476    return NULL;
477 }
478
479 /**
480  * scond_free:
481  * @cond                    : pointer to condition variable object
482  *
483  * Frees a condition variable.
484 **/
485 void scond_free(scond_t *cond)
486 {
487    if (!cond)
488       return;
489
490 #ifdef USE_WIN32_THREADS
491    CloseHandle(cond->event);
492    CloseHandle(cond->hot_potato);
493    DeleteCriticalSection(&cond->cs);
494 #else
495    pthread_cond_destroy(&cond->cond);
496 #endif
497    free(cond);
498 }
499
500 #ifdef USE_WIN32_THREADS
501 static bool _scond_wait_win32(scond_t *cond, slock_t *lock, DWORD dwMilliseconds)
502 {
503    struct queue_entry myentry;
504    struct queue_entry **ptr;
505
506 #if _WIN32_WINNT >= 0x0500 || defined(_XBOX)
507    static LARGE_INTEGER performanceCounterFrequency;
508    LARGE_INTEGER tsBegin;
509    static bool first_init  = true;
510 #else
511    static bool beginPeriod = false;
512    DWORD tsBegin;
513 #endif
514    DWORD waitResult;
515    DWORD dwFinalTimeout = dwMilliseconds; /* Careful! in case we begin in the head,
516                                              we don't do the hot potato stuff,
517                                              so this timeout needs presetting. */
518
519    /* Reminder: `lock` is held before this is called. */
520    /* however, someone else may have called scond_signal without the lock. soo... */
521    EnterCriticalSection(&cond->cs);
522
523    /* since this library is meant for realtime game software
524     * I have no problem setting this to 1 and forgetting about it. */
525 #if _WIN32_WINNT >= 0x0500 || defined(_XBOX)
526    if (first_init)
527    {
528       performanceCounterFrequency.QuadPart = 0;
529       first_init = false;
530    }
531
532    if (performanceCounterFrequency.QuadPart == 0)
533       QueryPerformanceFrequency(&performanceCounterFrequency);
534 #else
535    if (!beginPeriod)
536    {
537       beginPeriod = true;
538       timeBeginPeriod(1);
539    }
540 #endif
541
542    /* Now we can take a good timestamp for use in faking the timeout ourselves. */
543    /* But don't bother unless we need to (to save a little time) */
544    if (dwMilliseconds != INFINITE)
545 #if _WIN32_WINNT >= 0x0500 || defined(_XBOX)
546       QueryPerformanceCounter(&tsBegin);
547 #else
548       tsBegin = timeGetTime();
549 #endif
550
551    /* add ourselves to a queue of waiting threads */
552    ptr = &cond->head;
553
554    /* walk to the end of the linked list */
555    while (*ptr)
556       ptr       = &((*ptr)->next);
557
558    *ptr         = &myentry;
559    myentry.next = NULL;
560
561    cond->waiters++;
562
563    /* now the conceptual lock release and condition block are supposed to be atomic.
564     * we can't do that in Windows, but we can simulate the effects by using
565     * the queue, by the following analysis:
566     * What happens if they aren't atomic?
567     *
568     * 1. a signaller can rush in and signal, expecting a waiter to get it;
569     * but the waiter wouldn't, because he isn't blocked yet.
570     * Solution: Win32 events make this easy. The event will sit there enabled
571     *
572     * 2. a signaller can rush in and signal, and then turn right around and wait.
573     * Solution: the signaller will get queued behind the waiter, who's
574     * enqueued before he releases the mutex. */
575
576    /* It's my turn if I'm the head of the queue.
577     * Check to see if it's my turn. */
578    while (cond->head != &myentry)
579    {
580       /* It isn't my turn: */
581       DWORD timeout = INFINITE;
582
583       /* As long as someone is even going to be able to wake up
584        * when they receive the potato, keep it going round. */
585       if (cond->wakens > 0)
586          SetEvent(cond->hot_potato);
587
588       /* Assess the remaining timeout time */
589       if (dwMilliseconds != INFINITE)
590       {
591 #if _WIN32_WINNT >= 0x0500 || defined(_XBOX)
592          LARGE_INTEGER now;
593          LONGLONG elapsed;
594
595          QueryPerformanceCounter(&now);
596          elapsed  = now.QuadPart - tsBegin.QuadPart;
597          elapsed *= 1000;
598          elapsed /= performanceCounterFrequency.QuadPart;
599 #else
600          DWORD now     = timeGetTime();
601          DWORD elapsed = now - tsBegin;
602 #endif
603
604          /* Try one last time with a zero timeout (keeps the code simpler) */
605          if (elapsed > dwMilliseconds)
606             elapsed = dwMilliseconds;
607
608          timeout = dwMilliseconds - elapsed;
609       }
610
611       /* Let someone else go */
612       LeaveCriticalSection(&lock->lock);
613       LeaveCriticalSection(&cond->cs);
614
615       /* Wait a while to catch the hot potato..
616        * someone else should get a chance to go */
617       /* After all, it isn't my turn (and it must be someone else's) */
618       Sleep(0);
619       waitResult = WaitForSingleObject(cond->hot_potato, timeout);
620
621       /* I should come out of here with the main lock taken */
622       EnterCriticalSection(&lock->lock);
623       EnterCriticalSection(&cond->cs);
624
625       if (waitResult == WAIT_TIMEOUT)
626       {
627          /* Out of time! Now, let's think about this. I do have the potato now--
628           * maybe it's my turn, and I have the event?
629           * If that's the case, I could proceed right now without aborting
630           * due to timeout.
631           *
632           * However.. I DID wait a real long time. The caller was willing
633           * to wait that long.
634           *
635           * I choose to give him one last chance with a zero timeout
636           * in the next step
637           */
638          if (cond->head == &myentry)
639          {
640             dwFinalTimeout = 0;
641             break;
642          }
643          else
644          {
645             /* It's not our turn and we're out of time. Give up.
646              * Remove ourself from the queue and bail. */
647             struct queue_entry *curr = cond->head;
648
649             while (curr->next != &myentry)
650                curr = curr->next;
651             curr->next = myentry.next;
652             cond->waiters--;
653             LeaveCriticalSection(&cond->cs);
654             return false;
655          }
656       }
657
658    }
659
660    /* It's my turn now -- and I hold the potato */
661
662    /* I still have the main lock, in any case */
663    /* I need to release it so that someone can set the event */
664    LeaveCriticalSection(&lock->lock);
665    LeaveCriticalSection(&cond->cs);
666
667    /* Wait for someone to actually signal this condition */
668    /* We're the only waiter waiting on the event right now -- everyone else
669     * is waiting on something different */
670    waitResult = WaitForSingleObject(cond->event, dwFinalTimeout);
671
672    /* Take the main lock so we can do work. Nobody else waits on this lock
673     * for very long, so even though it's GO TIME we won't have to wait long */
674    EnterCriticalSection(&lock->lock);
675    EnterCriticalSection(&cond->cs);
676
677    /* Remove ourselves from the queue */
678    cond->head = myentry.next;
679    cond->waiters--;
680
681    if (waitResult == WAIT_TIMEOUT)
682    {
683       /* Oops! ran out of time in the final wait. Just bail. */
684       LeaveCriticalSection(&cond->cs);
685       return false;
686    }
687
688    /* If any other wakenings are pending, go ahead and set it up  */
689    /* There may actually be no waiters. That's OK. The first waiter will come in,
690     * find it's his turn, and immediately get the signaled event */
691    cond->wakens--;
692    if (cond->wakens > 0)
693    {
694       SetEvent(cond->event);
695
696       /* Progress the queue: Put the hot potato back into play. It'll be
697        * tossed around until next in line gets it */
698       SetEvent(cond->hot_potato);
699    }
700
701    LeaveCriticalSection(&cond->cs);
702    return true;
703 }
704 #endif
705
706 /**
707  * scond_wait:
708  * @cond                    : pointer to condition variable object
709  * @lock                    : pointer to mutex object
710  *
711  * Block on a condition variable (i.e. wait on a condition).
712  **/
713 void scond_wait(scond_t *cond, slock_t *lock)
714 {
715 #ifdef USE_WIN32_THREADS
716    _scond_wait_win32(cond, lock, INFINITE);
717 #else
718    pthread_cond_wait(&cond->cond, &lock->lock);
719 #endif
720 }
721
722 /**
723  * scond_broadcast:
724  * @cond                    : pointer to condition variable object
725  *
726  * Broadcast a condition. Unblocks all threads currently blocked
727  * on the specified condition variable @cond.
728  **/
729 int scond_broadcast(scond_t *cond)
730 {
731 #ifdef USE_WIN32_THREADS
732    /* Remember, we currently have mutex */
733    if (cond->waiters != 0)
734    {
735       /* Awaken everything which is currently queued up */
736       if (cond->wakens == 0)
737          SetEvent(cond->event);
738       cond->wakens = cond->waiters;
739
740       /* Since there is now at least one pending waken, the potato must be in play */
741       SetEvent(cond->hot_potato);
742    }
743    return 0;
744 #else
745    return pthread_cond_broadcast(&cond->cond);
746 #endif
747 }
748
749 /**
750  * scond_signal:
751  * @cond                    : pointer to condition variable object
752  *
753  * Signal a condition. Unblocks at least one of the threads currently blocked
754  * on the specified condition variable @cond.
755  **/
756 void scond_signal(scond_t *cond)
757 {
758 #ifdef USE_WIN32_THREADS
759
760    /* Unfortunately, pthread_cond_signal does not require that the
761     * lock be held in advance */
762    /* To avoid stomping on the condvar from other threads, we need
763     * to control access to it with this */
764    EnterCriticalSection(&cond->cs);
765
766    /* remember: we currently have mutex */
767    if (cond->waiters == 0)
768    {
769       LeaveCriticalSection(&cond->cs);
770       return;
771    }
772
773    /* wake up the next thing in the queue */
774    if (cond->wakens == 0)
775       SetEvent(cond->event);
776
777    cond->wakens++;
778
779    /* The data structure is done being modified.. I think we can leave the CS now.
780     * This would prevent some other thread from receiving the hot potato and then
781     * immediately stalling for the critical section.
782     * But remember, we were trying to replicate a semantic where this entire
783     * scond_signal call was controlled (by the user) by a lock.
784     * So in case there's trouble with this, we can move it after SetEvent() */
785    LeaveCriticalSection(&cond->cs);
786
787    /* Since there is now at least one pending waken, the potato must be in play */
788    SetEvent(cond->hot_potato);
789
790 #else
791    pthread_cond_signal(&cond->cond);
792 #endif
793 }
794
795 /**
796  * scond_wait_timeout:
797  * @cond                    : pointer to condition variable object
798  * @lock                    : pointer to mutex object
799  * @timeout_us              : timeout (in microseconds)
800  *
801  * Try to block on a condition variable (i.e. wait on a condition) until
802  * @timeout_us elapses.
803  *
804  * Returns: false (0) if timeout elapses before condition variable is
805  * signaled or broadcast, otherwise true (1).
806  **/
807 bool scond_wait_timeout(scond_t *cond, slock_t *lock, int64_t timeout_us)
808 {
809 #ifdef USE_WIN32_THREADS
810    /* How to convert a microsecond (us) timeout to millisecond (ms)?
811     *
812     * Someone asking for a 0 timeout clearly wants immediate timeout.
813     * Someone asking for a 1 timeout clearly wants an actual timeout
814     * of the minimum length */
815    /* The implementation of a 0 timeout here with pthreads is sketchy.
816     * It isn't clear what happens if pthread_cond_timedwait is called with NOW.
817     * Moreover, it is possible that this thread gets pre-empted after the
818     * clock_gettime but before the pthread_cond_timedwait.
819     * In order to help smoke out problems caused by this strange usage,
820     * let's treat a 0 timeout as always timing out.
821     */
822    if (timeout_us == 0)
823       return false;
824    else if (timeout_us < 1000)
825       return _scond_wait_win32(cond, lock, 1);
826    /* Someone asking for 1000 or 1001 timeout shouldn't
827     * accidentally get 2ms. */
828    return _scond_wait_win32(cond, lock, timeout_us / 1000);
829 #else
830    int64_t seconds, remainder;
831    struct timespec now;
832 #ifdef __MACH__
833    /* OSX doesn't have clock_gettime. */
834    clock_serv_t cclock;
835    mach_timespec_t mts;
836    host_get_clock_service(mach_host_self(), CALENDAR_CLOCK, &cclock);
837    clock_get_time(cclock, &mts);
838    mach_port_deallocate(mach_task_self(), cclock);
839    now.tv_sec = mts.tv_sec;
840    now.tv_nsec = mts.tv_nsec;
841 #elif !defined(__PSL1GHT__) && defined(__PS3__)
842    sys_time_sec_t s;
843    sys_time_nsec_t n;
844    sys_time_get_current_time(&s, &n);
845    now.tv_sec            = s;
846    now.tv_nsec           = n;
847 #elif defined(PS2)
848    int tickms            = ps2_clock();
849    now.tv_sec            = tickms / 1000;
850    now.tv_nsec           = tickms * 1000;
851 #elif !defined(DINGUX_BETA) && (defined(__mips__) || defined(VITA) || defined(_3DS))
852    struct timeval tm;
853    gettimeofday(&tm, NULL);
854    now.tv_sec            = tm.tv_sec;
855    now.tv_nsec           = tm.tv_usec * 1000;
856 #elif defined(RETRO_WIN32_USE_PTHREADS)
857    _ftime64_s(&now);
858 #elif defined(GEKKO)
859    /* Avoid gettimeofday due to it being reported to be broken */
860    const uint64_t tickms = gettime() / TB_TIMER_CLOCK;
861    now.tv_sec            = tickms / 1000;
862    now.tv_nsec           = tickms * 1000;
863 #else
864    clock_gettime(CLOCK_REALTIME, &now);
865 #endif
866
867    seconds              = timeout_us / INT64_C(1000000);
868    remainder            = timeout_us % INT64_C(1000000);
869
870    now.tv_sec          += seconds;
871    now.tv_nsec         += remainder * INT64_C(1000);
872
873    if (now.tv_nsec > 1000000000)
874    {
875       now.tv_nsec      -= 1000000000;
876       now.tv_sec       += 1;
877    }
878
879    return (pthread_cond_timedwait(&cond->cond, &lock->lock, &now) == 0);
880 #endif
881 }
882
883 #ifdef HAVE_THREAD_STORAGE
884 bool sthread_tls_create(sthread_tls_t *tls)
885 {
886 #ifdef USE_WIN32_THREADS
887    return (*tls = TlsAlloc()) != TLS_OUT_OF_INDEXES;
888 #else
889    return pthread_key_create((pthread_key_t*)tls, NULL) == 0;
890 #endif
891 }
892
893 bool sthread_tls_delete(sthread_tls_t *tls)
894 {
895 #ifdef USE_WIN32_THREADS
896    return TlsFree(*tls) != 0;
897 #else
898    return pthread_key_delete(*tls) == 0;
899 #endif
900 }
901
902 void *sthread_tls_get(sthread_tls_t *tls)
903 {
904 #ifdef USE_WIN32_THREADS
905    return TlsGetValue(*tls);
906 #else
907    return pthread_getspecific(*tls);
908 #endif
909 }
910
911 bool sthread_tls_set(sthread_tls_t *tls, const void *data)
912 {
913 #ifdef USE_WIN32_THREADS
914    return TlsSetValue(*tls, (void*)data) != 0;
915 #else
916    return pthread_setspecific(*tls, data) == 0;
917 #endif
918 }
919 #endif
920
921 uintptr_t sthread_get_thread_id(sthread_t *thread)
922 {
923    if (thread)
924       return (uintptr_t)thread->id;
925    return 0;
926 }
927
928 uintptr_t sthread_get_current_thread_id(void)
929 {
930 #ifdef USE_WIN32_THREADS
931    return (uintptr_t)GetCurrentThreadId();
932 #else
933    return (uintptr_t)pthread_self();
934 #endif
935 }