commit 86d99b5

uint  ·  2026-05-04 10:08:50 +0000 UTC
parent 2cde702
revert back to pthread from tinycthread
6 files changed,  +38, -1468
+9, -2
 1@@ -3,8 +3,15 @@ CC = cc
 2 VER = 2.26
 3 GIT_VER != git describe --always --tags 2>/dev/null || echo unknown
 4 CPPFLAGS = -D_POSIX_C_SOURCE=200809L -DGIT_VER=\"$(GIT_VER)\" -DVERSION=\"$(VER)\"
 5-CFLAGS = -std=c99 -Wall -Wextra -Iserver/include -Iexternal -pthread
 6-SRC = server/*.c external/tinycthread.c
 7+CFLAGS = -std=c99 -Wall -Wextra -Iserver/include -pthread
 8+SRC = server/config.c \
 9+      server/http.c \
10+      server/json.c \
11+      server/parados.c \
12+      server/scan.c \
13+      server/users.c \
14+      server/util.c
15+
16 OUT = parados
17 
18 # Install Paths
+0, -22
 1@@ -1,22 +0,0 @@
 2-Copyright (c) 2012 Marcus Geelnard
 3-              2013-2016 Evan Nemerson
 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-
+0, -931
  1@@ -1,931 +0,0 @@
  2-/* -*- mode: c; tab-width: 2; indent-tabs-mode: nil; -*-
  3-Copyright (c) 2012 Marcus Geelnard
  4-Copyright (c) 2013-2016 Evan Nemerson
  5-
  6-This software is provided 'as-is', without any express or implied
  7-warranty. In no event will the authors be held liable for any damages
  8-arising from the use of this software.
  9-
 10-Permission is granted to anyone to use this software for any purpose,
 11-including commercial applications, and to alter it and redistribute it
 12-freely, subject to the following restrictions:
 13-
 14-    1. The origin of this software must not be misrepresented; you must not
 15-    claim that you wrote the original software. If you use this software
 16-    in a product, an acknowledgment in the product documentation would be
 17-    appreciated but is not required.
 18-
 19-    2. Altered source versions must be plainly marked as such, and must not be
 20-    misrepresented as being the original software.
 21-
 22-    3. This notice may not be removed or altered from any source
 23-    distribution.
 24-*/
 25-
 26-#include <stdlib.h>
 27-#include "tinycthread.h"
 28-
 29-/* Platform specific includes */
 30-#if defined(_TTHREAD_POSIX_)
 31-  #include <signal.h>
 32-  #include <sched.h>
 33-  #include <unistd.h>
 34-  #include <sys/time.h>
 35-  #include <errno.h>
 36-#elif defined(_TTHREAD_WIN32_)
 37-  #include <process.h>
 38-  #include <sys/timeb.h>
 39-#endif
 40-
 41-/* Standard, good-to-have defines */
 42-#ifndef NULL
 43-  #define NULL (void*)0
 44-#endif
 45-#ifndef TRUE
 46-  #define TRUE 1
 47-#endif
 48-#ifndef FALSE
 49-  #define FALSE 0
 50-#endif
 51-
 52-#ifdef __cplusplus
 53-extern "C" {
 54-#endif
 55-
 56-
 57-int mtx_init(mtx_t *mtx, int type)
 58-{
 59-#if defined(_TTHREAD_WIN32_)
 60-  mtx->mAlreadyLocked = FALSE;
 61-  mtx->mRecursive = type & mtx_recursive;
 62-  mtx->mTimed = type & mtx_timed;
 63-  if (!mtx->mTimed)
 64-  {
 65-    InitializeCriticalSection(&(mtx->mHandle.cs));
 66-  }
 67-  else
 68-  {
 69-    mtx->mHandle.mut = CreateMutex(NULL, FALSE, NULL);
 70-    if (mtx->mHandle.mut == NULL)
 71-    {
 72-      return thrd_error;
 73-    }
 74-  }
 75-  return thrd_success;
 76-#else
 77-  int ret;
 78-  pthread_mutexattr_t attr;
 79-  pthread_mutexattr_init(&attr);
 80-  if (type & mtx_recursive)
 81-  {
 82-    pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
 83-  }
 84-  ret = pthread_mutex_init(mtx, &attr);
 85-  pthread_mutexattr_destroy(&attr);
 86-  return ret == 0 ? thrd_success : thrd_error;
 87-#endif
 88-}
 89-
 90-void mtx_destroy(mtx_t *mtx)
 91-{
 92-#if defined(_TTHREAD_WIN32_)
 93-  if (!mtx->mTimed)
 94-  {
 95-    DeleteCriticalSection(&(mtx->mHandle.cs));
 96-  }
 97-  else
 98-  {
 99-    CloseHandle(mtx->mHandle.mut);
100-  }
101-#else
102-  pthread_mutex_destroy(mtx);
103-#endif
104-}
105-
106-int mtx_lock(mtx_t *mtx)
107-{
108-#if defined(_TTHREAD_WIN32_)
109-  if (!mtx->mTimed)
110-  {
111-    EnterCriticalSection(&(mtx->mHandle.cs));
112-  }
113-  else
114-  {
115-    switch (WaitForSingleObject(mtx->mHandle.mut, INFINITE))
116-    {
117-      case WAIT_OBJECT_0:
118-        break;
119-      case WAIT_ABANDONED:
120-      default:
121-        return thrd_error;
122-    }
123-  }
124-
125-  if (!mtx->mRecursive)
126-  {
127-    while(mtx->mAlreadyLocked) Sleep(1); /* Simulate deadlock... */
128-    mtx->mAlreadyLocked = TRUE;
129-  }
130-  return thrd_success;
131-#else
132-  return pthread_mutex_lock(mtx) == 0 ? thrd_success : thrd_error;
133-#endif
134-}
135-
136-int mtx_timedlock(mtx_t *mtx, const struct timespec *ts)
137-{
138-#if defined(_TTHREAD_WIN32_)
139-  struct timespec current_ts;
140-  DWORD timeoutMs;
141-
142-  if (!mtx->mTimed)
143-  {
144-    return thrd_error;
145-  }
146-
147-  timespec_get(&current_ts, TIME_UTC);
148-
149-  if ((current_ts.tv_sec > ts->tv_sec) || ((current_ts.tv_sec == ts->tv_sec) && (current_ts.tv_nsec >= ts->tv_nsec)))
150-  {
151-    timeoutMs = 0;
152-  }
153-  else
154-  {
155-    timeoutMs  = (DWORD)(ts->tv_sec  - current_ts.tv_sec)  * 1000;
156-    timeoutMs += (ts->tv_nsec - current_ts.tv_nsec) / 1000000;
157-    timeoutMs += 1;
158-  }
159-
160-  /* TODO: the timeout for WaitForSingleObject doesn't include time
161-     while the computer is asleep. */
162-  switch (WaitForSingleObject(mtx->mHandle.mut, timeoutMs))
163-  {
164-    case WAIT_OBJECT_0:
165-      break;
166-    case WAIT_TIMEOUT:
167-      return thrd_timedout;
168-    case WAIT_ABANDONED:
169-    default:
170-      return thrd_error;
171-  }
172-
173-  if (!mtx->mRecursive)
174-  {
175-    while(mtx->mAlreadyLocked) Sleep(1); /* Simulate deadlock... */
176-    mtx->mAlreadyLocked = TRUE;
177-  }
178-
179-  return thrd_success;
180-#elif defined(_POSIX_TIMEOUTS) && (_POSIX_TIMEOUTS >= 200112L) && defined(_POSIX_THREADS) && (_POSIX_THREADS >= 200112L)
181-  switch (pthread_mutex_timedlock(mtx, ts)) {
182-    case 0:
183-      return thrd_success;
184-    case ETIMEDOUT:
185-      return thrd_timedout;
186-    default:
187-      return thrd_error;
188-  }
189-#else
190-  int rc;
191-  struct timespec cur, dur;
192-
193-  /* Try to acquire the lock and, if we fail, sleep for 5ms. */
194-  while ((rc = pthread_mutex_trylock (mtx)) == EBUSY) {
195-    timespec_get(&cur, TIME_UTC);
196-
197-    if ((cur.tv_sec > ts->tv_sec) || ((cur.tv_sec == ts->tv_sec) && (cur.tv_nsec >= ts->tv_nsec)))
198-    {
199-      break;
200-    }
201-
202-    dur.tv_sec = ts->tv_sec - cur.tv_sec;
203-    dur.tv_nsec = ts->tv_nsec - cur.tv_nsec;
204-    if (dur.tv_nsec < 0)
205-    {
206-      dur.tv_sec--;
207-      dur.tv_nsec += 1000000000;
208-    }
209-
210-    if ((dur.tv_sec != 0) || (dur.tv_nsec > 5000000))
211-    {
212-      dur.tv_sec = 0;
213-      dur.tv_nsec = 5000000;
214-    }
215-
216-    nanosleep(&dur, NULL);
217-  }
218-
219-  switch (rc) {
220-    case 0:
221-      return thrd_success;
222-    case ETIMEDOUT:
223-    case EBUSY:
224-      return thrd_timedout;
225-    default:
226-      return thrd_error;
227-  }
228-#endif
229-}
230-
231-int mtx_trylock(mtx_t *mtx)
232-{
233-#if defined(_TTHREAD_WIN32_)
234-  int ret;
235-
236-  if (!mtx->mTimed)
237-  {
238-    ret = TryEnterCriticalSection(&(mtx->mHandle.cs)) ? thrd_success : thrd_busy;
239-  }
240-  else
241-  {
242-    ret = (WaitForSingleObject(mtx->mHandle.mut, 0) == WAIT_OBJECT_0) ? thrd_success : thrd_busy;
243-  }
244-
245-  if ((!mtx->mRecursive) && (ret == thrd_success))
246-  {
247-    if (mtx->mAlreadyLocked)
248-    {
249-      LeaveCriticalSection(&(mtx->mHandle.cs));
250-      ret = thrd_busy;
251-    }
252-    else
253-    {
254-      mtx->mAlreadyLocked = TRUE;
255-    }
256-  }
257-  return ret;
258-#else
259-  return (pthread_mutex_trylock(mtx) == 0) ? thrd_success : thrd_busy;
260-#endif
261-}
262-
263-int mtx_unlock(mtx_t *mtx)
264-{
265-#if defined(_TTHREAD_WIN32_)
266-  mtx->mAlreadyLocked = FALSE;
267-  if (!mtx->mTimed)
268-  {
269-    LeaveCriticalSection(&(mtx->mHandle.cs));
270-  }
271-  else
272-  {
273-    if (!ReleaseMutex(mtx->mHandle.mut))
274-    {
275-      return thrd_error;
276-    }
277-  }
278-  return thrd_success;
279-#else
280-  return pthread_mutex_unlock(mtx) == 0 ? thrd_success : thrd_error;;
281-#endif
282-}
283-
284-#if defined(_TTHREAD_WIN32_)
285-#define _CONDITION_EVENT_ONE 0
286-#define _CONDITION_EVENT_ALL 1
287-#endif
288-
289-int cnd_init(cnd_t *cond)
290-{
291-#if defined(_TTHREAD_WIN32_)
292-  cond->mWaitersCount = 0;
293-
294-  /* Init critical section */
295-  InitializeCriticalSection(&cond->mWaitersCountLock);
296-
297-  /* Init events */
298-  cond->mEvents[_CONDITION_EVENT_ONE] = CreateEvent(NULL, FALSE, FALSE, NULL);
299-  if (cond->mEvents[_CONDITION_EVENT_ONE] == NULL)
300-  {
301-    cond->mEvents[_CONDITION_EVENT_ALL] = NULL;
302-    return thrd_error;
303-  }
304-  cond->mEvents[_CONDITION_EVENT_ALL] = CreateEvent(NULL, TRUE, FALSE, NULL);
305-  if (cond->mEvents[_CONDITION_EVENT_ALL] == NULL)
306-  {
307-    CloseHandle(cond->mEvents[_CONDITION_EVENT_ONE]);
308-    cond->mEvents[_CONDITION_EVENT_ONE] = NULL;
309-    return thrd_error;
310-  }
311-
312-  return thrd_success;
313-#else
314-  return pthread_cond_init(cond, NULL) == 0 ? thrd_success : thrd_error;
315-#endif
316-}
317-
318-void cnd_destroy(cnd_t *cond)
319-{
320-#if defined(_TTHREAD_WIN32_)
321-  if (cond->mEvents[_CONDITION_EVENT_ONE] != NULL)
322-  {
323-    CloseHandle(cond->mEvents[_CONDITION_EVENT_ONE]);
324-  }
325-  if (cond->mEvents[_CONDITION_EVENT_ALL] != NULL)
326-  {
327-    CloseHandle(cond->mEvents[_CONDITION_EVENT_ALL]);
328-  }
329-  DeleteCriticalSection(&cond->mWaitersCountLock);
330-#else
331-  pthread_cond_destroy(cond);
332-#endif
333-}
334-
335-int cnd_signal(cnd_t *cond)
336-{
337-#if defined(_TTHREAD_WIN32_)
338-  int haveWaiters;
339-
340-  /* Are there any waiters? */
341-  EnterCriticalSection(&cond->mWaitersCountLock);
342-  haveWaiters = (cond->mWaitersCount > 0);
343-  LeaveCriticalSection(&cond->mWaitersCountLock);
344-
345-  /* If we have any waiting threads, send them a signal */
346-  if(haveWaiters)
347-  {
348-    if (SetEvent(cond->mEvents[_CONDITION_EVENT_ONE]) == 0)
349-    {
350-      return thrd_error;
351-    }
352-  }
353-
354-  return thrd_success;
355-#else
356-  return pthread_cond_signal(cond) == 0 ? thrd_success : thrd_error;
357-#endif
358-}
359-
360-int cnd_broadcast(cnd_t *cond)
361-{
362-#if defined(_TTHREAD_WIN32_)
363-  int haveWaiters;
364-
365-  /* Are there any waiters? */
366-  EnterCriticalSection(&cond->mWaitersCountLock);
367-  haveWaiters = (cond->mWaitersCount > 0);
368-  LeaveCriticalSection(&cond->mWaitersCountLock);
369-
370-  /* If we have any waiting threads, send them a signal */
371-  if(haveWaiters)
372-  {
373-    if (SetEvent(cond->mEvents[_CONDITION_EVENT_ALL]) == 0)
374-    {
375-      return thrd_error;
376-    }
377-  }
378-
379-  return thrd_success;
380-#else
381-  return pthread_cond_broadcast(cond) == 0 ? thrd_success : thrd_error;
382-#endif
383-}
384-
385-#if defined(_TTHREAD_WIN32_)
386-static int _cnd_timedwait_win32(cnd_t *cond, mtx_t *mtx, DWORD timeout)
387-{
388-  DWORD result;
389-  int lastWaiter;
390-
391-  /* Increment number of waiters */
392-  EnterCriticalSection(&cond->mWaitersCountLock);
393-  ++ cond->mWaitersCount;
394-  LeaveCriticalSection(&cond->mWaitersCountLock);
395-
396-  /* Release the mutex while waiting for the condition (will decrease
397-     the number of waiters when done)... */
398-  mtx_unlock(mtx);
399-
400-  /* Wait for either event to become signaled due to cnd_signal() or
401-     cnd_broadcast() being called */
402-  result = WaitForMultipleObjects(2, cond->mEvents, FALSE, timeout);
403-  if (result == WAIT_TIMEOUT)
404-  {
405-    /* The mutex is locked again before the function returns, even if an error occurred */
406-    mtx_lock(mtx);
407-    return thrd_timedout;
408-  }
409-  else if (result == WAIT_FAILED)
410-  {
411-    /* The mutex is locked again before the function returns, even if an error occurred */
412-    mtx_lock(mtx);
413-    return thrd_error;
414-  }
415-
416-  /* Check if we are the last waiter */
417-  EnterCriticalSection(&cond->mWaitersCountLock);
418-  -- cond->mWaitersCount;
419-  lastWaiter = (result == (WAIT_OBJECT_0 + _CONDITION_EVENT_ALL)) &&
420-               (cond->mWaitersCount == 0);
421-  LeaveCriticalSection(&cond->mWaitersCountLock);
422-
423-  /* If we are the last waiter to be notified to stop waiting, reset the event */
424-  if (lastWaiter)
425-  {
426-    if (ResetEvent(cond->mEvents[_CONDITION_EVENT_ALL]) == 0)
427-    {
428-      /* The mutex is locked again before the function returns, even if an error occurred */
429-      mtx_lock(mtx);
430-      return thrd_error;
431-    }
432-  }
433-
434-  /* Re-acquire the mutex */
435-  mtx_lock(mtx);
436-
437-  return thrd_success;
438-}
439-#endif
440-
441-int cnd_wait(cnd_t *cond, mtx_t *mtx)
442-{
443-#if defined(_TTHREAD_WIN32_)
444-  return _cnd_timedwait_win32(cond, mtx, INFINITE);
445-#else
446-  return pthread_cond_wait(cond, mtx) == 0 ? thrd_success : thrd_error;
447-#endif
448-}
449-
450-int cnd_timedwait(cnd_t *cond, mtx_t *mtx, const struct timespec *ts)
451-{
452-#if defined(_TTHREAD_WIN32_)
453-  struct timespec now;
454-  if (timespec_get(&now, TIME_UTC) == TIME_UTC)
455-  {
456-    unsigned long long nowInMilliseconds = now.tv_sec * 1000 + now.tv_nsec / 1000000;
457-    unsigned long long tsInMilliseconds  = ts->tv_sec * 1000 + ts->tv_nsec / 1000000;
458-    DWORD delta = (tsInMilliseconds > nowInMilliseconds) ?
459-      (DWORD)(tsInMilliseconds - nowInMilliseconds) : 0;
460-    return _cnd_timedwait_win32(cond, mtx, delta);
461-  }
462-  else
463-    return thrd_error;
464-#else
465-  int ret;
466-  ret = pthread_cond_timedwait(cond, mtx, ts);
467-  if (ret == ETIMEDOUT)
468-  {
469-    return thrd_timedout;
470-  }
471-  return ret == 0 ? thrd_success : thrd_error;
472-#endif
473-}
474-
475-#if defined(_TTHREAD_WIN32_)
476-struct TinyCThreadTSSData {
477-  void* value;
478-  tss_t key;
479-  struct TinyCThreadTSSData* next;
480-};
481-
482-static tss_dtor_t _tinycthread_tss_dtors[1088] = { NULL, };
483-
484-static _Thread_local struct TinyCThreadTSSData* _tinycthread_tss_head = NULL;
485-static _Thread_local struct TinyCThreadTSSData* _tinycthread_tss_tail = NULL;
486-
487-static void _tinycthread_tss_cleanup (void);
488-
489-static void _tinycthread_tss_cleanup (void) {
490-  struct TinyCThreadTSSData* data;
491-  int iteration;
492-  unsigned int again = 1;
493-  void* value;
494-
495-  for (iteration = 0 ; iteration < TSS_DTOR_ITERATIONS && again > 0 ; iteration++)
496-  {
497-    again = 0;
498-    for (data = _tinycthread_tss_head ; data != NULL ; data = data->next)
499-    {
500-      if (data->value != NULL)
501-      {
502-        value = data->value;
503-        data->value = NULL;
504-
505-        if (_tinycthread_tss_dtors[data->key] != NULL)
506-        {
507-          again = 1;
508-          _tinycthread_tss_dtors[data->key](value);
509-        }
510-      }
511-    }
512-  }
513-
514-  while (_tinycthread_tss_head != NULL) {
515-    data = _tinycthread_tss_head->next;
516-    free (_tinycthread_tss_head);
517-    _tinycthread_tss_head = data;
518-  }
519-  _tinycthread_tss_head = NULL;
520-  _tinycthread_tss_tail = NULL;
521-}
522-
523-static void NTAPI _tinycthread_tss_callback(PVOID h, DWORD dwReason, PVOID pv)
524-{
525-  (void)h;
526-  (void)pv;
527-
528-  if (_tinycthread_tss_head != NULL && (dwReason == DLL_THREAD_DETACH || dwReason == DLL_PROCESS_DETACH))
529-  {
530-    _tinycthread_tss_cleanup();
531-  }
532-}
533-
534-#if defined(_MSC_VER)
535-  #ifdef _M_X64
536-    #pragma const_seg(".CRT$XLB")
537-  #else
538-    #pragma data_seg(".CRT$XLB")
539-  #endif
540-  PIMAGE_TLS_CALLBACK p_thread_callback = _tinycthread_tss_callback;
541-  #ifdef _M_X64
542-    #pragma data_seg()
543-  #else
544-    #pragma const_seg()
545-  #endif
546-#else
547-  PIMAGE_TLS_CALLBACK p_thread_callback __attribute__((section(".CRT$XLB"))) = _tinycthread_tss_callback;
548-#endif
549-
550-#endif /* defined(_TTHREAD_WIN32_) */
551-
552-/** Information to pass to the new thread (what to run). */
553-typedef struct {
554-  thrd_start_t mFunction; /**< Pointer to the function to be executed. */
555-  void * mArg;            /**< Function argument for the thread function. */
556-} _thread_start_info;
557-
558-/* Thread wrapper function. */
559-#if defined(_TTHREAD_WIN32_)
560-static DWORD WINAPI _thrd_wrapper_function(LPVOID aArg)
561-#elif defined(_TTHREAD_POSIX_)
562-static void * _thrd_wrapper_function(void * aArg)
563-#endif
564-{
565-  thrd_start_t fun;
566-  void *arg;
567-  int  res;
568-
569-  /* Get thread startup information */
570-  _thread_start_info *ti = (_thread_start_info *) aArg;
571-  fun = ti->mFunction;
572-  arg = ti->mArg;
573-
574-  /* The thread is responsible for freeing the startup information */
575-  free((void *)ti);
576-
577-  /* Call the actual client thread function */
578-  res = fun(arg);
579-
580-#if defined(_TTHREAD_WIN32_)
581-  if (_tinycthread_tss_head != NULL)
582-  {
583-    _tinycthread_tss_cleanup();
584-  }
585-
586-  return (DWORD)res;
587-#else
588-  return (void*)(intptr_t)res;
589-#endif
590-}
591-
592-int thrd_create(thrd_t *thr, thrd_start_t func, void *arg)
593-{
594-  /* Fill out the thread startup information (passed to the thread wrapper,
595-     which will eventually free it) */
596-  _thread_start_info* ti = (_thread_start_info*)malloc(sizeof(_thread_start_info));
597-  if (ti == NULL)
598-  {
599-    return thrd_nomem;
600-  }
601-  ti->mFunction = func;
602-  ti->mArg = arg;
603-
604-  /* Create the thread */
605-#if defined(_TTHREAD_WIN32_)
606-  *thr = CreateThread(NULL, 0, _thrd_wrapper_function, (LPVOID) ti, 0, NULL);
607-#elif defined(_TTHREAD_POSIX_)
608-  if(pthread_create(thr, NULL, _thrd_wrapper_function, (void *)ti) != 0)
609-  {
610-    *thr = 0;
611-  }
612-#endif
613-
614-  /* Did we fail to create the thread? */
615-  if(!*thr)
616-  {
617-    free(ti);
618-    return thrd_error;
619-  }
620-
621-  return thrd_success;
622-}
623-
624-thrd_t thrd_current(void)
625-{
626-#if defined(_TTHREAD_WIN32_)
627-  return GetCurrentThread();
628-#else
629-  return pthread_self();
630-#endif
631-}
632-
633-int thrd_detach(thrd_t thr)
634-{
635-#if defined(_TTHREAD_WIN32_)
636-  /* https://stackoverflow.com/questions/12744324/how-to-detach-a-thread-on-windows-c#answer-12746081 */
637-  return CloseHandle(thr) != 0 ? thrd_success : thrd_error;
638-#else
639-  return pthread_detach(thr) == 0 ? thrd_success : thrd_error;
640-#endif
641-}
642-
643-int thrd_equal(thrd_t thr0, thrd_t thr1)
644-{
645-#if defined(_TTHREAD_WIN32_)
646-  return GetThreadId(thr0) == GetThreadId(thr1);
647-#else
648-  return pthread_equal(thr0, thr1);
649-#endif
650-}
651-
652-void thrd_exit(int res)
653-{
654-#if defined(_TTHREAD_WIN32_)
655-  if (_tinycthread_tss_head != NULL)
656-  {
657-    _tinycthread_tss_cleanup();
658-  }
659-
660-  ExitThread((DWORD)res);
661-#else
662-  pthread_exit((void*)(intptr_t)res);
663-#endif
664-}
665-
666-int thrd_join(thrd_t thr, int *res)
667-{
668-#if defined(_TTHREAD_WIN32_)
669-  DWORD dwRes;
670-
671-  if (WaitForSingleObject(thr, INFINITE) == WAIT_FAILED)
672-  {
673-    return thrd_error;
674-  }
675-  if (res != NULL)
676-  {
677-    if (GetExitCodeThread(thr, &dwRes) != 0)
678-    {
679-      *res = (int) dwRes;
680-    }
681-    else
682-    {
683-      return thrd_error;
684-    }
685-  }
686-  CloseHandle(thr);
687-#elif defined(_TTHREAD_POSIX_)
688-  void *pres;
689-  if (pthread_join(thr, &pres) != 0)
690-  {
691-    return thrd_error;
692-  }
693-  if (res != NULL)
694-  {
695-    *res = (int)(intptr_t)pres;
696-  }
697-#endif
698-  return thrd_success;
699-}
700-
701-int thrd_sleep(const struct timespec *duration, struct timespec *remaining)
702-{
703-#if !defined(_TTHREAD_WIN32_)
704-  int res = nanosleep(duration, remaining);
705-  if (res == 0) {
706-    return 0;
707-  } else if (errno == EINTR) {
708-    return -1;
709-  } else {
710-    return -2;
711-  }
712-#else
713-  struct timespec start;
714-  DWORD t;
715-
716-  timespec_get(&start, TIME_UTC);
717-
718-  t = SleepEx((DWORD)(duration->tv_sec * 1000 +
719-              duration->tv_nsec / 1000000 +
720-              (((duration->tv_nsec % 1000000) == 0) ? 0 : 1)),
721-              TRUE);
722-
723-  if (t == 0) {
724-    return 0;
725-  } else {
726-    if (remaining != NULL) {
727-      timespec_get(remaining, TIME_UTC);
728-      remaining->tv_sec -= start.tv_sec;
729-      remaining->tv_nsec -= start.tv_nsec;
730-      if (remaining->tv_nsec < 0)
731-      {
732-        remaining->tv_nsec += 1000000000;
733-        remaining->tv_sec -= 1;
734-      }
735-    }
736-
737-    return (t == WAIT_IO_COMPLETION) ? -1 : -2;
738-  }
739-#endif
740-}
741-
742-void thrd_yield(void)
743-{
744-#if defined(_TTHREAD_WIN32_)
745-  Sleep(0);
746-#else
747-  sched_yield();
748-#endif
749-}
750-
751-int tss_create(tss_t *key, tss_dtor_t dtor)
752-{
753-#if defined(_TTHREAD_WIN32_)
754-  *key = TlsAlloc();
755-  if (*key == TLS_OUT_OF_INDEXES)
756-  {
757-    return thrd_error;
758-  }
759-  _tinycthread_tss_dtors[*key] = dtor;
760-#else
761-  if (pthread_key_create(key, dtor) != 0)
762-  {
763-    return thrd_error;
764-  }
765-#endif
766-  return thrd_success;
767-}
768-
769-void tss_delete(tss_t key)
770-{
771-#if defined(_TTHREAD_WIN32_)
772-  struct TinyCThreadTSSData* data = (struct TinyCThreadTSSData*) TlsGetValue (key);
773-  struct TinyCThreadTSSData* prev = NULL;
774-  if (data != NULL)
775-  {
776-    if (data == _tinycthread_tss_head)
777-    {
778-      _tinycthread_tss_head = data->next;
779-    }
780-    else
781-    {
782-      prev = _tinycthread_tss_head;
783-      if (prev != NULL)
784-      {
785-        while (prev->next != data)
786-        {
787-          prev = prev->next;
788-        }
789-      }
790-    }
791-
792-    if (data == _tinycthread_tss_tail)
793-    {
794-      _tinycthread_tss_tail = prev;
795-    }
796-
797-    free (data);
798-  }
799-  _tinycthread_tss_dtors[key] = NULL;
800-  TlsFree(key);
801-#else
802-  pthread_key_delete(key);
803-#endif
804-}
805-
806-void *tss_get(tss_t key)
807-{
808-#if defined(_TTHREAD_WIN32_)
809-  struct TinyCThreadTSSData* data = (struct TinyCThreadTSSData*)TlsGetValue(key);
810-  if (data == NULL)
811-  {
812-    return NULL;
813-  }
814-  return data->value;
815-#else
816-  return pthread_getspecific(key);
817-#endif
818-}
819-
820-int tss_set(tss_t key, void *val)
821-{
822-#if defined(_TTHREAD_WIN32_)
823-  struct TinyCThreadTSSData* data = (struct TinyCThreadTSSData*)TlsGetValue(key);
824-  if (data == NULL)
825-  {
826-    data = (struct TinyCThreadTSSData*)malloc(sizeof(struct TinyCThreadTSSData));
827-    if (data == NULL)
828-    {
829-      return thrd_error;
830-	}
831-
832-    data->value = NULL;
833-    data->key = key;
834-    data->next = NULL;
835-
836-    if (_tinycthread_tss_tail != NULL)
837-    {
838-      _tinycthread_tss_tail->next = data;
839-    }
840-    else
841-    {
842-      _tinycthread_tss_tail = data;
843-    }
844-
845-    if (_tinycthread_tss_head == NULL)
846-    {
847-      _tinycthread_tss_head = data;
848-    }
849-
850-    if (!TlsSetValue(key, data))
851-    {
852-      free (data);
853-	  return thrd_error;
854-    }
855-  }
856-  data->value = val;
857-#else
858-  if (pthread_setspecific(key, val) != 0)
859-  {
860-    return thrd_error;
861-  }
862-#endif
863-  return thrd_success;
864-}
865-
866-#if defined(_TTHREAD_EMULATE_TIMESPEC_GET_)
867-int _tthread_timespec_get(struct timespec *ts, int base)
868-{
869-#if defined(_TTHREAD_WIN32_)
870-  struct _timeb tb;
871-#elif !defined(CLOCK_REALTIME)
872-  struct timeval tv;
873-#endif
874-
875-  if (base != TIME_UTC)
876-  {
877-    return 0;
878-  }
879-
880-#if defined(_TTHREAD_WIN32_)
881-  _ftime_s(&tb);
882-  ts->tv_sec = (time_t)tb.time;
883-  ts->tv_nsec = 1000000L * (long)tb.millitm;
884-#elif defined(CLOCK_REALTIME)
885-  base = (clock_gettime(CLOCK_REALTIME, ts) == 0) ? base : 0;
886-#else
887-  gettimeofday(&tv, NULL);
888-  ts->tv_sec = (time_t)tv.tv_sec;
889-  ts->tv_nsec = 1000L * (long)tv.tv_usec;
890-#endif
891-
892-  return base;
893-}
894-#endif /* _TTHREAD_EMULATE_TIMESPEC_GET_ */
895-
896-#if defined(_TTHREAD_WIN32_)
897-void call_once(once_flag *flag, void (*func)(void))
898-{
899-  /* The idea here is that we use a spin lock (via the
900-     InterlockedCompareExchange function) to restrict access to the
901-     critical section until we have initialized it, then we use the
902-     critical section to block until the callback has completed
903-     execution. */
904-  while (flag->status < 3)
905-  {
906-    switch (flag->status)
907-    {
908-      case 0:
909-        if (InterlockedCompareExchange (&(flag->status), 1, 0) == 0) {
910-          InitializeCriticalSection(&(flag->lock));
911-          EnterCriticalSection(&(flag->lock));
912-          flag->status = 2;
913-          func();
914-          flag->status = 3;
915-          LeaveCriticalSection(&(flag->lock));
916-          return;
917-        }
918-        break;
919-      case 1:
920-        break;
921-      case 2:
922-        EnterCriticalSection(&(flag->lock));
923-        LeaveCriticalSection(&(flag->lock));
924-        break;
925-    }
926-  }
927-}
928-#endif /* defined(_TTHREAD_WIN32_) */
929-
930-#ifdef __cplusplus
931-}
932-#endif
+0, -482
  1@@ -1,482 +0,0 @@
  2-/* -*- mode: c; tab-width: 2; indent-tabs-mode: nil; -*-
  3-Copyright (c) 2012 Marcus Geelnard
  4-Copyright (c) 2013-2016 Evan Nemerson
  5-
  6-This software is provided 'as-is', without any express or implied
  7-warranty. In no event will the authors be held liable for any damages
  8-arising from the use of this software.
  9-
 10-Permission is granted to anyone to use this software for any purpose,
 11-including commercial applications, and to alter it and redistribute it
 12-freely, subject to the following restrictions:
 13-
 14-    1. The origin of this software must not be misrepresented; you must not
 15-    claim that you wrote the original software. If you use this software
 16-    in a product, an acknowledgment in the product documentation would be
 17-    appreciated but is not required.
 18-
 19-    2. Altered source versions must be plainly marked as such, and must not be
 20-    misrepresented as being the original software.
 21-
 22-    3. This notice may not be removed or altered from any source
 23-    distribution.
 24-*/
 25-
 26-#ifndef _TINYCTHREAD_H_
 27-#define _TINYCTHREAD_H_
 28-
 29-#ifdef __cplusplus
 30-extern "C" {
 31-#endif
 32-
 33-/**
 34-* @file
 35-* @mainpage TinyCThread API Reference
 36-*
 37-* @section intro_sec Introduction
 38-* TinyCThread is a minimal, portable implementation of basic threading
 39-* classes for C.
 40-*
 41-* They closely mimic the functionality and naming of the C11 standard, and
 42-* should be easily replaceable with the corresponding standard variants.
 43-*
 44-* @section port_sec Portability
 45-* The Win32 variant uses the native Win32 API for implementing the thread
 46-* classes, while for other systems, the POSIX threads API (pthread) is used.
 47-*
 48-* @section misc_sec Miscellaneous
 49-* The following special keywords are available: #_Thread_local.
 50-*
 51-* For more detailed information, browse the different sections of this
 52-* documentation. A good place to start is:
 53-* tinycthread.h.
 54-*/
 55-
 56-/* Which platform are we on? */
 57-#if !defined(_TTHREAD_PLATFORM_DEFINED_)
 58-  #if defined(_WIN32) || defined(__WIN32__) || defined(__WINDOWS__)
 59-    #define _TTHREAD_WIN32_
 60-  #else
 61-    #define _TTHREAD_POSIX_
 62-  #endif
 63-  #define _TTHREAD_PLATFORM_DEFINED_
 64-#endif
 65-
 66-/* Activate some POSIX functionality (e.g. clock_gettime and recursive mutexes) */
 67-#if defined(_TTHREAD_POSIX_)
 68-  #undef _FEATURES_H
 69-  #if !defined(_GNU_SOURCE)
 70-    #define _GNU_SOURCE
 71-  #endif
 72-  #if !defined(_POSIX_C_SOURCE) || ((_POSIX_C_SOURCE - 0) < 199309L)
 73-    #undef _POSIX_C_SOURCE
 74-    #define _POSIX_C_SOURCE 199309L
 75-  #endif
 76-  #if !defined(_XOPEN_SOURCE) || ((_XOPEN_SOURCE - 0) < 500)
 77-    #undef _XOPEN_SOURCE
 78-    #define _XOPEN_SOURCE 500
 79-  #endif
 80-  #define _XPG6
 81-#endif
 82-
 83-/* Generic includes */
 84-#include <time.h>
 85-
 86-/* Platform specific includes */
 87-#if defined(_TTHREAD_POSIX_)
 88-  #include <pthread.h>
 89-#elif defined(_TTHREAD_WIN32_)
 90-  #ifndef WIN32_LEAN_AND_MEAN
 91-    #define WIN32_LEAN_AND_MEAN
 92-    #define __UNDEF_LEAN_AND_MEAN
 93-  #endif
 94-  #include <windows.h>
 95-  #ifdef __UNDEF_LEAN_AND_MEAN
 96-    #undef WIN32_LEAN_AND_MEAN
 97-    #undef __UNDEF_LEAN_AND_MEAN
 98-  #endif
 99-#endif
100-
101-/* Compiler-specific information */
102-#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L
103-  #define TTHREAD_NORETURN _Noreturn
104-#elif defined(__GNUC__)
105-  #define TTHREAD_NORETURN __attribute__((__noreturn__))
106-#else
107-  #define TTHREAD_NORETURN
108-#endif
109-
110-/* If TIME_UTC is missing, provide it and provide a wrapper for
111-   timespec_get. */
112-#ifndef TIME_UTC
113-#define TIME_UTC 1
114-#define _TTHREAD_EMULATE_TIMESPEC_GET_
115-
116-#if defined(_TTHREAD_WIN32_)
117-struct _tthread_timespec {
118-  time_t tv_sec;
119-  long   tv_nsec;
120-};
121-#define timespec _tthread_timespec
122-#endif
123-
124-int _tthread_timespec_get(struct timespec *ts, int base);
125-#define timespec_get _tthread_timespec_get
126-#endif
127-
128-/** TinyCThread version (major number). */
129-#define TINYCTHREAD_VERSION_MAJOR 1
130-/** TinyCThread version (minor number). */
131-#define TINYCTHREAD_VERSION_MINOR 2
132-/** TinyCThread version (full version). */
133-#define TINYCTHREAD_VERSION (TINYCTHREAD_VERSION_MAJOR * 100 + TINYCTHREAD_VERSION_MINOR)
134-
135-/**
136-* @def _Thread_local
137-* Thread local storage keyword.
138-* A variable that is declared with the @c _Thread_local keyword makes the
139-* value of the variable local to each thread (known as thread-local storage,
140-* or TLS). Example usage:
141-* @code
142-* // This variable is local to each thread.
143-* _Thread_local int variable;
144-* @endcode
145-* @note The @c _Thread_local keyword is a macro that maps to the corresponding
146-* compiler directive (e.g. @c __declspec(thread)).
147-* @note This directive is currently not supported on Mac OS X (it will give
148-* a compiler error), since compile-time TLS is not supported in the Mac OS X
149-* executable format. Also, some older versions of MinGW (before GCC 4.x) do
150-* not support this directive, nor does the Tiny C Compiler.
151-* @hideinitializer
152-*/
153-
154-#if !(defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201102L)) && !defined(_Thread_local)
155- #if defined(__GNUC__) || defined(__INTEL_COMPILER) || defined(__SUNPRO_CC) || defined(__IBMCPP__)
156-  #define _Thread_local __thread
157- #else
158-  #define _Thread_local __declspec(thread)
159- #endif
160-#elif defined(__GNUC__) && defined(__GNUC_MINOR__) && (((__GNUC__ << 8) | __GNUC_MINOR__) < ((4 << 8) | 9))
161- #define _Thread_local __thread
162-#endif
163-
164-/* Macros */
165-#if defined(_TTHREAD_WIN32_)
166-#define TSS_DTOR_ITERATIONS (4)
167-#else
168-#define TSS_DTOR_ITERATIONS PTHREAD_DESTRUCTOR_ITERATIONS
169-#endif
170-
171-/* Function return values */
172-#define thrd_error    0 /**< The requested operation failed */
173-#define thrd_success  1 /**< The requested operation succeeded */
174-#define thrd_timedout 2 /**< The time specified in the call was reached without acquiring the requested resource */
175-#define thrd_busy     3 /**< The requested operation failed because a tesource requested by a test and return function is already in use */
176-#define thrd_nomem    4 /**< The requested operation failed because it was unable to allocate memory */
177-
178-/* Mutex types */
179-#define mtx_plain     0
180-#define mtx_timed     1
181-#define mtx_recursive 2
182-
183-/* Mutex */
184-#if defined(_TTHREAD_WIN32_)
185-typedef struct {
186-  union {
187-    CRITICAL_SECTION cs;      /* Critical section handle (used for non-timed mutexes) */
188-    HANDLE mut;               /* Mutex handle (used for timed mutex) */
189-  } mHandle;                  /* Mutex handle */
190-  int mAlreadyLocked;         /* TRUE if the mutex is already locked */
191-  int mRecursive;             /* TRUE if the mutex is recursive */
192-  int mTimed;                 /* TRUE if the mutex is timed */
193-} mtx_t;
194-#else
195-typedef pthread_mutex_t mtx_t;
196-#endif
197-
198-/** Create a mutex object.
199-* @param mtx A mutex object.
200-* @param type Bit-mask that must have one of the following six values:
201-*   @li @c mtx_plain for a simple non-recursive mutex
202-*   @li @c mtx_timed for a non-recursive mutex that supports timeout
203-*   @li @c mtx_plain | @c mtx_recursive (same as @c mtx_plain, but recursive)
204-*   @li @c mtx_timed | @c mtx_recursive (same as @c mtx_timed, but recursive)
205-* @return @ref thrd_success on success, or @ref thrd_error if the request could
206-* not be honored.
207-*/
208-int mtx_init(mtx_t *mtx, int type);
209-
210-/** Release any resources used by the given mutex.
211-* @param mtx A mutex object.
212-*/
213-void mtx_destroy(mtx_t *mtx);
214-
215-/** Lock the given mutex.
216-* Blocks until the given mutex can be locked. If the mutex is non-recursive, and
217-* the calling thread already has a lock on the mutex, this call will block
218-* forever.
219-* @param mtx A mutex object.
220-* @return @ref thrd_success on success, or @ref thrd_error if the request could
221-* not be honored.
222-*/
223-int mtx_lock(mtx_t *mtx);
224-
225-/** Lock the given mutex, or block until a specific point in time.
226-* Blocks until either the given mutex can be locked, or the specified TIME_UTC
227-* based time.
228-* @param mtx A mutex object.
229-* @param ts A UTC based calendar time
230-* @return @ref The mtx_timedlock function returns thrd_success on success, or
231-* thrd_timedout if the time specified was reached without acquiring the
232-* requested resource, or thrd_error if the request could not be honored.
233-*/
234-int mtx_timedlock(mtx_t *mtx, const struct timespec *ts);
235-
236-/** Try to lock the given mutex.
237-* The specified mutex shall support either test and return or timeout. If the
238-* mutex is already locked, the function returns without blocking.
239-* @param mtx A mutex object.
240-* @return @ref thrd_success on success, or @ref thrd_busy if the resource
241-* requested is already in use, or @ref thrd_error if the request could not be
242-* honored.
243-*/
244-int mtx_trylock(mtx_t *mtx);
245-
246-/** Unlock the given mutex.
247-* @param mtx A mutex object.
248-* @return @ref thrd_success on success, or @ref thrd_error if the request could
249-* not be honored.
250-*/
251-int mtx_unlock(mtx_t *mtx);
252-
253-/* Condition variable */
254-#if defined(_TTHREAD_WIN32_)
255-typedef struct {
256-  HANDLE mEvents[2];                  /* Signal and broadcast event HANDLEs. */
257-  unsigned int mWaitersCount;         /* Count of the number of waiters. */
258-  CRITICAL_SECTION mWaitersCountLock; /* Serialize access to mWaitersCount. */
259-} cnd_t;
260-#else
261-typedef pthread_cond_t cnd_t;
262-#endif
263-
264-/** Create a condition variable object.
265-* @param cond A condition variable object.
266-* @return @ref thrd_success on success, or @ref thrd_error if the request could
267-* not be honored.
268-*/
269-int cnd_init(cnd_t *cond);
270-
271-/** Release any resources used by the given condition variable.
272-* @param cond A condition variable object.
273-*/
274-void cnd_destroy(cnd_t *cond);
275-
276-/** Signal a condition variable.
277-* Unblocks one of the threads that are blocked on the given condition variable
278-* at the time of the call. If no threads are blocked on the condition variable
279-* at the time of the call, the function does nothing and return success.
280-* @param cond A condition variable object.
281-* @return @ref thrd_success on success, or @ref thrd_error if the request could
282-* not be honored.
283-*/
284-int cnd_signal(cnd_t *cond);
285-
286-/** Broadcast a condition variable.
287-* Unblocks all of the threads that are blocked on the given condition variable
288-* at the time of the call. If no threads are blocked on the condition variable
289-* at the time of the call, the function does nothing and return success.
290-* @param cond A condition variable object.
291-* @return @ref thrd_success on success, or @ref thrd_error if the request could
292-* not be honored.
293-*/
294-int cnd_broadcast(cnd_t *cond);
295-
296-/** Wait for a condition variable to become signaled.
297-* The function atomically unlocks the given mutex and endeavors to block until
298-* the given condition variable is signaled by a call to cnd_signal or to
299-* cnd_broadcast. When the calling thread becomes unblocked it locks the mutex
300-* before it returns.
301-* @param cond A condition variable object.
302-* @param mtx A mutex object.
303-* @return @ref thrd_success on success, or @ref thrd_error if the request could
304-* not be honored.
305-*/
306-int cnd_wait(cnd_t *cond, mtx_t *mtx);
307-
308-/** Wait for a condition variable to become signaled.
309-* The function atomically unlocks the given mutex and endeavors to block until
310-* the given condition variable is signaled by a call to cnd_signal or to
311-* cnd_broadcast, or until after the specified time. When the calling thread
312-* becomes unblocked it locks the mutex before it returns.
313-* @param cond A condition variable object.
314-* @param mtx A mutex object.
315-* @param xt A point in time at which the request will time out (absolute time).
316-* @return @ref thrd_success upon success, or @ref thrd_timeout if the time
317-* specified in the call was reached without acquiring the requested resource, or
318-* @ref thrd_error if the request could not be honored.
319-*/
320-int cnd_timedwait(cnd_t *cond, mtx_t *mtx, const struct timespec *ts);
321-
322-/* Thread */
323-#if defined(_TTHREAD_WIN32_)
324-typedef HANDLE thrd_t;
325-#else
326-typedef pthread_t thrd_t;
327-#endif
328-
329-/** Thread start function.
330-* Any thread that is started with the @ref thrd_create() function must be
331-* started through a function of this type.
332-* @param arg The thread argument (the @c arg argument of the corresponding
333-*        @ref thrd_create() call).
334-* @return The thread return value, which can be obtained by another thread
335-* by using the @ref thrd_join() function.
336-*/
337-typedef int (*thrd_start_t)(void *arg);
338-
339-/** Create a new thread.
340-* @param thr Identifier of the newly created thread.
341-* @param func A function pointer to the function that will be executed in
342-*        the new thread.
343-* @param arg An argument to the thread function.
344-* @return @ref thrd_success on success, or @ref thrd_nomem if no memory could
345-* be allocated for the thread requested, or @ref thrd_error if the request
346-* could not be honored.
347-* @note A thread’s identifier may be reused for a different thread once the
348-* original thread has exited and either been detached or joined to another
349-* thread.
350-*/
351-int thrd_create(thrd_t *thr, thrd_start_t func, void *arg);
352-
353-/** Identify the calling thread.
354-* @return The identifier of the calling thread.
355-*/
356-thrd_t thrd_current(void);
357-
358-/** Dispose of any resources allocated to the thread when that thread exits.
359- * @return thrd_success, or thrd_error on error
360-*/
361-int thrd_detach(thrd_t thr);
362-
363-/** Compare two thread identifiers.
364-* The function determines if two thread identifiers refer to the same thread.
365-* @return Zero if the two thread identifiers refer to different threads.
366-* Otherwise a nonzero value is returned.
367-*/
368-int thrd_equal(thrd_t thr0, thrd_t thr1);
369-
370-/** Terminate execution of the calling thread.
371-* @param res Result code of the calling thread.
372-*/
373-TTHREAD_NORETURN void thrd_exit(int res);
374-
375-/** Wait for a thread to terminate.
376-* The function joins the given thread with the current thread by blocking
377-* until the other thread has terminated.
378-* @param thr The thread to join with.
379-* @param res If this pointer is not NULL, the function will store the result
380-*        code of the given thread in the integer pointed to by @c res.
381-* @return @ref thrd_success on success, or @ref thrd_error if the request could
382-* not be honored.
383-*/
384-int thrd_join(thrd_t thr, int *res);
385-
386-/** Put the calling thread to sleep.
387-* Suspend execution of the calling thread.
388-* @param duration  Interval to sleep for
389-* @param remaining If non-NULL, this parameter will hold the remaining
390-*                  time until time_point upon return. This will
391-*                  typically be zero, but if the thread was woken up
392-*                  by a signal that is not ignored before duration was
393-*                  reached @c remaining will hold a positive time.
394-* @return 0 (zero) on successful sleep, -1 if an interrupt occurred,
395-*         or a negative value if the operation fails.
396-*/
397-int thrd_sleep(const struct timespec *duration, struct timespec *remaining);
398-
399-/** Yield execution to another thread.
400-* Permit other threads to run, even if the current thread would ordinarily
401-* continue to run.
402-*/
403-void thrd_yield(void);
404-
405-/* Thread local storage */
406-#if defined(_TTHREAD_WIN32_)
407-typedef DWORD tss_t;
408-#else
409-typedef pthread_key_t tss_t;
410-#endif
411-
412-/** Destructor function for a thread-specific storage.
413-* @param val The value of the destructed thread-specific storage.
414-*/
415-typedef void (*tss_dtor_t)(void *val);
416-
417-/** Create a thread-specific storage.
418-* @param key The unique key identifier that will be set if the function is
419-*        successful.
420-* @param dtor Destructor function. This can be NULL.
421-* @return @ref thrd_success on success, or @ref thrd_error if the request could
422-* not be honored.
423-* @note On Windows, the @c dtor will definitely be called when
424-* appropriate for threads created with @ref thrd_create.  It will be
425-* called for other threads in most cases, the possible exception being
426-* for DLLs loaded with LoadLibraryEx.  In order to be certain, you
427-* should use @ref thrd_create whenever possible.
428-*/
429-int tss_create(tss_t *key, tss_dtor_t dtor);
430-
431-/** Delete a thread-specific storage.
432-* The function releases any resources used by the given thread-specific
433-* storage.
434-* @param key The key that shall be deleted.
435-*/
436-void tss_delete(tss_t key);
437-
438-/** Get the value for a thread-specific storage.
439-* @param key The thread-specific storage identifier.
440-* @return The value for the current thread held in the given thread-specific
441-* storage.
442-*/
443-void *tss_get(tss_t key);
444-
445-/** Set the value for a thread-specific storage.
446-* @param key The thread-specific storage identifier.
447-* @param val The value of the thread-specific storage to set for the current
448-*        thread.
449-* @return @ref thrd_success on success, or @ref thrd_error if the request could
450-* not be honored.
451-*/
452-int tss_set(tss_t key, void *val);
453-
454-#if defined(_TTHREAD_WIN32_)
455-  typedef struct {
456-    LONG volatile status;
457-    CRITICAL_SECTION lock;
458-  } once_flag;
459-  #define ONCE_FLAG_INIT {0,}
460-#else
461-  typedef pthread_once_t once_flag;
462-  #define ONCE_FLAG_INIT PTHREAD_ONCE_INIT
463-#endif
464-
465-/** Invoke a callback exactly once
466- * @param flag Flag used to ensure the callback is invoked exactly
467- *        once.
468- * @param func Callback to invoke.
469- */
470-#if defined(_TTHREAD_WIN32_)
471-  void call_once(once_flag *flag, void (*func)(void));
472-#else
473-  static inline void call_once(once_flag *flag, void (*func)(void))
474-  {
475-    (void)pthread_once(flag, func);
476-  }
477-#endif
478-
479-#ifdef __cplusplus
480-}
481-#endif
482-
483-#endif /* _TINYTHREAD_H_ */
+10, -10
 1@@ -3,6 +3,7 @@
 2 #include <limits.h>
 3 #include <stddef.h>
 4 #include <stdint.h>
 5+#include <pthread.h>
 6 #include <stdio.h>
 7 #include <stdlib.h>
 8 #include <string.h>
 9@@ -10,7 +11,6 @@
