tinycthread.c
Go to the documentation of this file.
1 /* -*- mode: c; tab-width: 2; indent-tabs-mode: nil; -*-
2 Copyright (c) 2012 Marcus Geelnard
3 
4 This software is provided 'as-is', without any express or implied
5 warranty. In no event will the authors be held liable for any damages
6 arising from the use of this software.
7 
8 Permission is granted to anyone to use this software for any purpose,
9 including commercial applications, and to alter it and redistribute it
10 freely, subject to the following restrictions:
11 
12  1. The origin of this software must not be misrepresented; you must not
13  claim that you wrote the original software. If you use this software
14  in a product, an acknowledgment in the product documentation would be
15  appreciated but is not required.
16 
17  2. Altered source versions must be plainly marked as such, and must not be
18  misrepresented as being the original software.
19 
20  3. This notice may not be removed or altered from any source
21  distribution.
22 */
23 
24 /* 2013-01-06 Camilla Löwy <elmindreda@glfw.org>
25  *
26  * Added casts from time_t to DWORD to avoid warnings on VC++.
27  * Fixed time retrieval on POSIX systems.
28  */
29 
30 #include "tinycthread.h"
31 #include <stdlib.h>
32 
33 /* Platform specific includes */
34 #if defined(_TTHREAD_POSIX_)
35  #include <signal.h>
36  #include <sched.h>
37  #include <unistd.h>
38  #include <sys/time.h>
39  #include <errno.h>
40 #elif defined(_TTHREAD_WIN32_)
41  #include <process.h>
42  #include <sys/timeb.h>
43 #endif
44 
45 /* Standard, good-to-have defines */
46 #ifndef NULL
47  #define NULL (void*)0
48 #endif
49 #ifndef TRUE
50  #define TRUE 1
51 #endif
52 #ifndef FALSE
53  #define FALSE 0
54 #endif
55 
56 int mtx_init(mtx_t *mtx, int type)
57 {
58 #if defined(_TTHREAD_WIN32_)
59  mtx->mAlreadyLocked = FALSE;
60  mtx->mRecursive = type & mtx_recursive;
61  InitializeCriticalSection(&mtx->mHandle);
62  return thrd_success;
63 #else
64  int ret;
65  pthread_mutexattr_t attr;
66  pthread_mutexattr_init(&attr);
67  if (type & mtx_recursive)
68  {
69  pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
70  }
71  ret = pthread_mutex_init(mtx, &attr);
72  pthread_mutexattr_destroy(&attr);
73  return ret == 0 ? thrd_success : thrd_error;
74 #endif
75 }
76 
77 void mtx_destroy(mtx_t *mtx)
78 {
79 #if defined(_TTHREAD_WIN32_)
80  DeleteCriticalSection(&mtx->mHandle);
81 #else
82  pthread_mutex_destroy(mtx);
83 #endif
84 }
85 
86 int mtx_lock(mtx_t *mtx)
87 {
88 #if defined(_TTHREAD_WIN32_)
89  EnterCriticalSection(&mtx->mHandle);
90  if (!mtx->mRecursive)
91  {
92  while(mtx->mAlreadyLocked) Sleep(1000); /* Simulate deadlock... */
93  mtx->mAlreadyLocked = TRUE;
94  }
95  return thrd_success;
96 #else
97  return pthread_mutex_lock(mtx) == 0 ? thrd_success : thrd_error;
98 #endif
99 }
100 
101 int mtx_timedlock(mtx_t *mtx, const struct timespec *ts)
102 {
103  /* FIXME! */
104  (void)mtx;
105  (void)ts;
106  return thrd_error;
107 }
108 
110 {
111 #if defined(_TTHREAD_WIN32_)
112  int ret = TryEnterCriticalSection(&mtx->mHandle) ? thrd_success : thrd_busy;
113  if ((!mtx->mRecursive) && (ret == thrd_success) && mtx->mAlreadyLocked)
114  {
115  LeaveCriticalSection(&mtx->mHandle);
116  ret = thrd_busy;
117  }
118  return ret;
119 #else
120  return (pthread_mutex_trylock(mtx) == 0) ? thrd_success : thrd_busy;
121 #endif
122 }
123 
124 int mtx_unlock(mtx_t *mtx)
125 {
126 #if defined(_TTHREAD_WIN32_)
127  mtx->mAlreadyLocked = FALSE;
128  LeaveCriticalSection(&mtx->mHandle);
129  return thrd_success;
130 #else
131  return pthread_mutex_unlock(mtx) == 0 ? thrd_success : thrd_error;;
132 #endif
133 }
134 
135 #if defined(_TTHREAD_WIN32_)
136 #define _CONDITION_EVENT_ONE 0
137 #define _CONDITION_EVENT_ALL 1
138 #endif
139 
140 int cnd_init(cnd_t *cond)
141 {
142 #if defined(_TTHREAD_WIN32_)
143  cond->mWaitersCount = 0;
144 
145  /* Init critical section */
146  InitializeCriticalSection(&cond->mWaitersCountLock);
147 
148  /* Init events */
149  cond->mEvents[_CONDITION_EVENT_ONE] = CreateEvent(NULL, FALSE, FALSE, NULL);
150  if (cond->mEvents[_CONDITION_EVENT_ONE] == NULL)
151  {
152  cond->mEvents[_CONDITION_EVENT_ALL] = NULL;
153  return thrd_error;
154  }
155  cond->mEvents[_CONDITION_EVENT_ALL] = CreateEvent(NULL, TRUE, FALSE, NULL);
156  if (cond->mEvents[_CONDITION_EVENT_ALL] == NULL)
157  {
158  CloseHandle(cond->mEvents[_CONDITION_EVENT_ONE]);
159  cond->mEvents[_CONDITION_EVENT_ONE] = NULL;
160  return thrd_error;
161  }
162 
163  return thrd_success;
164 #else
165  return pthread_cond_init(cond, NULL) == 0 ? thrd_success : thrd_error;
166 #endif
167 }
168 
169 void cnd_destroy(cnd_t *cond)
170 {
171 #if defined(_TTHREAD_WIN32_)
172  if (cond->mEvents[_CONDITION_EVENT_ONE] != NULL)
173  {
174  CloseHandle(cond->mEvents[_CONDITION_EVENT_ONE]);
175  }
176  if (cond->mEvents[_CONDITION_EVENT_ALL] != NULL)
177  {
178  CloseHandle(cond->mEvents[_CONDITION_EVENT_ALL]);
179  }
180  DeleteCriticalSection(&cond->mWaitersCountLock);
181 #else
182  pthread_cond_destroy(cond);
183 #endif
184 }
185 
186 int cnd_signal(cnd_t *cond)
187 {
188 #if defined(_TTHREAD_WIN32_)
189  int haveWaiters;
190 
191  /* Are there any waiters? */
192  EnterCriticalSection(&cond->mWaitersCountLock);
193  haveWaiters = (cond->mWaitersCount > 0);
194  LeaveCriticalSection(&cond->mWaitersCountLock);
195 
196  /* If we have any waiting threads, send them a signal */
197  if(haveWaiters)
198  {
199  if (SetEvent(cond->mEvents[_CONDITION_EVENT_ONE]) == 0)
200  {
201  return thrd_error;
202  }
203  }
204 
205  return thrd_success;
206 #else
207  return pthread_cond_signal(cond) == 0 ? thrd_success : thrd_error;
208 #endif
209 }
210 
212 {
213 #if defined(_TTHREAD_WIN32_)
214  int haveWaiters;
215 
216  /* Are there any waiters? */
217  EnterCriticalSection(&cond->mWaitersCountLock);
218  haveWaiters = (cond->mWaitersCount > 0);
219  LeaveCriticalSection(&cond->mWaitersCountLock);
220 
221  /* If we have any waiting threads, send them a signal */
222  if(haveWaiters)
223  {
224  if (SetEvent(cond->mEvents[_CONDITION_EVENT_ALL]) == 0)
225  {
226  return thrd_error;
227  }
228  }
229 
230  return thrd_success;
231 #else
232  return pthread_cond_signal(cond) == 0 ? thrd_success : thrd_error;
233 #endif
234 }
235 
236 #if defined(_TTHREAD_WIN32_)
237 static int _cnd_timedwait_win32(cnd_t *cond, mtx_t *mtx, DWORD timeout)
238 {
239  int result, lastWaiter;
240 
241  /* Increment number of waiters */
242  EnterCriticalSection(&cond->mWaitersCountLock);
243  ++ cond->mWaitersCount;
244  LeaveCriticalSection(&cond->mWaitersCountLock);
245 
246  /* Release the mutex while waiting for the condition (will decrease
247  the number of waiters when done)... */
248  mtx_unlock(mtx);
249 
250  /* Wait for either event to become signaled due to cnd_signal() or
251  cnd_broadcast() being called */
252  result = WaitForMultipleObjects(2, cond->mEvents, FALSE, timeout);
253  if (result == WAIT_TIMEOUT)
254  {
255  return thrd_timeout;
256  }
257  else if (result == (int)WAIT_FAILED)
258  {
259  return thrd_error;
260  }
261 
262  /* Check if we are the last waiter */
263  EnterCriticalSection(&cond->mWaitersCountLock);
264  -- cond->mWaitersCount;
265  lastWaiter = (result == (WAIT_OBJECT_0 + _CONDITION_EVENT_ALL)) &&
266  (cond->mWaitersCount == 0);
267  LeaveCriticalSection(&cond->mWaitersCountLock);
268 
269  /* If we are the last waiter to be notified to stop waiting, reset the event */
270  if (lastWaiter)
271  {
272  if (ResetEvent(cond->mEvents[_CONDITION_EVENT_ALL]) == 0)
273  {
274  return thrd_error;
275  }
276  }
277 
278  /* Re-acquire the mutex */
279  mtx_lock(mtx);
280 
281  return thrd_success;
282 }
283 #endif
284 
285 int cnd_wait(cnd_t *cond, mtx_t *mtx)
286 {
287 #if defined(_TTHREAD_WIN32_)
288  return _cnd_timedwait_win32(cond, mtx, INFINITE);
289 #else
290  return pthread_cond_wait(cond, mtx) == 0 ? thrd_success : thrd_error;
291 #endif
292 }
293 
294 int cnd_timedwait(cnd_t *cond, mtx_t *mtx, const struct timespec *ts)
295 {
296 #if defined(_TTHREAD_WIN32_)
297  struct timespec now;
298  if (clock_gettime(CLOCK_REALTIME, &now) == 0)
299  {
300  DWORD delta = (DWORD) ((ts->tv_sec - now.tv_sec) * 1000 +
301  (ts->tv_nsec - now.tv_nsec + 500000) / 1000000);
302  return _cnd_timedwait_win32(cond, mtx, delta);
303  }
304  else
305  return thrd_error;
306 #else
307  int ret;
308  ret = pthread_cond_timedwait(cond, mtx, ts);
309  if (ret == ETIMEDOUT)
310  {
311  return thrd_timeout;
312  }
313  return ret == 0 ? thrd_success : thrd_error;
314 #endif
315 }
316 
317 
319 typedef struct {
321  void * mArg;
323 
324 /* Thread wrapper function. */
325 #if defined(_TTHREAD_WIN32_)
326 static unsigned WINAPI _thrd_wrapper_function(void * aArg)
327 #elif defined(_TTHREAD_POSIX_)
328 static void * _thrd_wrapper_function(void * aArg)
329 #endif
330 {
331  thrd_start_t fun;
332  void *arg;
333  int res;
334 #if defined(_TTHREAD_POSIX_)
335  void *pres;
336 #endif
337 
338  /* Get thread startup information */
339  _thread_start_info *ti = (_thread_start_info *) aArg;
340  fun = ti->mFunction;
341  arg = ti->mArg;
342 
343  /* The thread is responsible for freeing the startup information */
344  free((void *)ti);
345 
346  /* Call the actual client thread function */
347  res = fun(arg);
348 
349 #if defined(_TTHREAD_WIN32_)
350  return res;
351 #else
352  pres = malloc(sizeof(int));
353  if (pres != NULL)
354  {
355  *(int*)pres = res;
356  }
357  return pres;
358 #endif
359 }
360 
362 {
363  /* Fill out the thread startup information (passed to the thread wrapper,
364  which will eventually free it) */
366  if (ti == NULL)
367  {
368  return thrd_nomem;
369  }
370  ti->mFunction = func;
371  ti->mArg = arg;
372 
373  /* Create the thread */
374 #if defined(_TTHREAD_WIN32_)
375  *thr = (HANDLE)_beginthreadex(NULL, 0, _thrd_wrapper_function, (void *)ti, 0, NULL);
376 #elif defined(_TTHREAD_POSIX_)
377  if(pthread_create(thr, NULL, _thrd_wrapper_function, (void *)ti) != 0)
378  {
379  *thr = 0;
380  }
381 #endif
382 
383  /* Did we fail to create the thread? */
384  if(!*thr)
385  {
386  free(ti);
387  return thrd_error;
388  }
389 
390  return thrd_success;
391 }
392 
394 {
395 #if defined(_TTHREAD_WIN32_)
396  return GetCurrentThread();
397 #else
398  return pthread_self();
399 #endif
400 }
401 
403 {
404  /* FIXME! */
405  (void)thr;
406  return thrd_error;
407 }
408 
409 int thrd_equal(thrd_t thr0, thrd_t thr1)
410 {
411 #if defined(_TTHREAD_WIN32_)
412  return thr0 == thr1;
413 #else
414  return pthread_equal(thr0, thr1);
415 #endif
416 }
417 
418 void thrd_exit(int res)
419 {
420 #if defined(_TTHREAD_WIN32_)
421  ExitThread(res);
422 #else
423  void *pres = malloc(sizeof(int));
424  if (pres != NULL)
425  {
426  *(int*)pres = res;
427  }
428  pthread_exit(pres);
429 #endif
430 }
431 
432 int thrd_join(thrd_t thr, int *res)
433 {
434 #if defined(_TTHREAD_WIN32_)
435  if (WaitForSingleObject(thr, INFINITE) == WAIT_FAILED)
436  {
437  return thrd_error;
438  }
439  if (res != NULL)
440  {
441  DWORD dwRes;
442  GetExitCodeThread(thr, &dwRes);
443  *res = dwRes;
444  }
445 #elif defined(_TTHREAD_POSIX_)
446  void *pres;
447  int ires = 0;
448  if (pthread_join(thr, &pres) != 0)
449  {
450  return thrd_error;
451  }
452  if (pres != NULL)
453  {
454  ires = *(int*)pres;
455  free(pres);
456  }
457  if (res != NULL)
458  {
459  *res = ires;
460  }
461 #endif
462  return thrd_success;
463 }
464 
465 int thrd_sleep(const struct timespec *time_point, struct timespec *remaining)
466 {
467  struct timespec now;
468 #if defined(_TTHREAD_WIN32_)
469  DWORD delta;
470 #else
471  long delta;
472 #endif
473 
474  /* Get the current time */
475  if (clock_gettime(CLOCK_REALTIME, &now) != 0)
476  return -2; // FIXME: Some specific error code?
477 
478 #if defined(_TTHREAD_WIN32_)
479  /* Delta in milliseconds */
480  delta = (DWORD) ((time_point->tv_sec - now.tv_sec) * 1000 +
481  (time_point->tv_nsec - now.tv_nsec + 500000) / 1000000);
482  if (delta > 0)
483  {
484  Sleep(delta);
485  }
486 #else
487  /* Delta in microseconds */
488  delta = (time_point->tv_sec - now.tv_sec) * 1000000L +
489  (time_point->tv_nsec - now.tv_nsec + 500L) / 1000L;
490 
491  /* On some systems, the usleep argument must be < 1000000 */
492  while (delta > 999999L)
493  {
494  usleep(999999);
495  delta -= 999999L;
496  }
497  if (delta > 0L)
498  {
499  usleep((useconds_t)delta);
500  }
501 #endif
502 
503  /* We don't support waking up prematurely (yet) */
504  if (remaining)
505  {
506  remaining->tv_sec = 0;
507  remaining->tv_nsec = 0;
508  }
509  return 0;
510 }
511 
512 void thrd_yield(void)
513 {
514 #if defined(_TTHREAD_WIN32_)
515  Sleep(0);
516 #else
517  sched_yield();
518 #endif
519 }
520 
522 {
523 #if defined(_TTHREAD_WIN32_)
524  /* FIXME: The destructor function is not supported yet... */
525  if (dtor != NULL)
526  {
527  return thrd_error;
528  }
529  *key = TlsAlloc();
530  if (*key == TLS_OUT_OF_INDEXES)
531  {
532  return thrd_error;
533  }
534 #else
535  if (pthread_key_create(key, dtor) != 0)
536  {
537  return thrd_error;
538  }
539 #endif
540  return thrd_success;
541 }
542 
544 {
545 #if defined(_TTHREAD_WIN32_)
546  TlsFree(key);
547 #else
548  pthread_key_delete(key);
549 #endif
550 }
551 
553 {
554 #if defined(_TTHREAD_WIN32_)
555  return TlsGetValue(key);
556 #else
557  return pthread_getspecific(key);
558 #endif
559 }
560 
561 int tss_set(tss_t key, void *val)
562 {
563 #if defined(_TTHREAD_WIN32_)
564  if (TlsSetValue(key, val) == 0)
565  {
566  return thrd_error;
567  }
568 #else
569  if (pthread_setspecific(key, val) != 0)
570  {
571  return thrd_error;
572  }
573 #endif
574  return thrd_success;
575 }
576 
577 #if defined(_TTHREAD_EMULATE_CLOCK_GETTIME_)
578 int _tthread_clock_gettime(clockid_t clk_id, struct timespec *ts)
579 {
580 #if defined(_TTHREAD_WIN32_)
581  struct _timeb tb;
582  _ftime(&tb);
583  ts->tv_sec = (time_t)tb.time;
584  ts->tv_nsec = 1000000L * (long)tb.millitm;
585 #else
586  struct timeval tv;
587  gettimeofday(&tv, NULL);
588  ts->tv_sec = (time_t)tv.tv_sec;
589  ts->tv_nsec = 1000L * (long)tv.tv_usec;
590 #endif
591  return 0;
592 }
593 #endif // _TTHREAD_EMULATE_CLOCK_GETTIME_
594 
void thrd_exit(int res)
Definition: tinycthread.c:418
typedef void(APIENTRY *GLDEBUGPROC)(GLenum source
thrd_start_t mFunction
Definition: tinycthread.c:320
int cnd_timedwait(cnd_t *cond, mtx_t *mtx, const struct timespec *ts)
Definition: tinycthread.c:294
int mtx_timedlock(mtx_t *mtx, const struct timespec *ts)
Definition: tinycthread.c:101
int thrd_equal(thrd_t thr0, thrd_t thr1)
Definition: tinycthread.c:409
int mtx_init(mtx_t *mtx, int type)
Definition: tinycthread.c:56
pthread_cond_t cnd_t
Definition: tinycthread.h:252
int thrd_create(thrd_t *thr, thrd_start_t func, void *arg)
Definition: tinycthread.c:361
#define thrd_nomem
Definition: tinycthread.h:175
int(* thrd_start_t)(void *arg)
Definition: tinycthread.h:328
Definition: arg_fwd.hpp:23
#define mtx_recursive
Definition: tinycthread.h:181
GLuint GLfloat * val
GLuint64 key
Definition: glext.h:8966
#define thrd_error
Definition: tinycthread.h:171
void tss_delete(tss_t key)
Definition: tinycthread.c:543
int mtx_unlock(mtx_t *mtx)
Definition: tinycthread.c:124
int tss_set(tss_t key, void *val)
Definition: tinycthread.c:561
int tss_create(tss_t *key, tss_dtor_t dtor)
Definition: tinycthread.c:521
int cnd_init(cnd_t *cond)
Definition: tinycthread.c:140
int cnd_wait(cnd_t *cond, mtx_t *mtx)
Definition: tinycthread.c:285
#define thrd_timeout
Definition: tinycthread.h:173
void * tss_get(tss_t key)
Definition: tinycthread.c:552
void mtx_destroy(mtx_t *mtx)
Definition: tinycthread.c:77
void(* tss_dtor_t)(void *val)
Definition: tinycthread.h:404
int thrd_join(thrd_t thr, int *res)
Definition: tinycthread.c:432
int cnd_broadcast(cnd_t *cond)
Definition: tinycthread.c:211
GLenum func
void thrd_yield(void)
Definition: tinycthread.c:512
pthread_mutex_t mtx_t
Definition: tinycthread.h:191
pthread_key_t tss_t
Definition: tinycthread.h:398
void cnd_destroy(cnd_t *cond)
Definition: tinycthread.c:169
static void * _thrd_wrapper_function(void *aArg)
Definition: tinycthread.c:328
#define thrd_busy
Definition: tinycthread.h:174
GLbitfield GLuint64 timeout
GLenum type
int cnd_signal(cnd_t *cond)
Definition: tinycthread.c:186
pthread_t thrd_t
Definition: tinycthread.h:317
thrd_t thrd_current(void)
Definition: tinycthread.c:393
#define NULL
Definition: tinycthread.c:47
#define TRUE
Definition: tinycthread.c:50
GLuint res
Definition: glext.h:8856
int thrd_sleep(const struct timespec *time_point, struct timespec *remaining)
Definition: tinycthread.c:465
int mtx_lock(mtx_t *mtx)
Definition: tinycthread.c:86
#define FALSE
Definition: tinycthread.c:53
int mtx_trylock(mtx_t *mtx)
Definition: tinycthread.c:109
GLuint64EXT * result
Definition: glext.h:10921
#define thrd_success
Definition: tinycthread.h:172
int thrd_detach(thrd_t thr)
Definition: tinycthread.c:402


librealsense2
Author(s): Sergey Dorodnicov , Doron Hirshberg , Mark Horn , Reagan Lopez , Itay Carpis
autogenerated on Mon May 3 2021 02:50:11