1 /*
2 * virthread.c: basic thread synchronization primitives
3 *
4 * Copyright (C) 2009-2010, 2014 Red Hat, Inc.
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library. If not, see
18 * <http://www.gnu.org/licenses/>.
19 *
20 */
21
22 #include <config.h>
23
24 #include "virthread.h"
25
26 #ifdef __FreeBSD__
27 # include <pthread_np.h>
28 #endif
29
30 #include <unistd.h>
31 #include <inttypes.h>
32 #if WITH_SYS_SYSCALL_H
33 # include <sys/syscall.h>
34 #endif
35
36 #include "viralloc.h"
37 #include "virthreadjob.h"
38
39
virOnce(virOnceControl * once,virOnceFunc init)40 int virOnce(virOnceControl *once, virOnceFunc init)
41 {
42 int ret;
43
44 ret = pthread_once(&once->once, init);
45 if (ret != 0) {
46 errno = ret;
47 return -1;
48 }
49
50 return 0;
51 }
52
53
virMutexInit(virMutex * m)54 int virMutexInit(virMutex *m)
55 {
56 int ret;
57 pthread_mutexattr_t attr;
58 pthread_mutexattr_init(&attr);
59 pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_NORMAL);
60 ret = pthread_mutex_init(&m->lock, &attr);
61 pthread_mutexattr_destroy(&attr);
62 if (ret != 0) {
63 errno = ret;
64 return -1;
65 }
66 return 0;
67 }
68
virMutexInitRecursive(virMutex * m)69 int virMutexInitRecursive(virMutex *m)
70 {
71 int ret;
72 pthread_mutexattr_t attr;
73 pthread_mutexattr_init(&attr);
74 pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
75 ret = pthread_mutex_init(&m->lock, &attr);
76 pthread_mutexattr_destroy(&attr);
77 if (ret != 0) {
78 errno = ret;
79 return -1;
80 }
81 return 0;
82 }
83
virMutexDestroy(virMutex * m)84 void virMutexDestroy(virMutex *m)
85 {
86 pthread_mutex_destroy(&m->lock);
87 }
88
virMutexLock(virMutex * m)89 void virMutexLock(virMutex *m)
90 {
91 pthread_mutex_lock(&m->lock);
92 }
93
virMutexUnlock(virMutex * m)94 void virMutexUnlock(virMutex *m)
95 {
96 pthread_mutex_unlock(&m->lock);
97 }
98
99
virRWLockInit(virRWLock * m)100 int virRWLockInit(virRWLock *m)
101 {
102 int ret;
103 ret = pthread_rwlock_init(&m->lock, NULL);
104 if (ret != 0) {
105 errno = ret;
106 return -1;
107 }
108 return 0;
109 }
110
virRWLockDestroy(virRWLock * m)111 void virRWLockDestroy(virRWLock *m)
112 {
113 pthread_rwlock_destroy(&m->lock);
114 }
115
116
virRWLockRead(virRWLock * m)117 void virRWLockRead(virRWLock *m)
118 {
119 pthread_rwlock_rdlock(&m->lock);
120 }
121
virRWLockWrite(virRWLock * m)122 void virRWLockWrite(virRWLock *m)
123 {
124 pthread_rwlock_wrlock(&m->lock);
125 }
126
127
virRWLockUnlock(virRWLock * m)128 void virRWLockUnlock(virRWLock *m)
129 {
130 pthread_rwlock_unlock(&m->lock);
131 }
132
virCondInit(virCond * c)133 int virCondInit(virCond *c)
134 {
135 int ret;
136 if ((ret = pthread_cond_init(&c->cond, NULL)) != 0) {
137 errno = ret;
138 return -1;
139 }
140 return 0;
141 }
142
virCondDestroy(virCond * c)143 int virCondDestroy(virCond *c)
144 {
145 int ret;
146 if ((ret = pthread_cond_destroy(&c->cond)) != 0) {
147 errno = ret;
148 return -1;
149 }
150 return 0;
151 }
152
virCondWait(virCond * c,virMutex * m)153 int virCondWait(virCond *c, virMutex *m)
154 {
155 int ret;
156 if ((ret = pthread_cond_wait(&c->cond, &m->lock)) != 0) {
157 errno = ret;
158 return -1;
159 }
160 return 0;
161 }
162
virCondWaitUntil(virCond * c,virMutex * m,unsigned long long whenms)163 int virCondWaitUntil(virCond *c, virMutex *m, unsigned long long whenms)
164 {
165 int ret;
166 struct timespec ts;
167
168 ts.tv_sec = whenms / 1000;
169 ts.tv_nsec = (whenms % 1000) * 1000000;
170
171 if ((ret = pthread_cond_timedwait(&c->cond, &m->lock, &ts)) != 0) {
172 errno = ret;
173 return -1;
174 }
175 return 0;
176 }
177
virCondSignal(virCond * c)178 void virCondSignal(virCond *c)
179 {
180 pthread_cond_signal(&c->cond);
181 }
182
virCondBroadcast(virCond * c)183 void virCondBroadcast(virCond *c)
184 {
185 pthread_cond_broadcast(&c->cond);
186 }
187
188 struct virThreadArgs {
189 virThreadFunc func;
190 char *name;
191 bool worker;
192 void *opaque;
193 };
194
virThreadMaxName(void)195 size_t virThreadMaxName(void)
196 {
197 #if defined(__FreeBSD__) || defined(__APPLE__)
198 return 63;
199 #else
200 # ifdef __linux__
201 return 15;
202 # else
203 return 0; /* unlimited */
204 # endif
205 #endif
206 }
207
virThreadHelper(void * data)208 static void *virThreadHelper(void *data)
209 {
210 struct virThreadArgs *args = data;
211 struct virThreadArgs local = *args;
212 g_autofree char *thname = NULL;
213 size_t maxname = virThreadMaxName();
214
215 /* Free args early, rather than tying it up during the entire thread. */
216 g_free(args);
217
218 if (local.worker)
219 virThreadJobSetWorker(local.name);
220 else
221 virThreadJobSet(local.name);
222
223 if (maxname) {
224 thname = g_strndup(local.name, maxname);
225 } else {
226 thname = g_strdup(local.name);
227 }
228
229 #if defined(__linux__) || defined(WIN32)
230 pthread_setname_np(pthread_self(), thname);
231 #else
232 # ifdef __FreeBSD__
233 pthread_set_name_np(pthread_self(), thname);
234 # else
235 # ifdef __APPLE__
236 pthread_setname_np(thname);
237 # endif
238 # endif
239 #endif
240
241 local.func(local.opaque);
242
243 if (!local.worker)
244 virThreadJobClear(0);
245
246 g_free(local.name);
247 return NULL;
248 }
249
virThreadCreateFull(virThread * thread,bool joinable,virThreadFunc func,const char * name,bool worker,void * opaque)250 int virThreadCreateFull(virThread *thread,
251 bool joinable,
252 virThreadFunc func,
253 const char *name,
254 bool worker,
255 void *opaque)
256 {
257 struct virThreadArgs *args;
258 pthread_attr_t attr;
259 int ret = -1;
260 int err;
261
262 if ((err = pthread_attr_init(&attr)) != 0)
263 goto cleanup;
264
265 args = g_new0(struct virThreadArgs, 1);
266 args->func = func;
267 args->name = g_strdup(name);
268 args->worker = worker;
269 args->opaque = opaque;
270
271 if (!joinable)
272 pthread_attr_setdetachstate(&attr, 1);
273
274 err = pthread_create(&thread->thread, &attr, virThreadHelper, args);
275 if (err != 0) {
276 g_free(args->name);
277 g_free(args);
278 goto cleanup;
279 }
280 /* New thread owns 'args' in success case, so don't free */
281
282 ret = 0;
283 cleanup:
284 pthread_attr_destroy(&attr);
285 if (ret < 0)
286 errno = err;
287 return ret;
288 }
289
virThreadSelf(virThread * thread)290 void virThreadSelf(virThread *thread)
291 {
292 thread->thread = pthread_self();
293 }
294
virThreadIsSelf(virThread * thread)295 bool virThreadIsSelf(virThread *thread)
296 {
297 return pthread_equal(pthread_self(), thread->thread) ? true : false;
298 }
299
300 /* For debugging use only; this result is not guaranteed unique if
301 * pthread_t is larger than a 64-bit pointer, nor does it always match
302 * the pthread_self() id on Linux. */
virThreadSelfID(void)303 unsigned long long virThreadSelfID(void)
304 {
305 #if defined(WITH_SYS_SYSCALL_H) && defined(SYS_gettid) && defined(__linux__)
306 pid_t tid = syscall(SYS_gettid);
307 return tid;
308 #else
309 union {
310 unsigned long long l;
311 pthread_t t;
312 } u;
313 u.t = pthread_self();
314 return u.l;
315 #endif
316 }
317
318 /* For debugging use only; this result is not guaranteed unique if
319 * pthread_t is larger than a 64-bit pointer, nor does it always match
320 * the thread id of virThreadSelfID on Linux. */
virThreadID(virThread * thread)321 unsigned long long virThreadID(virThread *thread)
322 {
323 union {
324 unsigned long long l;
325 pthread_t t;
326 } u;
327 u.t = thread->thread;
328 return u.l;
329 }
330
virThreadJoin(virThread * thread)331 void virThreadJoin(virThread *thread)
332 {
333 pthread_join(thread->thread, NULL);
334 }
335
virThreadCancel(virThread * thread)336 void virThreadCancel(virThread *thread)
337 {
338 pthread_cancel(thread->thread);
339 }
340
virThreadLocalInit(virThreadLocal * l,virThreadLocalCleanup c)341 int virThreadLocalInit(virThreadLocal *l,
342 virThreadLocalCleanup c)
343 {
344 int ret;
345 if ((ret = pthread_key_create(&l->key, c)) != 0) {
346 errno = ret;
347 return -1;
348 }
349 return 0;
350 }
351
virThreadLocalGet(virThreadLocal * l)352 void *virThreadLocalGet(virThreadLocal *l)
353 {
354 return pthread_getspecific(l->key);
355 }
356
virThreadLocalSet(virThreadLocal * l,void * val)357 int virThreadLocalSet(virThreadLocal *l, void *val)
358 {
359 int err = pthread_setspecific(l->key, val);
360 if (err) {
361 errno = err;
362 return -1;
363 }
364 return 0;
365 }
366