/simpletypesystem/trunk

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/simpletypesystem/trunk
128 by Gustav Hartvigsson
* Removed blasted #pragma message s from Thread.h
1
/* -*- mode: c; tab-width: 2; indent-tabs-mode: nil; -*-
2
Copyright (c) 2012 Marcus Geelnard
151.1.2 by Gustav Hartvigsson
* Removed wchar.
3
Copyright (c) 2013-2016 Evan Nemerson
128 by Gustav Hartvigsson
* Removed blasted #pragma message s from Thread.h
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
18
    2. Altered source versions must be plainly marked as such, and must not be
19
    misrepresented as being the original software.
20
21
    3. This notice may not be removed or altered from any source
22
    distribution.
23
*/
24
25
#include "tinycthread.h"
26
#include <stdlib.h>
27
28
/* Platform specific includes */
29
#if defined(_TTHREAD_POSIX_)
30
  #include <signal.h>
31
  #include <sched.h>
32
  #include <unistd.h>
33
  #include <sys/time.h>
34
  #include <errno.h>
35
#elif defined(_TTHREAD_WIN32_)
36
  #include <process.h>
37
  #include <sys/timeb.h>
38
#endif
39
40
/* Standard, good-to-have defines */
41
#ifndef NULL
42
  #define NULL (void*)0
43
#endif
44
#ifndef TRUE
45
  #define TRUE 1
46
#endif
47
#ifndef FALSE
48
  #define FALSE 0
