1 | /* |
2 | Simple DirectMedia Layer |
3 | Copyright (C) 1997-2021 Sam Lantinga <slouken@libsdl.org> |
4 | |
5 | This software is provided 'as-is', without any express or implied |
6 | warranty. In no event will the authors be held liable for any damages |
7 | arising from the use of this software. |
8 | |
9 | Permission is granted to anyone to use this software for any purpose, |
10 | including commercial applications, and to alter it and redistribute it |
11 | freely, subject to the following restrictions: |
12 | |
13 | 1. The origin of this software must not be misrepresented; you must not |
14 | claim that you wrote the original software. If you use this software |
15 | in a product, an acknowledgment in the product documentation would be |
16 | appreciated but is not required. |
17 | 2. Altered source versions must be plainly marked as such, and must not be |
18 | misrepresented as being the original software. |
19 | 3. This notice may not be removed or altered from any source distribution. |
20 | */ |
21 | #include "../../SDL_internal.h" |
22 | |
23 | #include <sys/time.h> |
24 | #include <time.h> |
25 | #include <unistd.h> |
26 | #include <errno.h> |
27 | #include <pthread.h> |
28 | |
29 | #include "SDL_thread.h" |
30 | #include "SDL_sysmutex_c.h" |
31 | |
32 | struct SDL_cond |
33 | { |
34 | pthread_cond_t cond; |
35 | }; |
36 | |
37 | /* Create a condition variable */ |
38 | SDL_cond * |
39 | SDL_CreateCond(void) |
40 | { |
41 | SDL_cond *cond; |
42 | |
43 | cond = (SDL_cond *) SDL_malloc(sizeof(SDL_cond)); |
44 | if (cond) { |
45 | if (pthread_cond_init(&cond->cond, NULL) != 0) { |
46 | SDL_SetError("pthread_cond_init() failed" ); |
47 | SDL_free(cond); |
48 | cond = NULL; |
49 | } |
50 | } |
51 | return (cond); |
52 | } |
53 | |
54 | /* Destroy a condition variable */ |
55 | void |
56 | SDL_DestroyCond(SDL_cond * cond) |
57 | { |
58 | if (cond) { |
59 | pthread_cond_destroy(&cond->cond); |
60 | SDL_free(cond); |
61 | } |
62 | } |
63 | |
64 | /* Restart one of the threads that are waiting on the condition variable */ |
65 | int |
66 | SDL_CondSignal(SDL_cond * cond) |
67 | { |
68 | int retval; |
69 | |
70 | if (!cond) { |
71 | return SDL_SetError("Passed a NULL condition variable" ); |
72 | } |
73 | |
74 | retval = 0; |
75 | if (pthread_cond_signal(&cond->cond) != 0) { |
76 | return SDL_SetError("pthread_cond_signal() failed" ); |
77 | } |
78 | return retval; |
79 | } |
80 | |
81 | /* Restart all threads that are waiting on the condition variable */ |
82 | int |
83 | SDL_CondBroadcast(SDL_cond * cond) |
84 | { |
85 | int retval; |
86 | |
87 | if (!cond) { |
88 | return SDL_SetError("Passed a NULL condition variable" ); |
89 | } |
90 | |
91 | retval = 0; |
92 | if (pthread_cond_broadcast(&cond->cond) != 0) { |
93 | return SDL_SetError("pthread_cond_broadcast() failed" ); |
94 | } |
95 | return retval; |
96 | } |
97 | |
98 | int |
99 | SDL_CondWaitTimeout(SDL_cond * cond, SDL_mutex * mutex, Uint32 ms) |
100 | { |
101 | int retval; |
102 | #ifndef HAVE_CLOCK_GETTIME |
103 | struct timeval delta; |
104 | #endif |
105 | struct timespec abstime; |
106 | |
107 | if (!cond) { |
108 | return SDL_SetError("Passed a NULL condition variable" ); |
109 | } |
110 | |
111 | #ifdef HAVE_CLOCK_GETTIME |
112 | clock_gettime(CLOCK_REALTIME, &abstime); |
113 | |
114 | abstime.tv_nsec += (ms % 1000) * 1000000; |
115 | abstime.tv_sec += ms / 1000; |
116 | #else |
117 | gettimeofday(&delta, NULL); |
118 | |
119 | abstime.tv_sec = delta.tv_sec + (ms / 1000); |
120 | abstime.tv_nsec = (delta.tv_usec + (ms % 1000) * 1000) * 1000; |
121 | #endif |
122 | if (abstime.tv_nsec > 1000000000) { |
123 | abstime.tv_sec += 1; |
124 | abstime.tv_nsec -= 1000000000; |
125 | } |
126 | |
127 | tryagain: |
128 | retval = pthread_cond_timedwait(&cond->cond, &mutex->id, &abstime); |
129 | switch (retval) { |
130 | case EINTR: |
131 | goto tryagain; |
132 | /* break; -Wunreachable-code-break */ |
133 | case ETIMEDOUT: |
134 | retval = SDL_MUTEX_TIMEDOUT; |
135 | break; |
136 | case 0: |
137 | break; |
138 | default: |
139 | retval = SDL_SetError("pthread_cond_timedwait() failed" ); |
140 | } |
141 | return retval; |
142 | } |
143 | |
144 | /* Wait on the condition variable, unlocking the provided mutex. |
145 | The mutex must be locked before entering this function! |
146 | */ |
147 | int |
148 | SDL_CondWait(SDL_cond * cond, SDL_mutex * mutex) |
149 | { |
150 | if (!cond) { |
151 | return SDL_SetError("Passed a NULL condition variable" ); |
152 | } else if (pthread_cond_wait(&cond->cond, &mutex->id) != 0) { |
153 | return SDL_SetError("pthread_cond_wait() failed" ); |
154 | } |
155 | return 0; |
156 | } |
157 | |
158 | /* vi: set ts=4 sw=4 expandtab: */ |
159 | |