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