49
#endif
50
51
#ifdef __cplusplus
52
extern "C" {
53
#endif
54
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
  mtx->mTimed = type & mtx_timed;
62
  if (!mtx->mTimed)
63
  {
64
    InitializeCriticalSection(&(mtx->mHandle.cs));
65
  }
66
  else
67
  {
68
    mtx->mHandle.mut = CreateMutex(NULL, FALSE, NULL);
69
    if (mtx->mHandle.mut == NULL)
70
    {
71
      return thrd_error;
72
    }
73
  }
74
  return thrd_success;
75
#else
76
  int ret;
77
  pthread_mutexattr_t attr;
78
  pthread_mutexattr_init(&attr);
79
  if (type & mtx_recursive)
80
  {
81
    pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
82
  }
83
  ret = pthread_mutex_init(mtx, &attr);
84
  pthread_mutexattr_destroy(&attr);
85
  return ret == 0 ? thrd_success : thrd_error;
86
#endif
87
}
88
89
void mtx_destroy(mtx_t *mtx)
90
{
91
#if defined(_TTHREAD_WIN32_)
92
  if (!mtx->mTimed)
93
  {
94
    DeleteCriticalSection(&(mtx->mHandle.cs));
95
  }
96
  else
97
  {
98
    CloseHandle(mtx->mHandle.mut);
99
  }
100
#else
101
  pthread_mutex_destroy(mtx);
102
#endif
103
}
104
105
int mtx_lock(mtx_t *mtx)
106
{
107
#if defined(_TTHREAD_WIN32_)
108
  if (!mtx->mTimed)
109
  {
110
    EnterCriticalSection(&(mtx->mHandle.cs));
111
  }
112
  else
113
  {
114
    switch (WaitForSingleObject(mtx->mHandle.mut, INFINITE))
115
    {
116
      case WAIT_OBJECT_0:
117
        break;
118
      case WAIT_ABANDONED:
119
      default:
120
        return thrd_error;
121
    }
122
  }
123
124
  if (!mtx->mRecursive)
125
  {
126
    while(mtx->mAlreadyLocked) Sleep(1); /* Simulate deadlock... */
127
    mtx->mAlreadyLocked = TRUE;
128
  }
129
  return thrd_success;
130
#else
131
  return pthread_mutex_lock(mtx) == 0 ? thrd_success : thrd_error;
132
#endif
133
}
134
135
int mtx_timedlock(mtx_t *mtx, const struct timespec *ts)
136
{
137
#if defined(_TTHREAD_WIN32_)
138
  struct timespec current_ts;
139
  DWORD timeoutMs;
140
141
  if (!mtx->mTimed)
142
  {
143
    return thrd_error;
144
  }
145
146
  timespec_get(&current_ts, TIME_UTC);
147
148
  if ((current_ts.tv_sec > ts->tv_sec) || ((current_ts.tv_sec == ts->tv_sec) && (current_ts.tv_nsec >= ts->tv_nsec)))
149
  {
150
    timeoutMs = 0;
151
  }
152
  else
153
  {
154
    timeoutMs  = (DWORD)(ts->tv_sec  - current_ts.tv_sec)  * 1000;
155
    timeoutMs += (ts->tv_nsec - current_ts.tv_nsec) / 1000000;
156
    timeoutMs += 1;
157
  }
158
159
  /* TODO: the timeout for WaitForSingleObject doesn't include time
160
     while the computer is asleep. */
161
  switch (WaitForSingleObject(mtx->mHandle.mut, timeoutMs))
162
  {
163
    case WAIT_OBJECT_0:
164
      break;
165
    case WAIT_TIMEOUT:
166
      return thrd_timedout;
167
    case WAIT_ABANDONED:
168
    default:
169
      return thrd_error;
170
  }
171
172
  if (!mtx->mRecursive)
173
  {
174
    while(mtx->mAlreadyLocked) Sleep(1); /* Simulate deadlock... */
175
    mtx->mAlreadyLocked = TRUE;
176
  }
177
178
  return thrd_success;
179
#elif defined(_POSIX_TIMEOUTS) && (_POSIX_TIMEOUTS >= 200112L) && defined(_POSIX_THREADS) && (_POSIX_THREADS >= 200112L)
180
  switch (pthread_mutex_timedlock(mtx, ts)) {
181
    case 0:
182
      return thrd_success;
183
    case ETIMEDOUT:
184
      return thrd_timedout;
185
    default:
186
      return thrd_error;
187
  }
188
#else
189
  int rc;
190
  struct timespec cur, dur;
191
192
  /* Try to acquire the lock and, if we fail, sleep for 5ms. */
193
  while ((rc = pthread_mutex_trylock (mtx)) == EBUSY) {
194
    timespec_get(&cur, TIME_UTC);
195
196
    if ((cur.tv_sec > ts->tv_sec) || ((cur.tv_sec == ts->tv_sec) && (cur.tv_nsec >= ts->tv_nsec)))
197
    {
198
      break;
199
    }
200
201
    dur.tv_sec = ts->tv_sec - cur.tv_sec;
202
    dur.tv_nsec = ts->tv_nsec - cur.tv_nsec;
203
    if (dur.tv_nsec < 0)
204
    {
205
      dur.tv_sec--;
206
      dur.tv_nsec += 1000000000;
207
    }
208
209
    if ((dur.tv_sec != 0) || (dur.tv_nsec > 5000000))
210
    {
211
      dur.tv_sec = 0;
212
      dur.tv_nsec = 5000000;
213
    }
214
215
    nanosleep(&dur, NULL);
216
  }
217
218
  switch (rc) {
219
    case 0:
220
      return thrd_success;
221
    case ETIMEDOUT:
222
    case EBUSY:
223
      return thrd_timedout;
224
    default:
225
      return thrd_error;
226
  }
227
#endif
228
}
229
230
int mtx_trylock(mtx_t *mtx)
231
{
232
#if defined(_TTHREAD_WIN32_)
233
  int ret;
234
235
  if (!mtx->mTimed)
236
  {
237
    ret = TryEnterCriticalSection(&(mtx->mHandle.cs)) ? thrd_success : thrd_busy;
238
  }
239
  else
240
  {
241
    ret = (WaitForSingleObject(mtx->mHandle.mut, 0) == WAIT_OBJECT_0) ? thrd_success : thrd_busy;
242
  }
243
244
  if ((!mtx->mRecursive) && (ret == thrd_success))
245
  {
246
    if (mtx->mAlreadyLocked)
247
    {
248
      LeaveCriticalSection(&(mtx->mHandle.cs));
249
      ret = thrd_busy;
250
    }
251
    else
252
    {
253
      mtx->mAlreadyLocked = TRUE;
254
    }
255
  }
256
  return ret;
257
#else
258
  return (pthread_mutex_trylock(mtx) == 0) ? thrd_success : thrd_busy;
259
#endif
260
}
261
262
int mtx_unlock(mtx_t *mtx)
263
{
264
#if defined(_TTHREAD_WIN32_)
265
  mtx->mAlreadyLocked = FALSE;
266
  if (!mtx->mTimed)
267
  {
268
    LeaveCriticalSection(&(mtx->mHandle.cs));
269
  }
270
  else
271
  {
272
    if (!ReleaseMutex(mtx->mHandle.mut))
273
    {
274
      return thrd_error;
275
    }
276
  }
277
  return thrd_success;
278
#else
279
  return pthread_mutex_unlock(mtx) == 0 ? thrd_success : thrd_error;;
280
#endif
281
}
282
283
#if defined(_TTHREAD_WIN32_)
284
#define _CONDITION_EVENT_ONE 0
285
#define _CONDITION_EVENT_ALL 1
286
#endif
287
288
int cnd_init(cnd_t *cond)
289
{
290
#if defined(_TTHREAD_WIN32_)
291
  cond->mWaitersCount = 0;
292
293
  /* Init critical section */
294
  InitializeCriticalSection(&cond->mWaitersCountLock);
295
296
  /* Init events */
297
  cond->mEvents[_CONDITION_EVENT_ONE] = CreateEvent(NULL, FALSE, FALSE, NULL);
298
  if (cond->mEvents[_CONDITION_EVENT_ONE] == NULL)
299
  {
300
    cond->mEvents[_CONDITION_EVENT_ALL] = NULL;
301
    return thrd_error;
302
  }
303
  cond->mEvents[_CONDITION_EVENT_ALL] = CreateEvent(NULL, TRUE, FALSE, NULL);
304
  if (cond->mEvents[_CONDITION_EVENT_ALL] == NULL)
305
  {
306
    CloseHandle(cond->mEvents[_CONDITION_EVENT_ONE]);
307
    cond->mEvents[_CONDITION_EVENT_ONE] = NULL;
308
    return thrd_error;
309
  }
310
311
  return thrd_success;
312
#else
313
  return pthread_cond_init(cond, NULL) == 0 ? thrd_success : thrd_error;
314
#endif
315
}
316
317
void cnd_destroy(cnd_t *cond)
318
{
319
#if defined(_TTHREAD_WIN32_)
320
  if (cond->mEvents[_CONDITION_EVENT_ONE] != NULL)
321
  {
322
    CloseHandle(cond->mEvents[_CONDITION_EVENT_ONE]);
323
  }
324
  if (cond->mEvents[_CONDITION_EVENT_ALL] != NULL)
325
  {
326
    CloseHandle(cond->mEvents[_CONDITION_EVENT_ALL]);
327
  }
328
  DeleteCriticalSection(&cond->mWaitersCountLock);
329
#else
330
  pthread_cond_destroy(cond);
331
#endif
332
}
333
334
int cnd_signal(cnd_t *cond)
335
{
336
#if defined(_TTHREAD_WIN32_)
337
  int haveWaiters;
338
339
  /* Are there any waiters? */
340
  EnterCriticalSection(&cond->mWaitersCountLock);
341
  haveWaiters = (cond->mWaitersCount > 0);
342
  LeaveCriticalSection(&cond->mWaitersCountLock);
343
344
  /* If we have any waiting threads, send them a signal */
345
  if(haveWaiters)
346
  {
347
    if (SetEvent(cond->mEvents[_CONDITION_EVENT_ONE]) == 0)
348
    {
349
      return thrd_error;
350
    }
351
  }
352
353
  return thrd_success;
354
#else
355
  return pthread_cond_signal(cond) == 0 ? thrd_success : thrd_error;
356
#endif
357
}
358
359
int cnd_broadcast(cnd_t *cond)
360
{
361
#if defined(_TTHREAD_WIN32_)
362
  int haveWaiters;
363
364
  /* Are there any waiters? */
365
  EnterCriticalSection(&cond->mWaitersCountLock);
366
  haveWaiters = (cond->mWaitersCount > 0);
367
  LeaveCriticalSection(&cond->mWaitersCountLock);
368
369
  /* If we have any waiting threads, send them a signal */
370
  if(haveWaiters)
371
  {
372
    if (SetEvent(cond->mEvents[_CONDITION_EVENT_ALL]) == 0)
373
    {
374
      return thrd_error;
375
    }
376
  }
377
378
  return thrd_success;
379
#else
380
  return pthread_cond_broadcast(cond) == 0 ? thrd_success : thrd_error;
381
#endif
382
}
383
384
#if defined(_TTHREAD_WIN32_)
385
static int _cnd_timedwait_win32(cnd_t *cond, mtx_t *mtx, DWORD timeout)
386
{
151.1.2 by Gustav Hartvigsson
* Removed wchar.
387
  DWORD result;
388
  int lastWaiter;
128 by Gustav Hartvigsson
* Removed blasted #pragma message s from Thread.h
389
390
  /* Increment number of waiters */
391
  EnterCriticalSection(&cond->mWaitersCountLock);
392
  ++ cond->mWaitersCount;
393
  LeaveCriticalSection(&cond->mWaitersCountLock);
394
395
  /* Release the mutex while waiting for the condition (will decrease
396
     the number of waiters when done)... */
397
  mtx_unlock(mtx);
398
399
  /* Wait for either event to become signaled due to cnd_signal() or
400
     cnd_broadcast() being called */
401
  result = WaitForMultipleObjects(2, cond->mEvents, FALSE, timeout);
402
  if (result == WAIT_TIMEOUT)
403
  {
404
    /* The mutex is locked again before the function returns, even if an error occurred */
405
    mtx_lock(mtx);
406
    return thrd_timedout;
407
  }
151.1.2 by Gustav Hartvigsson
* Removed wchar.
408
  else if (result == WAIT_FAILED)
128 by Gustav Hartvigsson
* Removed blasted #pragma message s from Thread.h
409
  {
410
    /* The mutex is locked again before the function returns, even if an error occurred */
411
    mtx_lock(mtx);
412
    return thrd_error;
413
  }
414
415
  /* Check if we are the last waiter */
416
  EnterCriticalSection(&cond->mWaitersCountLock);
417
  -- cond->mWaitersCount;
418
  lastWaiter = (result == (WAIT_OBJECT_0 + _CONDITION_EVENT_ALL)) &&
419
               (cond->mWaitersCount == 0);
420
  LeaveCriticalSection(&cond->mWaitersCountLock);
421
422
  /* If we are the last waiter to be notified to stop waiting, reset the event */
423
  if (lastWaiter)
424
  {
425
    if (ResetEvent(cond->mEvents[_CONDITION_EVENT_ALL]) == 0)
426
    {
427
      /* The mutex is locked again before the function returns, even if an error occurred */
428
      mtx_lock(mtx);
429
      return thrd_error;
430
    }
431
  }
432
433
  /* Re-acquire the mutex */
434
  mtx_lock(mtx);
435
436
  return thrd_success;
437
}
438
#endif
439
440
int cnd_wait(cnd_t *cond, mtx_t *mtx)
441
{
442
#if defined(_TTHREAD_WIN32_)
443
  return _cnd_timedwait_win32(cond, mtx, INFINITE);
444
#else
445
  return pthread_cond_wait(cond, mtx) == 0 ? thrd_success : thrd_error;
446
#endif
447
}
448
449
int cnd_timedwait(cnd_t *cond, mtx_t *mtx, const struct timespec *ts)
450
{
451
#if defined(_TTHREAD_WIN32_)
452
  struct timespec now;
453
  if (timespec_get(&now, TIME_UTC) == TIME_UTC)
454
  {
455
    unsigned long long nowInMilliseconds = now.tv_sec * 1000 + now.tv_nsec / 1000000;
456
    unsigned long long tsInMilliseconds  = ts->tv_sec * 1000 + ts->tv_nsec / 1000000;
457
    DWORD delta = (tsInMilliseconds > nowInMilliseconds) ?
458
      (DWORD)(tsInMilliseconds - nowInMilliseconds) : 0;
459
    return _cnd_timedwait_win32(cond, mtx, delta);
460
  }
461
  else
462
    return thrd_error;
463
#else
464
  int ret;
465
  ret = pthread_cond_timedwait(cond, mtx, ts);
466
  if (ret == ETIMEDOUT)
467
  {
468
    return thrd_timedout;
469
  }
470
  return ret == 0 ? thrd_success : thrd_error;
471
#endif
472
}
473
474
#if defined(_TTHREAD_WIN32_)
475
struct TinyCThreadTSSData {
476
  void* value;
477
  tss_t key;
478
  struct TinyCThreadTSSData* next;
479
};
480
481
static tss_dtor_t _tinycthread_tss_dtors[1088] = { NULL, };
482
483
static _Thread_local struct TinyCThreadTSSData* _tinycthread_tss_head = NULL;
484
static _Thread_local struct TinyCThreadTSSData* _tinycthread_tss_tail = NULL;
485
486
static void _tinycthread_tss_cleanup (void);
487
488
static void _tinycthread_tss_cleanup (void) {
489
  struct TinyCThreadTSSData* data;
490
  int iteration;
491
  unsigned int again = 1;
492
  void* value;
493
494
  for (iteration = 0 ; iteration < TSS_DTOR_ITERATIONS && again > 0 ; iteration++)
495
  {
496
    again = 0;
497
    for (data = _tinycthread_tss_head ; data != NULL ; data = data->next)
498
    {
499
      if (data->value != NULL)
500
      {
501
        value = data->value;
502
        data->value = NULL;
503
504
        if (_tinycthread_tss_dtors[data->key] != NULL)
505
        {
506
          again = 1;
507
          _tinycthread_tss_dtors[data->key](value);
508
        }
509
      }
510
    }
511
  }
512
513
  while (_tinycthread_tss_head != NULL) {
514
    data = _tinycthread_tss_head->next;
515
    free (_tinycthread_tss_head);
516
    _tinycthread_tss_head = data;
517
  }
518
  _tinycthread_tss_head = NULL;
519
  _tinycthread_tss_tail = NULL;
520
}
521
522
static void NTAPI _tinycthread_tss_callback(PVOID h, DWORD dwReason, PVOID pv)
523
{
524
  (void)h;
525
  (void)pv;
526
527
  if (_tinycthread_tss_head != NULL && (dwReason == DLL_THREAD_DETACH || dwReason == DLL_PROCESS_DETACH))
528
  {
529
    _tinycthread_tss_cleanup();
530
  }
531
}
532
533
#if defined(_MSC_VER)
534
  #ifdef _M_X64
