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