1 /* $NetBSD: evthread_pthread.c,v 1.5 2020/05/25 20:47:33 christos Exp $ */
2
3 /*
4 * Copyright 2009-2012 Niels Provos and Nick Mathewson
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28 #include "event2/event-config.h"
29 #include "evconfig-private.h"
30
31 /* With glibc we need to define _GNU_SOURCE to get PTHREAD_MUTEX_RECURSIVE.
32 * This comes from evconfig-private.h
33 */
34 #include <pthread.h>
35
36 struct event_base;
37 #include "event2/thread.h"
38
39 #include <stdlib.h>
40 #include <string.h>
41 #include "mm-internal.h"
42 #include "evthread-internal.h"
43
44 static pthread_mutexattr_t attr_recursive;
45
46 static void *
evthread_posix_lock_alloc(unsigned locktype)47 evthread_posix_lock_alloc(unsigned locktype)
48 {
49 pthread_mutexattr_t *attr = NULL;
50 pthread_mutex_t *lock = mm_malloc(sizeof(pthread_mutex_t));
51 if (!lock)
52 return NULL;
53 if (locktype & EVTHREAD_LOCKTYPE_RECURSIVE)
54 attr = &attr_recursive;
55 if (pthread_mutex_init(lock, attr)) {
56 mm_free(lock);
57 return NULL;
58 }
59 return lock;
60 }
61
62 static void
evthread_posix_lock_free(void * lock_,unsigned locktype)63 evthread_posix_lock_free(void *lock_, unsigned locktype)
64 {
65 pthread_mutex_t *lock = lock_;
66 pthread_mutex_destroy(lock);
67 mm_free(lock);
68 }
69
70 static int
evthread_posix_lock(unsigned mode,void * lock_)71 evthread_posix_lock(unsigned mode, void *lock_)
72 {
73 pthread_mutex_t *lock = lock_;
74 if (mode & EVTHREAD_TRY)
75 return pthread_mutex_trylock(lock);
76 else
77 return pthread_mutex_lock(lock);
78 }
79
80 static int
evthread_posix_unlock(unsigned mode,void * lock_)81 evthread_posix_unlock(unsigned mode, void *lock_)
82 {
83 pthread_mutex_t *lock = lock_;
84 return pthread_mutex_unlock(lock);
85 }
86
87 static unsigned long
evthread_posix_get_id(void)88 evthread_posix_get_id(void)
89 {
90 union {
91 pthread_t thr;
92 #if EVENT__SIZEOF_PTHREAD_T > EVENT__SIZEOF_LONG
93 ev_uint64_t id;
94 #else
95 unsigned long id;
96 #endif
97 } r;
98 #if EVENT__SIZEOF_PTHREAD_T < EVENT__SIZEOF_LONG
99 memset(&r, 0, sizeof(r));
100 #endif
101 r.thr = pthread_self();
102 return (unsigned long)r.id;
103 }
104
105 static void *
evthread_posix_cond_alloc(unsigned condflags)106 evthread_posix_cond_alloc(unsigned condflags)
107 {
108 pthread_cond_t *cond = mm_malloc(sizeof(pthread_cond_t));
109 if (!cond)
110 return NULL;
111 if (pthread_cond_init(cond, NULL)) {
112 mm_free(cond);
113 return NULL;
114 }
115 return cond;
116 }
117
118 static void
evthread_posix_cond_free(void * cond_)119 evthread_posix_cond_free(void *cond_)
120 {
121 pthread_cond_t *cond = cond_;
122 pthread_cond_destroy(cond);
123 mm_free(cond);
124 }
125
126 static int
evthread_posix_cond_signal(void * cond_,int broadcast)127 evthread_posix_cond_signal(void *cond_, int broadcast)
128 {
129 pthread_cond_t *cond = cond_;
130 int r;
131 if (broadcast)
132 r = pthread_cond_broadcast(cond);
133 else
134 r = pthread_cond_signal(cond);
135 return r ? -1 : 0;
136 }
137
138 static int
evthread_posix_cond_wait(void * cond_,void * lock_,const struct timeval * tv)139 evthread_posix_cond_wait(void *cond_, void *lock_, const struct timeval *tv)
140 {
141 int r;
142 pthread_cond_t *cond = cond_;
143 pthread_mutex_t *lock = lock_;
144
145 if (tv) {
146 struct timeval now, abstime;
147 struct timespec ts;
148 evutil_gettimeofday(&now, NULL);
149 evutil_timeradd(&now, tv, &abstime);
150 ts.tv_sec = abstime.tv_sec;
151 ts.tv_nsec = abstime.tv_usec*1000;
152 r = pthread_cond_timedwait(cond, lock, &ts);
153 if (r == ETIMEDOUT)
154 return 1;
155 else if (r)
156 return -1;
157 else
158 return 0;
159 } else {
160 r = pthread_cond_wait(cond, lock);
161 return r ? -1 : 0;
162 }
163 }
164
165 int
evthread_use_pthreads(void)166 evthread_use_pthreads(void)
167 {
168 struct evthread_lock_callbacks cbs = {
169 EVTHREAD_LOCK_API_VERSION,
170 EVTHREAD_LOCKTYPE_RECURSIVE,
171 evthread_posix_lock_alloc,
172 evthread_posix_lock_free,
173 evthread_posix_lock,
174 evthread_posix_unlock
175 };
176 struct evthread_condition_callbacks cond_cbs = {
177 EVTHREAD_CONDITION_API_VERSION,
178 evthread_posix_cond_alloc,
179 evthread_posix_cond_free,
180 evthread_posix_cond_signal,
181 evthread_posix_cond_wait
182 };
183 /* Set ourselves up to get recursive locks. */
184 if (pthread_mutexattr_init(&attr_recursive))
185 return -1;
186 if (pthread_mutexattr_settype(&attr_recursive, PTHREAD_MUTEX_RECURSIVE))
187 return -1;
188
189 evthread_set_lock_callbacks(&cbs);
190 evthread_set_condition_callbacks(&cond_cbs);
191 evthread_set_id_callback(evthread_posix_get_id);
192 return 0;
193 }
194