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