]> wimlib.net Git - wimlib/blob - src/threads.c
mount_image.c: add fallback definitions of RENAME_* constants
[wimlib] / src / threads.c
1 /*
2  * threads.c - Thread, mutex, and condition variable support.  Wraps around
3  *             pthreads or Windows native threads.
4  */
5
6 /*
7  * Copyright 2016-2023 Eric Biggers
8  *
9  * This file is free software; you can redistribute it and/or modify it under
10  * the terms of the GNU Lesser General Public License as published by the Free
11  * Software Foundation; either version 3 of the License, or (at your option) any
12  * later version.
13  *
14  * This file is distributed in the hope that it will be useful, but WITHOUT
15  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
16  * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
17  * details.
18  *
19  * You should have received a copy of the GNU Lesser General Public License
20  * along with this file; if not, see https://www.gnu.org/licenses/.
21  */
22
23 #ifdef HAVE_CONFIG_H
24 #  include "config.h"
25 #endif
26
27 #ifdef _WIN32
28 #  include "wimlib/win32_common.h"
29 #else
30 #  include <errno.h>
31 #  include <pthread.h>
32 #endif
33
34 #include "wimlib/assert.h"
35 #include "wimlib/error.h"
36 #include "wimlib/threads.h"
37 #include "wimlib/util.h"
38
39 #ifdef _WIN32
40
41 static WINAPI DWORD
42 win32_thrproc(LPVOID lpParameter)
43 {
44         struct thread *t = (struct thread *)lpParameter;
45
46         (*t->thrproc)(t->arg);
47         return 0;
48 }
49
50 bool thread_create(struct thread *t, void *(*thrproc)(void *), void *arg)
51 {
52         HANDLE h;
53
54         t->thrproc = thrproc;
55         t->arg = arg;
56         h = CreateThread(NULL, 0, win32_thrproc, (LPVOID)t, 0, NULL);
57         if (h == NULL) {
58                 win32_error(GetLastError(), L"Failed to create thread");
59                 return false;
60         }
61         t->win32_thread = (void *)h;
62         return true;
63 }
64
65 void thread_join(struct thread *t)
66 {
67         DWORD res = WaitForSingleObject((HANDLE)t->win32_thread, INFINITE);
68
69         wimlib_assert(res == WAIT_OBJECT_0);
70 }
71
72 bool mutex_init(struct mutex *m)
73 {
74         CRITICAL_SECTION *crit = MALLOC(sizeof(*crit));
75
76         if (!crit)
77                 return false;
78         InitializeCriticalSection(crit);
79         m->win32_crit = crit;
80         return true;
81 }
82
83 void mutex_destroy(struct mutex *m)
84 {
85         DeleteCriticalSection(m->win32_crit);
86         FREE(m->win32_crit);
87         m->win32_crit = NULL;
88 }
89
90 void mutex_lock(struct mutex *m)
91 {
92         CRITICAL_SECTION *crit = m->win32_crit;
93
94         if (unlikely(!crit)) {
95                 CRITICAL_SECTION *old;
96
97                 crit = MALLOC(sizeof(*crit));
98                 wimlib_assert(crit != NULL);
99                 InitializeCriticalSection(crit);
100                 old = InterlockedCompareExchangePointer(&m->win32_crit, crit,
101                                                         NULL);
102                 if (old) {
103                         DeleteCriticalSection(crit);
104                         FREE(crit);
105                         crit = old;
106                 }
107         }
108         EnterCriticalSection(crit);
109 }
110
111 void mutex_unlock(struct mutex *m)
112 {
113         LeaveCriticalSection(m->win32_crit);
114 }
115
116 bool condvar_init(struct condvar *c)
117 {
118         CONDITION_VARIABLE *cond = MALLOC(sizeof(*cond));
119
120         if (!cond)
121                 return false;
122         InitializeConditionVariable(cond);
123         c->win32_cond = cond;
124         return true;
125 }
126
127 void condvar_destroy(struct condvar *c)
128 {
129         FREE(c->win32_cond);
130         c->win32_cond = NULL;
131 }
132
133 void condvar_wait(struct condvar *c, struct mutex *m)
134 {
135         BOOL ok = SleepConditionVariableCS(c->win32_cond, m->win32_crit,
136                                            INFINITE);
137         wimlib_assert(ok);
138 }
139
140 void condvar_signal(struct condvar *c)
141 {
142         WakeConditionVariable(c->win32_cond);
143 }
144
145 void condvar_broadcast(struct condvar *c)
146 {
147         WakeAllConditionVariable(c->win32_cond);
148 }
149
150 #else /* _WIN32 */
151
152 bool thread_create(struct thread *t, void *(*thrproc)(void *), void *arg)
153 {
154         int err = pthread_create(&t->pthread, NULL, thrproc, arg);
155
156         if (err) {
157                 errno = err;
158                 ERROR_WITH_ERRNO("Failed to create thread");
159                 return false;
160         }
161         return true;
162 }
163
164 void thread_join(struct thread *t)
165 {
166         int err = pthread_join(t->pthread, NULL);
167
168         wimlib_assert(err == 0);
169 }
170
171 bool mutex_init(struct mutex *m)
172 {
173         int err = pthread_mutex_init(&m->pthread_mutex, NULL);
174
175         if (err) {
176                 errno = err;
177                 ERROR_WITH_ERRNO("Failed to initialize mutex");
178                 return false;
179         }
180         return true;
181 }
182
183 void mutex_destroy(struct mutex *m)
184 {
185         int err = pthread_mutex_destroy(&m->pthread_mutex);
186
187         wimlib_assert(err == 0);
188 }
189
190 void mutex_lock(struct mutex *m)
191 {
192         int err = pthread_mutex_lock(&m->pthread_mutex);
193
194         wimlib_assert(err == 0);
195 }
196
197 void mutex_unlock(struct mutex *m)
198 {
199         int err = pthread_mutex_unlock(&m->pthread_mutex);
200
201         wimlib_assert(err == 0);
202 }
203
204 bool condvar_init(struct condvar *c)
205 {
206         int err = pthread_cond_init(&c->pthread_cond, NULL);
207
208         if (err) {
209                 errno = err;
210                 ERROR_WITH_ERRNO("Failed to initialize condition variable");
211                 return false;
212         }
213         return true;
214 }
215
216 void condvar_destroy(struct condvar *c)
217 {
218         int err = pthread_cond_destroy(&c->pthread_cond);
219
220         wimlib_assert(err == 0);
221 }
222
223 void condvar_wait(struct condvar *c, struct mutex *m)
224 {
225         int err = pthread_cond_wait(&c->pthread_cond, &m->pthread_mutex);
226
227         wimlib_assert(err == 0);
228 }
229
230 void condvar_signal(struct condvar *c)
231 {
232         int err = pthread_cond_signal(&c->pthread_cond);
233
234         wimlib_assert(err == 0);
235 }
236
237 void condvar_broadcast(struct condvar *c)
238 {
239         int err = pthread_cond_broadcast(&c->pthread_cond);
240
241         wimlib_assert(err == 0);
242 }
243
244 #endif /* !_WIN32 */