xref: /netbsd-src/external/bsd/ntp/dist/sntp/libevent/evthread_pthread.c (revision cdfa2a7ef92791ba9db70a584a1d904730e6fb46)
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