xref: /netbsd-src/external/bsd/zstd/dist/lib/common/threading.c (revision 3117ece4fc4a4ca4489ba793710b60b0d26bab6c)
1*3117ece4Schristos /**
2*3117ece4Schristos  * Copyright (c) 2016 Tino Reichardt
3*3117ece4Schristos  * All rights reserved.
4*3117ece4Schristos  *
5*3117ece4Schristos  * You can contact the author at:
6*3117ece4Schristos  * - zstdmt source repository: https://github.com/mcmilk/zstdmt
7*3117ece4Schristos  *
8*3117ece4Schristos  * This source code is licensed under both the BSD-style license (found in the
9*3117ece4Schristos  * LICENSE file in the root directory of this source tree) and the GPLv2 (found
10*3117ece4Schristos  * in the COPYING file in the root directory of this source tree).
11*3117ece4Schristos  * You may select, at your option, one of the above-listed licenses.
12*3117ece4Schristos  */
13*3117ece4Schristos 
14*3117ece4Schristos /**
15*3117ece4Schristos  * This file will hold wrapper for systems, which do not support pthreads
16*3117ece4Schristos  */
17*3117ece4Schristos 
18*3117ece4Schristos #include "threading.h"
19*3117ece4Schristos 
20*3117ece4Schristos /* create fake symbol to avoid empty translation unit warning */
21*3117ece4Schristos int g_ZSTD_threading_useless_symbol;
22*3117ece4Schristos 
23*3117ece4Schristos #if defined(ZSTD_MULTITHREAD) && defined(_WIN32)
24*3117ece4Schristos 
25*3117ece4Schristos /**
26*3117ece4Schristos  * Windows minimalist Pthread Wrapper
27*3117ece4Schristos  */
28*3117ece4Schristos 
29*3117ece4Schristos 
30*3117ece4Schristos /* ===  Dependencies  === */
31*3117ece4Schristos #include <process.h>
32*3117ece4Schristos #include <errno.h>
33*3117ece4Schristos 
34*3117ece4Schristos 
35*3117ece4Schristos /* ===  Implementation  === */
36*3117ece4Schristos 
37*3117ece4Schristos typedef struct {
38*3117ece4Schristos     void* (*start_routine)(void*);
39*3117ece4Schristos     void* arg;
40*3117ece4Schristos     int initialized;
41*3117ece4Schristos     ZSTD_pthread_cond_t initialized_cond;
42*3117ece4Schristos     ZSTD_pthread_mutex_t initialized_mutex;
43*3117ece4Schristos } ZSTD_thread_params_t;
44*3117ece4Schristos 
45*3117ece4Schristos static unsigned __stdcall worker(void *arg)
46*3117ece4Schristos {
47*3117ece4Schristos     void* (*start_routine)(void*);
48*3117ece4Schristos     void* thread_arg;
49*3117ece4Schristos 
50*3117ece4Schristos     /* Initialized thread_arg and start_routine and signal main thread that we don't need it
51*3117ece4Schristos      * to wait any longer.
52*3117ece4Schristos      */
53*3117ece4Schristos     {
54*3117ece4Schristos         ZSTD_thread_params_t*  thread_param = (ZSTD_thread_params_t*)arg;
55*3117ece4Schristos         thread_arg = thread_param->arg;
56*3117ece4Schristos         start_routine = thread_param->start_routine;
57*3117ece4Schristos 
58*3117ece4Schristos         /* Signal main thread that we are running and do not depend on its memory anymore */
59*3117ece4Schristos         ZSTD_pthread_mutex_lock(&thread_param->initialized_mutex);
60*3117ece4Schristos         thread_param->initialized = 1;
61*3117ece4Schristos         ZSTD_pthread_cond_signal(&thread_param->initialized_cond);
62*3117ece4Schristos         ZSTD_pthread_mutex_unlock(&thread_param->initialized_mutex);
63*3117ece4Schristos     }
64*3117ece4Schristos 
65*3117ece4Schristos     start_routine(thread_arg);
66*3117ece4Schristos 
67*3117ece4Schristos     return 0;
68*3117ece4Schristos }
69*3117ece4Schristos 
70*3117ece4Schristos int ZSTD_pthread_create(ZSTD_pthread_t* thread, const void* unused,
71*3117ece4Schristos             void* (*start_routine) (void*), void* arg)
72*3117ece4Schristos {
73*3117ece4Schristos     ZSTD_thread_params_t thread_param;
74*3117ece4Schristos     (void)unused;
75*3117ece4Schristos 
76*3117ece4Schristos     if (thread==NULL) return -1;
77*3117ece4Schristos     *thread = NULL;
78*3117ece4Schristos 
79*3117ece4Schristos     thread_param.start_routine = start_routine;
80*3117ece4Schristos     thread_param.arg = arg;
81*3117ece4Schristos     thread_param.initialized = 0;
82*3117ece4Schristos 
83*3117ece4Schristos     /* Setup thread initialization synchronization */
84*3117ece4Schristos     if(ZSTD_pthread_cond_init(&thread_param.initialized_cond, NULL)) {
85*3117ece4Schristos         /* Should never happen on Windows */
86*3117ece4Schristos         return -1;
87*3117ece4Schristos     }
88*3117ece4Schristos     if(ZSTD_pthread_mutex_init(&thread_param.initialized_mutex, NULL)) {
89*3117ece4Schristos         /* Should never happen on Windows */
90*3117ece4Schristos         ZSTD_pthread_cond_destroy(&thread_param.initialized_cond);
91*3117ece4Schristos         return -1;
92*3117ece4Schristos     }
93*3117ece4Schristos 
94*3117ece4Schristos     /* Spawn thread */
95*3117ece4Schristos     *thread = (HANDLE)_beginthreadex(NULL, 0, worker, &thread_param, 0, NULL);
96*3117ece4Schristos     if (*thread==NULL) {
97*3117ece4Schristos         ZSTD_pthread_mutex_destroy(&thread_param.initialized_mutex);
98*3117ece4Schristos         ZSTD_pthread_cond_destroy(&thread_param.initialized_cond);
99*3117ece4Schristos         return errno;
100*3117ece4Schristos     }
101*3117ece4Schristos 
102*3117ece4Schristos     /* Wait for thread to be initialized */
103*3117ece4Schristos     ZSTD_pthread_mutex_lock(&thread_param.initialized_mutex);
104*3117ece4Schristos     while(!thread_param.initialized) {
105*3117ece4Schristos         ZSTD_pthread_cond_wait(&thread_param.initialized_cond, &thread_param.initialized_mutex);
106*3117ece4Schristos     }
107*3117ece4Schristos     ZSTD_pthread_mutex_unlock(&thread_param.initialized_mutex);
108*3117ece4Schristos     ZSTD_pthread_mutex_destroy(&thread_param.initialized_mutex);
109*3117ece4Schristos     ZSTD_pthread_cond_destroy(&thread_param.initialized_cond);
110*3117ece4Schristos 
111*3117ece4Schristos     return 0;
112*3117ece4Schristos }
113*3117ece4Schristos 
114*3117ece4Schristos int ZSTD_pthread_join(ZSTD_pthread_t thread)
115*3117ece4Schristos {
116*3117ece4Schristos     DWORD result;
117*3117ece4Schristos 
118*3117ece4Schristos     if (!thread) return 0;
119*3117ece4Schristos 
120*3117ece4Schristos     result = WaitForSingleObject(thread, INFINITE);
121*3117ece4Schristos     CloseHandle(thread);
122*3117ece4Schristos 
123*3117ece4Schristos     switch (result) {
124*3117ece4Schristos     case WAIT_OBJECT_0:
125*3117ece4Schristos         return 0;
126*3117ece4Schristos     case WAIT_ABANDONED:
127*3117ece4Schristos         return EINVAL;
128*3117ece4Schristos     default:
129*3117ece4Schristos         return GetLastError();
130*3117ece4Schristos     }
131*3117ece4Schristos }
132*3117ece4Schristos 
133*3117ece4Schristos #endif   /* ZSTD_MULTITHREAD */
134*3117ece4Schristos 
135*3117ece4Schristos #if defined(ZSTD_MULTITHREAD) && DEBUGLEVEL >= 1 && !defined(_WIN32)
136*3117ece4Schristos 
137*3117ece4Schristos #define ZSTD_DEPS_NEED_MALLOC
138*3117ece4Schristos #include "zstd_deps.h"
139*3117ece4Schristos 
140*3117ece4Schristos int ZSTD_pthread_mutex_init(ZSTD_pthread_mutex_t* mutex, pthread_mutexattr_t const* attr)
141*3117ece4Schristos {
142*3117ece4Schristos     assert(mutex != NULL);
143*3117ece4Schristos     *mutex = (pthread_mutex_t*)ZSTD_malloc(sizeof(pthread_mutex_t));
144*3117ece4Schristos     if (!*mutex)
145*3117ece4Schristos         return 1;
146*3117ece4Schristos     return pthread_mutex_init(*mutex, attr);
147*3117ece4Schristos }
148*3117ece4Schristos 
149*3117ece4Schristos int ZSTD_pthread_mutex_destroy(ZSTD_pthread_mutex_t* mutex)
150*3117ece4Schristos {
151*3117ece4Schristos     assert(mutex != NULL);
152*3117ece4Schristos     if (!*mutex)
153*3117ece4Schristos         return 0;
154*3117ece4Schristos     {
155*3117ece4Schristos         int const ret = pthread_mutex_destroy(*mutex);
156*3117ece4Schristos         ZSTD_free(*mutex);
157*3117ece4Schristos         return ret;
158*3117ece4Schristos     }
159*3117ece4Schristos }
160*3117ece4Schristos 
161*3117ece4Schristos int ZSTD_pthread_cond_init(ZSTD_pthread_cond_t* cond, pthread_condattr_t const* attr)
162*3117ece4Schristos {
163*3117ece4Schristos     assert(cond != NULL);
164*3117ece4Schristos     *cond = (pthread_cond_t*)ZSTD_malloc(sizeof(pthread_cond_t));
165*3117ece4Schristos     if (!*cond)
166*3117ece4Schristos         return 1;
167*3117ece4Schristos     return pthread_cond_init(*cond, attr);
168*3117ece4Schristos }
169*3117ece4Schristos 
170*3117ece4Schristos int ZSTD_pthread_cond_destroy(ZSTD_pthread_cond_t* cond)
171*3117ece4Schristos {
172*3117ece4Schristos     assert(cond != NULL);
173*3117ece4Schristos     if (!*cond)
174*3117ece4Schristos         return 0;
175*3117ece4Schristos     {
176*3117ece4Schristos         int const ret = pthread_cond_destroy(*cond);
177*3117ece4Schristos         ZSTD_free(*cond);
178*3117ece4Schristos         return ret;
179*3117ece4Schristos     }
180*3117ece4Schristos }
181*3117ece4Schristos 
182*3117ece4Schristos #endif
183