535
    #pragma const_seg(".CRT$XLB")
536
  #else
537
    #pragma data_seg(".CRT$XLB")
538
  #endif
539
  PIMAGE_TLS_CALLBACK p_thread_callback = _tinycthread_tss_callback;
540
  #ifdef _M_X64
541
    #pragma data_seg()
542
  #else
543
    #pragma const_seg()
544
  #endif
545
#else
546
  PIMAGE_TLS_CALLBACK p_thread_callback __attribute__((section(".CRT$XLB"))) = _tinycthread_tss_callback;
547
#endif
548
549
#endif /* defined(_TTHREAD_WIN32_) */
550
551
/** Information to pass to the new thread (what to run). */
552
typedef struct {
553
  thrd_start_t mFunction; /**< Pointer to the function to be executed. */
554
  void * mArg;            /**< Function argument for the thread function. */
555
} _thread_start_info;
556
557
/* Thread wrapper function. */
558
#if defined(_TTHREAD_WIN32_)
559
static DWORD WINAPI _thrd_wrapper_function(LPVOID aArg)
560
#elif defined(_TTHREAD_POSIX_)
561
static void * _thrd_wrapper_function(void * aArg)
562
#endif
563
{
564
  thrd_start_t fun;
565
  void *arg;
566
  int  res;
567
568
  /* Get thread startup information */
569
  _thread_start_info *ti = (_thread_start_info *) aArg;
570
  fun = ti->mFunction;
571
  arg = ti->mArg;
572
573
  /* The thread is responsible for freeing the startup information */
574
  free((void *)ti);
575
576
  /* Call the actual client thread function */
577
  res = fun(arg);
578
579
#if defined(_TTHREAD_WIN32_)
580
  if (_tinycthread_tss_head != NULL)
581
  {
582
    _tinycthread_tss_cleanup();
583
  }
584
585
  return (DWORD)res;
586
#else
587
  return (void*)(intptr_t)res;
588
#endif
589
}
590
591
int thrd_create(thrd_t *thr, thrd_start_t func, void *arg)
592
{
593
  /* Fill out the thread startup information (passed to the thread wrapper,
594
     which will eventually free it) */
595
  _thread_start_info* ti = (_thread_start_info*)malloc(sizeof(_thread_start_info));
596
  if (ti == NULL)
597
  {
598
    return thrd_nomem;
599
  }
600
  ti->mFunction = func;
601
  ti->mArg = arg;
602
603
  /* Create the thread */
604
#if defined(_TTHREAD_WIN32_)
605
  *thr = CreateThread(NULL, 0, _thrd_wrapper_function, (LPVOID) ti, 0, NULL);
606
#elif defined(_TTHREAD_POSIX_)
607
  if(pthread_create(thr, NULL, _thrd_wrapper_function, (void *)ti) != 0)
608
  {
609
    *thr = 0;
610
  }
611
#endif
612
613
  /* Did we fail to create the thread? */
614
  if(!*thr)
615
  {
616
    free(ti);
617
    return thrd_error;
618
  }
619
620
  return thrd_success;
621
}
622
623
thrd_t thrd_current(void)
624
{
625
#if defined(_TTHREAD_WIN32_)
626
  return GetCurrentThread();
627
#else
628
  return pthread_self();
629
#endif
630
}
631
632
int thrd_detach(thrd_t thr)
633
{
634
#if defined(_TTHREAD_WIN32_)
635
  /* https://stackoverflow.com/questions/12744324/how-to-detach-a-thread-on-windows-c#answer-12746081 */
636
  return CloseHandle(thr) != 0 ? thrd_success : thrd_error;
637
#else
638
  return pthread_detach(thr) == 0 ? thrd_success : thrd_error;
639
#endif
640
}
641
642
int thrd_equal(thrd_t thr0, thrd_t thr1)
643
{
644
#if defined(_TTHREAD_WIN32_)
151.1.2 by Gustav Hartvigsson
* Removed wchar.
645
  return GetThreadId(thr0) == GetThreadId(thr1);
128 by Gustav Hartvigsson
* Removed blasted #pragma message s from Thread.h
646
#else
647
  return pthread_equal(thr0, thr1);
648
#endif
649
}
650
651
void thrd_exit(int res)
652
{
653
#if defined(_TTHREAD_WIN32_)
654
  if (_tinycthread_tss_head != NULL)
655
  {
656
    _tinycthread_tss_cleanup();
657
  }
658
151.1.2 by Gustav Hartvigsson
* Removed wchar.
659
  ExitThread((DWORD)res);
128 by Gustav Hartvigsson
* Removed blasted #pragma message s from Thread.h
660
#else
661
  pthread_exit((void*)(intptr_t)res);
662
#endif
663
}
664
665
int thrd_join(thrd_t thr, int *res)
666
{
667
#if defined(_TTHREAD_WIN32_)
668
  DWORD dwRes;
669
670
  if (WaitForSingleObject(thr, INFINITE) == WAIT_FAILED)
671
  {
672
    return thrd_error;
673
  }
674
  if (res != NULL)
675
  {
676
    if (GetExitCodeThread(thr, &dwRes) != 0)
677
    {
151.1.2 by Gustav Hartvigsson
* Removed wchar.
678
      *res = (int) dwRes;
128 by Gustav Hartvigsson
* Removed blasted #pragma message s from Thread.h
679
    }
680
    else
681
    {
682
      return thrd_error;
683
    }
684
  }
685
  CloseHandle(thr);
686
#elif defined(_TTHREAD_POSIX_)
687
  void *pres;
688
  if (pthread_join(thr, &pres) != 0)
689
  {
690
    return thrd_error;
691
  }
692
  if (res != NULL)
693
  {
694
    *res = (int)(intptr_t)pres;
695
  }
696
#endif
697
  return thrd_success;
698
}
699
700
int thrd_sleep(const struct timespec *duration, struct timespec *remaining)
701
{
702
#if !defined(_TTHREAD_WIN32_)
151.1.2 by Gustav Hartvigsson
* Removed wchar.
703
  int res = nanosleep(duration, remaining);
704
  if (res == 0) {
705
    return 0;
706
  } else if (errno == EINTR) {
707
    return -1;
708
  } else {
709
    return -2;
710
  }
128 by Gustav Hartvigsson
* Removed blasted #pragma message s from Thread.h
711
#else
712
  struct timespec start;
713
  DWORD t;
714
715
  timespec_get(&start, TIME_UTC);
716
717
  t = SleepEx((DWORD)(duration->tv_sec * 1000 +
718
              duration->tv_nsec / 1000000 +
719
              (((duration->tv_nsec % 1000000) == 0) ? 0 : 1)),
720
              TRUE);
721
722
  if (t == 0) {
723
    return 0;
151.1.2 by Gustav Hartvigsson
* Removed wchar.
724
  } else {
725
    if (remaining != NULL) {
726
      timespec_get(remaining, TIME_UTC);
727
      remaining->tv_sec -= start.tv_sec;
728
      remaining->tv_nsec -= start.tv_nsec;
729
      if (remaining->tv_nsec < 0)
730
      {
731
        remaining->tv_nsec += 1000000000;
732
        remaining->tv_sec -= 1;
733
      }
128 by Gustav Hartvigsson
* Removed blasted #pragma message s from Thread.h
734
    }
151.1.2 by Gustav Hartvigsson
* Removed wchar.
735
736
    return (t == WAIT_IO_COMPLETION) ? -1 : -2;
128 by Gustav Hartvigsson
* Removed blasted #pragma message s from Thread.h
737
  }
738
#endif
739
}
740
741
void thrd_yield(void)
742
{
743
#if defined(_TTHREAD_WIN32_)
744
  Sleep(0);
745
#else
746
  sched_yield();
747
#endif
748
}
749
750
int tss_create(tss_t *key, tss_dtor_t dtor)
751
{
752
#if defined(_TTHREAD_WIN32_)
753
  *key = TlsAlloc();
754
  if (*key == TLS_OUT_OF_INDEXES)
755
  {
756
    return thrd_error;
757
  }
758
  _tinycthread_tss_dtors[*key] = dtor;
759
#else
760
  if (pthread_key_create(key, dtor) != 0)
761
  {
762
    return thrd_error;
763
  }
764
#endif
765
  return thrd_success;
766
}
767
768
void tss_delete(tss_t key)
769
{
770
#if defined(_TTHREAD_WIN32_)
771
  struct TinyCThreadTSSData* data = (struct TinyCThreadTSSData*) TlsGetValue (key);
772
  struct TinyCThreadTSSData* prev = NULL;
773
  if (data != NULL)
774
  {
775
    if (data == _tinycthread_tss_head)
776
    {
777
      _tinycthread_tss_head = data->next;
778
    }
779
    else
780
    {
781
      prev = _tinycthread_tss_head;
782
      if (prev != NULL)
783
      {
784
        while (prev->next != data)
785
        {
786
          prev = prev->next;
787
        }
788
      }
789
    }
790
791
    if (data == _tinycthread_tss_tail)
792
    {
793
      _tinycthread_tss_tail = prev;
794
    }
795
796
    free (data);
797
  }
798
  _tinycthread_tss_dtors[key] = NULL;
799
  TlsFree(key);
800
#else
801
  pthread_key_delete(key);
802
#endif
803
}
804
805
void *tss_get(tss_t key)
806
{
807
#if defined(_TTHREAD_WIN32_)
808
  struct TinyCThreadTSSData* data = (struct TinyCThreadTSSData*)TlsGetValue(key);
809
  if (data == NULL)
810
  {
811
    return NULL;
812
  }
813
  return data->value;
814
#else
815
  return pthread_getspecific(key);
816
#endif
817
}
818
819
int tss_set(tss_t key, void *val)
820
{
821
#if defined(_TTHREAD_WIN32_)
822
  struct TinyCThreadTSSData* data = (struct TinyCThreadTSSData*)TlsGetValue(key);
823
  if (data == NULL)
824
  {
825
    data = (struct TinyCThreadTSSData*)malloc(sizeof(struct TinyCThreadTSSData));
826
    if (data == NULL)
827
    {
828
      return thrd_error;
829
	}
830
831
    data->value = NULL;
832
    data->key = key;
833
    data->next = NULL;
834
835
    if (_tinycthread_tss_tail != NULL)
836
    {
837
      _tinycthread_tss_tail->next = data;
838
    }
839
    else
840
    {
841
      _tinycthread_tss_tail = data;
842
    }
843
844
    if (_tinycthread_tss_head == NULL)
845
    {
846
      _tinycthread_tss_head = data;
847
    }
848
849
    if (!TlsSetValue(key, data))
850
    {
851
      free (data);
852
	  return thrd_error;
853
    }
854
  }
855
  data->value = val;
856
#else
857
  if (pthread_setspecific(key, val) != 0)
858
  {
859
    return thrd_error;
860
  }
861
#endif
862
  return thrd_success;
863
}
864
865
#if defined(_TTHREAD_EMULATE_TIMESPEC_GET_)
866
int _tthread_timespec_get(struct timespec *ts, int base)
867
{
868
#if defined(_TTHREAD_WIN32_)
869
  struct _timeb tb;
870
#elif !defined(CLOCK_REALTIME)
871
  struct timeval tv;
872
#endif
873
874
  if (base != TIME_UTC)
875
  {
876
    return 0;
877
  }
878
879
#if defined(_TTHREAD_WIN32_)
880
  _ftime_s(&tb);
881
  ts->tv_sec = (time_t)tb.time;
882
  ts->tv_nsec = 1000000L * (long)tb.millitm;
883
#elif defined(CLOCK_REALTIME)
884
  base = (clock_gettime(CLOCK_REALTIME, ts) == 0) ? base : 0;
885
#else
886
  gettimeofday(&tv, NULL);
887
  ts->tv_sec = (time_t)tv.tv_sec;
888
  ts->tv_nsec = 1000L * (long)tv.tv_usec;
889
#endif
890
891
  return base;
892
}
893
#endif /* _TTHREAD_EMULATE_TIMESPEC_GET_ */
894
895
#if defined(_TTHREAD_WIN32_)
896
void call_once(once_flag *flag, void (*func)(void))
897
{
898
  /* The idea here is that we use a spin lock (via the
899
     InterlockedCompareExchange function) to restrict access to the
900
     critical section until we have initialized it, then we use the
901
     critical section to block until the callback has completed
902
     execution. */
903
  while (flag->status < 3)
904
  {
905
    switch (flag->status)
906
    {
907
      case 0:
908
        if (InterlockedCompareExchange (&(flag->status), 1, 0) == 0) {
909
          InitializeCriticalSection(&(flag->lock));
910
          EnterCriticalSection(&(flag->lock));
911
          flag->status = 2;
912
          func();
913
          flag->status = 3;
914
          LeaveCriticalSection(&(flag->lock));
915
          return;
916
        }
917
        break;
918
      case 1:
919
        break;
920
      case 2:
921
        EnterCriticalSection(&(flag->lock));
922
        LeaveCriticalSection(&(flag->lock));
923
        break;
924
    }
925
  }
926
}
927
#endif /* defined(_TTHREAD_WIN32_) */
928
929
#ifdef __cplusplus
930
}
931
#endif