10 #include <sys/stat.h>
11 #include <sys/types.h>
12 #include <time.h>
13-#include <tinycthread.h>
14 #include <unistd.h>
15 
16 #include "config.h"
17@@ -51,7 +51,7 @@ static int stat_item(const struct item* it, struct stat* st);
18 static int stream_file(int c, const struct item* it, const char* hdr, int head_only);
19 
20 extern struct library lib;
21-extern mtx_t lib_lock;
22+extern pthread_mutex_t lib_lock;
23 
24 /**
25  * @brief Sleep for configured auth delay
26@@ -213,7 +213,7 @@ static int item_path_for_id(char out[4096], uint64_t id, const struct user* u)
27 
28 	out[0] = '\0';
29 
30-	mtx_lock(&lib_lock);
31+	(void)pthread_mutex_lock(&lib_lock);
32 
33 	const struct item* it = find_item(id);
34 	if (!it) {
35@@ -234,7 +234,7 @@ static int item_path_for_id(char out[4096], uint64_t id, const struct user* u)
36 	ret = 0;
37 
38 out:
39-	mtx_unlock(&lib_lock);
40+	(void)pthread_mutex_unlock(&lib_lock);
41 	return ret; /* 0 ok, 1 not found, -1 error */
42 }
43 
44@@ -683,7 +683,7 @@ static int route_library(int c, const char* hdr, const struct user* u, int head_
45 	struct library view;
46 
47 	LOG(verbose_log, "HTTP", "Route              /library");
48-	mtx_lock(&lib_lock);
49+	(void)pthread_mutex_lock(&lib_lock);
50 	memset(&view, 0, sizeof(view));
51 
52 	if (!u) {
53@@ -695,7 +695,7 @@ static int route_library(int c, const char* hdr, const struct user* u, int head_
54 		if (lib.len > 0) {
55 			view.items = calloc(lib.len, sizeof(*view.items));
56 			if (!view.items) {
57-				mtx_unlock(&lib_lock);
58+				(void)pthread_mutex_unlock(&lib_lock);
59 				reply(c, hdr, &(struct response){ HTTP_500, HTTP_TEXT, NULL, "Server Error\n", sizeof("Server Error\n") - 1, 1, 0 });
60 				return -1;
61 			}
62@@ -713,13 +713,13 @@ static int route_library(int c, const char* hdr, const struct user* u, int head_
63 		if (u)
64 			free(view.items);
65 
66-		mtx_unlock(&lib_lock);
67+		(void)pthread_mutex_unlock(&lib_lock);
68 		LOG(verbose_log, "JSON", "Encode     FAILED");
69 		reply(c, hdr, &(struct response){ HTTP_500, HTTP_TEXT, NULL, "JSON Encode Failed\n", sizeof("JSON Encode Failed\n") - 1, 1, 0 });
70 		return -1;
71 	}
72 
73-	mtx_unlock(&lib_lock);
74+	(void)pthread_mutex_unlock(&lib_lock);
75 	LOG(verbose_log, "JSON", "Encoded bytes      %zu bytes", j.len);
76 	reply(c, hdr, &(struct response){ HTTP_200, HTTP_JSON, NULL, j.buf, j.len, !head_only, 0 });
77 	json_free(&j);
78@@ -785,12 +785,12 @@ static int route_rescan(int c, const char* hdr, const struct user* u)
79 	LOG(true, "SCAN", "Rescan requested   %s", u->name);
80 	clock_gettime(CLOCK_MONOTONIC, &t0);
81 
82-	mtx_lock(&lib_lock);
83+	(void)pthread_mutex_lock(&lib_lock);
84 	before = lib.len;
85 	LOG(verbose_log, "SCAN", "Rescan begin       %s (%zu items)", media_dir, before);
86 	int ok = scan_library_rescan(&lib, media_dir);
87 	after = lib.len;
88-	mtx_unlock(&lib_lock);
89+	(void)pthread_mutex_unlock(&lib_lock);
90 
91 	clock_gettime(CLOCK_MONOTONIC, &t1);
92 	long ms = (t1.tv_sec - t0.tv_sec) * 1000L + (t1.tv_nsec - t0.tv_nsec) / 1000000L;
+19, -21
  1@@ -26,7 +26,7 @@
  2 
  3 #include <arpa/inet.h>
  4 #include <netinet/in.h>
  5-#include <tinycthread.h>
  6+#include <pthread.h>
  7 
  8 #include "config.h"
  9 #include "http.h"
 10@@ -39,7 +39,7 @@
 11 #endif /* GIT_VER */
 12 
 13 static void apply_rlimits(void);
 14-static int client_thread(void* arg);
 15+static void* client_thread(void* arg);
 16 static void fd_set_cloexec(int fd);
 17 static void sock_set_timeouts(int fd);
 18 static void release_slot(void);
 19@@ -51,8 +51,8 @@ void setup(void);
 20 
 21 static int sock;
 22 struct library lib;
 23-mtx_t lib_lock;
 24-static mtx_t slots_lock;
 25+pthread_mutex_t lib_lock;
 26+static pthread_mutex_t slots_lock;
 27 static int slots_available;
 28 
 29 /**
 30@@ -75,10 +75,8 @@ static void apply_rlimits(void)
 31  * @brief Handle a single accepted client connection
 32  *
 33  * @param arg Client socket cast through void*
 34- *
 35- * @return 0=Success
 36  */
 37-static int client_thread(void* arg)
 38+static void* client_thread(void* arg)
 39 {
 40 	int c = (int)(intptr_t)arg;
 41 
 42@@ -88,7 +86,7 @@ static int client_thread(void* arg)
 43 	close(c);
 44 
 45 	release_slot();
 46-	return 0;
 47+	return NULL;
 48 }
 49 
 50 /**
 51@@ -123,13 +121,13 @@ static void sock_set_timeouts(int fd)
 52  */
 53 static void release_slot(void)
 54 {
 55-	if (mtx_lock(&slots_lock) != thrd_success)
 56+	if (pthread_mutex_lock(&slots_lock) != 0)
 57 		return;
 58 
 59 	if (slots_available < max_clients)
 60 		slots_available++;
 61 
 62-	(void)mtx_unlock(&slots_lock);
 63+	(void)pthread_mutex_unlock(&slots_lock);
 64 }
 65 
 66 /**
 67@@ -141,7 +139,7 @@ static int try_acquire_slot(void)
 68 {
 69 	int ok = 0;
 70 
 71-	if (mtx_lock(&slots_lock) != thrd_success)
 72+	if (pthread_mutex_lock(&slots_lock) != 0)
 73 		return -1;
 74 
 75 	if (slots_available > 0) {
 76@@ -149,7 +147,7 @@ static int try_acquire_slot(void)
 77 		ok = 1;
 78 	}
 79 
 80-	(void)mtx_unlock(&slots_lock);
 81+	(void)pthread_mutex_unlock(&slots_lock);
 82 	return ok;
 83 }
 84 
 85@@ -192,16 +190,16 @@ void run(void)
 86 		}
 87 
 88 		LOG(verbose_log, "CORE", "Connection         Accepted");
 89-		thrd_t t;
 90-		int err = thrd_create(&t, client_thread, (void*)(intptr_t)c);
 91-		if (err != thrd_success) {
 92-			LOG(true, "CORE", "thrd_create FAILED  %d", err);
 93+		pthread_t t;
 94+		int err = pthread_create(&t, NULL, client_thread, (void*)(intptr_t)c);
 95+		if (err != 0) {
 96+			LOG(true, "CORE", "pthread_create FAILED  %d", err);
 97 			close(c);
 98 			release_slot();
 99 			continue;
100 		}
101 
102-		(void)thrd_detach(t);
103+		(void)pthread_detach(t);
104 	}
105 }
106 
107@@ -212,11 +210,11 @@ void setup(void)
108 	config_load();
109 	apply_rlimits();
110 
111-	if (mtx_init(&lib_lock, mtx_plain) != thrd_success)
112-		die("mtx_init", EXIT_FAILURE);
113+	if (pthread_mutex_init(&lib_lock, NULL) != 0)
114+		die("pthread_mutex_init", EXIT_FAILURE);
115 
116-	if (mtx_init(&slots_lock, mtx_plain) != thrd_success)
117-		die("mtx_init", EXIT_FAILURE);
118+	if (pthread_mutex_init(&slots_lock, NULL) != 0)
119+		die("pthread_mutex_init", EXIT_FAILURE);
120 	slots_available = max_clients;
121 
122 	int ret = 1;