1 /*         ______   ___    ___
2  *        /\  _  \ /\_ \  /\_ \
3  *        \ \ \L\ \\//\ \ \//\ \      __     __   _ __   ___
4  *         \ \  __ \ \ \ \  \ \ \   /'__`\ /'_ `\/\`'__\/ __`\
5  *          \ \ \/\ \ \_\ \_ \_\ \_/\  __//\ \L\ \ \ \//\ \L\ \
6  *           \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/
7  *            \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/
8  *                                           /\____/
9  *                                           \_/__/
10  *
11  *      SDL thread support.
12  *
13  *      See LICENSE.txt for copyright information.
14  */
15 #include "allegro5/allegro.h"
16 #include "allegro5/internal/aintern.h"
17 #include "allegro5/internal/aintern_thread.h"
18 #include "allegro5/platform/allegro_internal_sdl.h"
19 
20 ALLEGRO_DEBUG_CHANNEL("thread")
21 
thread_trampoline(void * data)22 static int thread_trampoline(void* data)
23 {
24    _AL_THREAD *thread = data;
25    (*thread->proc)(thread, thread->arg);
26    return 0;
27 }
28 
_al_thread_create(_AL_THREAD * thread,void (* proc)(_AL_THREAD *,void *),void * arg)29 void _al_thread_create(_AL_THREAD *thread, void (*proc)(_AL_THREAD*, void*),
30    void *arg)
31 {
32    ASSERT(thread);
33    ASSERT(proc);
34    thread->should_stop = false;
35    thread->proc = proc;
36    thread->arg = arg;
37    thread->thread = SDL_CreateThread(thread_trampoline, "allegro", thread);
38 }
39 
_al_thread_create_with_stacksize(_AL_THREAD * thread,void (* proc)(_AL_THREAD *,void *),void * arg,size_t stacksize)40 void _al_thread_create_with_stacksize(_AL_THREAD *thread, void (*proc)(_AL_THREAD*, void*),
41    void *arg, size_t stacksize)
42 {
43    ASSERT(thread);
44    ASSERT(proc);
45    thread->should_stop = false;
46    thread->proc = proc;
47    thread->arg = arg;
48 #if SDL_VERSION_ATLEAST(2,0,9)
49    thread->thread = SDL_CreateThreadWithStackSize(thread_trampoline, "allegro", stacksize, thread);
50 #else
51    (void)stacksize;
52    ALLEGRO_WARN("Creating a thread with a custom thread size is not supported "
53       "on this version of SDL, it is too old.\n");
54    thread->thread = SDL_CreateThread(thread_trampoline, "allegro", thread);
55 #endif
56 }
57 
_al_thread_set_should_stop(_AL_THREAD * thread)58 void _al_thread_set_should_stop(_AL_THREAD *thread)
59 {
60    ASSERT(thread);
61    thread->should_stop = true;
62 }
63 
_al_thread_join(_AL_THREAD * thread)64 void _al_thread_join(_AL_THREAD *thread)
65 {
66    ASSERT(thread);
67    _al_thread_set_should_stop(thread);
68    int r;
69    SDL_WaitThread(thread->thread, &r);
70 }
71 
_al_thread_detach(_AL_THREAD * thread)72 void _al_thread_detach(_AL_THREAD *thread)
73 {
74    ASSERT(thread);
75    SDL_DetachThread(thread->thread);
76 }
77 
78 /* mutexes */
79 
_al_mutex_init(_AL_MUTEX * mutex)80 void _al_mutex_init(_AL_MUTEX *mutex)
81 {
82    ASSERT(mutex);
83 
84    mutex->mutex = SDL_CreateMutex();
85 }
86 
_al_mutex_init_recursive(_AL_MUTEX * mutex)87 void _al_mutex_init_recursive(_AL_MUTEX *mutex)
88 {
89    _al_mutex_init(mutex);
90 }
91 
_al_mutex_destroy(_AL_MUTEX * mutex)92 void _al_mutex_destroy(_AL_MUTEX *mutex)
93 {
94    ASSERT(mutex);
95 
96    if (mutex->mutex) {
97       SDL_DestroyMutex(mutex->mutex);
98       mutex->mutex = NULL;
99    }
100 }
101 
102 /* condition variables */
103 /* most of the condition variable implementation is actually inline */
104 
_al_cond_timedwait(_AL_COND * cond,_AL_MUTEX * mutex,const ALLEGRO_TIMEOUT * timeout)105 int _al_cond_timedwait(_AL_COND *cond, _AL_MUTEX *mutex,
106    const ALLEGRO_TIMEOUT *timeout)
107 {
108    ALLEGRO_TIMEOUT_SDL *timeout_sdl = (void *)timeout;
109    int r = SDL_CondWaitTimeout(cond->cond, mutex->mutex, timeout_sdl->ms);
110 
111    return (r == SDL_MUTEX_TIMEDOUT) ? -1 : 0;
112 }
113