1 | /* |
2 | Simple DirectMedia Layer |
3 | Copyright (C) 1997-2025 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_sysmutex_c.h" |
30 | |
31 | struct SDL_Condition |
32 | { |
33 | pthread_cond_t cond; |
34 | }; |
35 | |
36 | // Create a condition variable |
37 | SDL_Condition *SDL_CreateCondition(void) |
38 | { |
39 | SDL_Condition *cond; |
40 | |
41 | cond = (SDL_Condition *)SDL_malloc(sizeof(SDL_Condition)); |
42 | if (cond) { |
43 | if (pthread_cond_init(&cond->cond, NULL) != 0) { |
44 | SDL_SetError("pthread_cond_init() failed" ); |
45 | SDL_free(cond); |
46 | cond = NULL; |
47 | } |
48 | } |
49 | return cond; |
50 | } |
51 | |
52 | // Destroy a condition variable |
53 | void SDL_DestroyCondition(SDL_Condition *cond) |
54 | { |
55 | if (cond) { |
56 | pthread_cond_destroy(&cond->cond); |
57 | SDL_free(cond); |
58 | } |
59 | } |
60 | |
61 | // Restart one of the threads that are waiting on the condition variable |
62 | void SDL_SignalCondition(SDL_Condition *cond) |
63 | { |
64 | if (!cond) { |
65 | return; |
66 | } |
67 | |
68 | pthread_cond_signal(&cond->cond); |
69 | } |
70 | |
71 | // Restart all threads that are waiting on the condition variable |
72 | void SDL_BroadcastCondition(SDL_Condition *cond) |
73 | { |
74 | if (!cond) { |
75 | return; |
76 | } |
77 | |
78 | pthread_cond_broadcast(&cond->cond); |
79 | } |
80 | |
81 | bool SDL_WaitConditionTimeoutNS(SDL_Condition *cond, SDL_Mutex *mutex, Sint64 timeoutNS) |
82 | { |
83 | #ifndef HAVE_CLOCK_GETTIME |
84 | struct timeval delta; |
85 | #endif |
86 | struct timespec abstime; |
87 | |
88 | if (!cond || !mutex) { |
89 | return true; |
90 | } |
91 | |
92 | if (timeoutNS < 0) { |
93 | return (pthread_cond_wait(&cond->cond, &mutex->id) == 0); |
94 | } |
95 | |
96 | #ifdef HAVE_CLOCK_GETTIME |
97 | clock_gettime(CLOCK_REALTIME, &abstime); |
98 | |
99 | abstime.tv_sec += (timeoutNS / SDL_NS_PER_SECOND); |
100 | abstime.tv_nsec += (timeoutNS % SDL_NS_PER_SECOND); |
101 | #else |
102 | gettimeofday(&delta, NULL); |
103 | |
104 | abstime.tv_sec = delta.tv_sec + (timeoutNS / SDL_NS_PER_SECOND); |
105 | abstime.tv_nsec = SDL_US_TO_NS(delta.tv_usec) + (timeoutNS % SDL_NS_PER_SECOND); |
106 | #endif |
107 | while (abstime.tv_nsec >= 1000000000) { |
108 | abstime.tv_sec += 1; |
109 | abstime.tv_nsec -= 1000000000; |
110 | } |
111 | |
112 | bool result; |
113 | int rc; |
114 | tryagain: |
115 | rc = pthread_cond_timedwait(&cond->cond, &mutex->id, &abstime); |
116 | switch (rc) { |
117 | case EINTR: |
118 | goto tryagain; |
119 | // break; -Wunreachable-code-break |
120 | case ETIMEDOUT: |
121 | result = false; |
122 | break; |
123 | default: |
124 | result = true; |
125 | break; |
126 | } |
127 | return result; |
128 | } |
129 | |