commit 86d99b5
uint
·
2026-05-04 10:08:50 +0000 UTC
parent 2cde702
revert back to pthread from tinycthread
6 files changed,
+38,
-1468
M
Makefile
+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(¤t_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;