Line data Source code
1 : /* FreeTDS - Library of routines accessing Sybase and Microsoft databases
2 : *
3 : * Copyright (C) 2005 Liam Widdowson
4 : * Copyright (C) 2010-2012 Frediano Ziglio
5 : *
6 : * This library is free software; you can redistribute it and/or
7 : * modify it under the terms of the GNU Library General Public
8 : * License as published by the Free Software Foundation; either
9 : * version 2 of the License, or (at your option) any later version.
10 : *
11 : * This library is distributed in the hope that it will be useful,
12 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 : * Library General Public License for more details.
15 : *
16 : * You should have received a copy of the GNU Library General Public
17 : * License along with this library; if not, write to the
18 : * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19 : * Boston, MA 02111-1307, USA.
20 : */
21 :
22 : #ifndef TDSTHREAD_H
23 : #define TDSTHREAD_H 1
24 :
25 : #undef TDS_HAVE_MUTEX
26 :
27 : #if defined(_THREAD_SAFE) && defined(TDS_HAVE_PTHREAD_MUTEX)
28 :
29 : #include <tds_sysdep_public.h>
30 : #include <freetds/sysdep_types.h>
31 : #include <pthread.h>
32 : #include <errno.h>
33 :
34 : #include <freetds/pushvis.h>
35 :
36 : typedef pthread_mutex_t tds_raw_mutex;
37 : #define TDS_RAW_MUTEX_INITIALIZER PTHREAD_MUTEX_INITIALIZER
38 :
39 : static inline void tds_raw_mutex_lock(tds_raw_mutex *mtx)
40 : {
41 596013 : pthread_mutex_lock(mtx);
42 : }
43 :
44 : static inline int tds_raw_mutex_trylock(tds_raw_mutex *mtx)
45 : {
46 534608 : return pthread_mutex_trylock(mtx);
47 : }
48 :
49 : static inline void tds_raw_mutex_unlock(tds_raw_mutex *mtx)
50 : {
51 1048044 : pthread_mutex_unlock(mtx);
52 : }
53 :
54 : static inline int tds_raw_mutex_init(tds_raw_mutex *mtx)
55 : {
56 79576 : return pthread_mutex_init(mtx, NULL);
57 : }
58 :
59 : static inline void tds_raw_mutex_free(tds_raw_mutex *mtx)
60 : {
61 75773 : pthread_mutex_destroy(mtx);
62 : }
63 :
64 : typedef pthread_cond_t tds_condition;
65 :
66 : int tds_raw_cond_init(tds_condition *cond);
67 : static inline int tds_raw_cond_destroy(tds_condition *cond)
68 : {
69 1894 : return pthread_cond_destroy(cond);
70 : }
71 : static inline int tds_raw_cond_signal(tds_condition *cond)
72 : {
73 37857 : return pthread_cond_signal(cond);
74 : }
75 : static inline int tds_raw_cond_wait(tds_condition *cond, tds_raw_mutex *mtx)
76 : {
77 24 : return pthread_cond_wait(cond, mtx);
78 : }
79 : int tds_raw_cond_timedwait(tds_condition *cond, tds_raw_mutex *mtx, int timeout_sec);
80 :
81 : #define TDS_HAVE_MUTEX 1
82 :
83 : typedef pthread_t tds_thread;
84 : typedef pthread_t tds_thread_id;
85 : typedef void *(*tds_thread_proc)(void *arg);
86 : #define TDS_THREAD_PROC_DECLARE(name, arg) \
87 : void *name(void *arg)
88 : #define TDS_THREAD_RESULT(n) ((void*)(TDS_INTPTR)(n))
89 :
90 : static inline int tds_thread_create(tds_thread *ret, tds_thread_proc proc, void *arg)
91 : {
92 294 : return pthread_create(ret, NULL, proc, arg);
93 : }
94 :
95 1426 : static inline int tds_thread_create_detached(tds_thread_proc proc, void *arg)
96 : {
97 : tds_thread th;
98 1426 : int ret = pthread_create(&th, NULL, proc, arg);
99 1426 : if (!ret)
100 1426 : pthread_detach(th);
101 1426 : return ret;
102 : }
103 :
104 : static inline int tds_thread_join(tds_thread th, void **ret)
105 : {
106 294 : return pthread_join(th, ret);
107 : }
108 :
109 : static inline tds_thread_id tds_thread_get_current_id(void)
110 : {
111 1050488 : return pthread_self();
112 : }
113 :
114 : static inline int tds_thread_is_current(tds_thread_id th)
115 : {
116 87071 : return pthread_equal(th, pthread_self());
117 : }
118 :
119 : #include <freetds/popvis.h>
120 :
121 : #elif defined(_WIN32)
122 :
123 : #include <freetds/windows.h>
124 : #include <errno.h>
125 :
126 : /* old version of Windows do not define this constant */
127 : #ifndef ETIMEDOUT
128 : #define ETIMEDOUT 138
129 : #endif
130 :
131 : struct ptw32_mcs_node_t_;
132 :
133 : typedef struct {
134 : struct ptw32_mcs_node_t_ *lock;
135 : LONG done;
136 : DWORD thread_id;
137 : CRITICAL_SECTION crit;
138 : } tds_raw_mutex;
139 :
140 : #define TDS_RAW_MUTEX_INITIALIZER { NULL, 0, 0 }
141 :
142 : static inline int
143 : tds_raw_mutex_init(tds_raw_mutex *mtx)
144 : {
145 : mtx->lock = NULL;
146 : mtx->done = 0;
147 : mtx->thread_id = 0;
148 : return 0;
149 : }
150 :
151 : void tds_win_mutex_lock(tds_raw_mutex *mutex);
152 :
153 : static inline void tds_raw_mutex_lock(tds_raw_mutex *mtx)
154 : {
155 : if (mtx->done) {
156 : EnterCriticalSection(&mtx->crit);
157 : mtx->thread_id = GetCurrentThreadId();
158 : } else {
159 : tds_win_mutex_lock(mtx);
160 : }
161 : }
162 :
163 : int tds_raw_mutex_trylock(tds_raw_mutex *mtx);
164 :
165 : static inline void tds_raw_mutex_unlock(tds_raw_mutex *mtx)
166 : {
167 : mtx->thread_id = 0;
168 : LeaveCriticalSection(&mtx->crit);
169 : }
170 :
171 : static inline void tds_raw_mutex_free(tds_raw_mutex *mtx)
172 : {
173 : if (mtx->done) {
174 : DeleteCriticalSection(&mtx->crit);
175 : mtx->done = 0;
176 : }
177 : }
178 :
179 : #define TDS_HAVE_MUTEX 1
180 :
181 : /* easy way, only single signal supported */
182 : typedef void *TDS_CONDITION_VARIABLE;
183 : typedef union {
184 : HANDLE ev;
185 : TDS_CONDITION_VARIABLE cv;
186 : } tds_condition;
187 :
188 : extern int (*tds_raw_cond_init)(tds_condition *cond);
189 : extern int (*tds_raw_cond_destroy)(tds_condition *cond);
190 : extern int (*tds_raw_cond_signal)(tds_condition *cond);
191 : extern int (*tds_raw_cond_timedwait)(tds_condition *cond, tds_raw_mutex *mtx, int timeout_sec);
192 : static inline int tds_raw_cond_wait(tds_condition *cond, tds_raw_mutex *mtx)
193 : {
194 : return tds_raw_cond_timedwait(cond, mtx, -1);
195 : }
196 :
197 : typedef HANDLE tds_thread;
198 : typedef DWORD tds_thread_id;
199 : typedef DWORD (WINAPI *tds_thread_proc)(void *arg);
200 : #define TDS_THREAD_PROC_DECLARE(name, arg) \
201 : DWORD WINAPI name(void *arg)
202 : #define TDS_THREAD_RESULT(n) ((DWORD)(int)(n))
203 :
204 : static inline int tds_thread_create(tds_thread *ret, tds_thread_proc proc, void *arg)
205 : {
206 : *ret = CreateThread(NULL, 0, proc, arg, 0, NULL);
207 : return *ret != NULL ? 0 : 11 /* EAGAIN */;
208 : }
209 :
210 : static inline int tds_thread_create_detached(tds_thread_proc proc, void *arg)
211 : {
212 : HANDLE h = CreateThread(NULL, 0, proc, arg, 0, NULL);
213 : if (h)
214 : return 0;
215 : CloseHandle(h);
216 : return 11 /* EAGAIN */;
217 : }
218 :
219 : static inline int tds_thread_join(tds_thread th, void **ret)
220 : {
221 : if (WaitForSingleObject(th, INFINITE) == WAIT_OBJECT_0) {
222 : if (ret) {
223 : DWORD r;
224 : if (!GetExitCodeThread(th, &r))
225 : r = 0xffffffffu;
226 : *ret = (void*) (((char*)0) + r);
227 : }
228 :
229 : CloseHandle(th);
230 : return 0;
231 : }
232 : CloseHandle(th);
233 : return 22 /* EINVAL */;
234 : }
235 :
236 : static inline tds_thread_id tds_thread_get_current_id(void)
237 : {
238 : return GetCurrentThreadId();
239 : }
240 :
241 : static inline int tds_thread_is_current(tds_thread_id th)
242 : {
243 : return th == GetCurrentThreadId();
244 : }
245 :
246 : #else
247 :
248 : #include <tds_sysdep_public.h>
249 :
250 : /* define noops as "successful" */
251 : typedef struct {
252 : char dummy[0]; /* compiler compatibility */
253 : } tds_raw_mutex;
254 :
255 : #define TDS_RAW_MUTEX_INITIALIZER {}
256 :
257 : static inline void tds_raw_mutex_lock(tds_raw_mutex *mtx)
258 : {
259 : }
260 :
261 : static inline int tds_raw_mutex_trylock(tds_raw_mutex *mtx)
262 : {
263 : return 0;
264 : }
265 :
266 : static inline void tds_raw_mutex_unlock(tds_raw_mutex *mtx)
267 : {
268 : }
269 :
270 : static inline int tds_raw_mutex_init(tds_raw_mutex *mtx)
271 : {
272 : return 0;
273 : }
274 :
275 : static inline void tds_raw_mutex_free(tds_raw_mutex *mtx)
276 : {
277 : }
278 :
279 : typedef struct {
280 : char dummy[0]; /* compiler compatibility */
281 : } tds_condition;
282 :
283 : static inline int tds_raw_cond_init(tds_condition *cond)
284 : {
285 : return 0;
286 : }
287 : static inline int tds_raw_cond_destroy(tds_condition *cond)
288 : {
289 : return 0;
290 : }
291 : #define tds_raw_cond_signal(cond) \
292 : FreeTDS_Condition_not_compiled
293 :
294 : #define tds_raw_cond_wait(cond, mtx) \
295 : FreeTDS_Condition_not_compiled
296 :
297 : #define tds_raw_cond_timedwait(cond, mtx, timeout_sec) \
298 : FreeTDS_Condition_not_compiled
299 :
300 : typedef struct {
301 : char dummy[0]; /* compiler compatibility */
302 : } tds_thread;
303 : typedef int tds_thread_id;
304 :
305 : typedef void *(*tds_thread_proc)(void *arg);
306 : #define TDS_THREAD_PROC_DECLARE(name, arg) \
307 : void *name(void *arg)
308 : #define TDS_THREAD_RESULT(n) ((void*)(TDS_INTPTR)(n))
309 :
310 : #define tds_thread_create(ret, proc, arg) \
311 : FreeTDS_Thread_not_compiled
312 :
313 : #define tds_thread_create_detached(proc, arg) \
314 : FreeTDS_Thread_not_compiled
315 :
316 : #define tds_thread_join(th, ret) \
317 : FreeTDS_Thread_not_compiled
318 :
319 : static inline tds_thread_id tds_thread_get_current_id(void)
320 : {
321 : return 0;
322 : }
323 :
324 : static inline int tds_thread_is_current(tds_thread_id th)
325 : {
326 : return 1;
327 : }
328 :
329 : #endif
330 :
331 : # define tds_cond_init tds_raw_cond_init
332 : # define tds_cond_destroy tds_raw_cond_destroy
333 : # define tds_cond_signal tds_raw_cond_signal
334 : # if !ENABLE_EXTRA_CHECKS
335 : # define TDS_MUTEX_INITIALIZER TDS_RAW_MUTEX_INITIALIZER
336 : # define tds_mutex tds_raw_mutex
337 : # define tds_mutex_lock tds_raw_mutex_lock
338 : # define tds_mutex_trylock tds_raw_mutex_trylock
339 : # define tds_mutex_unlock tds_raw_mutex_unlock
340 : # define tds_mutex_check_owned(mtx) do {} while(0)
341 : # define tds_mutex_init tds_raw_mutex_init
342 : # define tds_mutex_free tds_raw_mutex_free
343 : # define tds_cond_wait tds_raw_cond_wait
344 : # define tds_cond_timedwait tds_raw_cond_timedwait
345 : # else
346 : # include <assert.h>
347 :
348 : typedef struct tds_mutex
349 : {
350 : tds_raw_mutex mtx;
351 : volatile int locked;
352 : volatile tds_thread_id locked_by;
353 : } tds_mutex;
354 :
355 : # define TDS_MUTEX_INITIALIZER { TDS_RAW_MUTEX_INITIALIZER, 0 }
356 :
357 596013 : static inline void tds_mutex_lock(tds_mutex *mtx)
358 : {
359 596013 : assert(mtx);
360 1192026 : tds_raw_mutex_lock(&mtx->mtx);
361 596013 : assert(!mtx->locked);
362 596013 : mtx->locked = 1;
363 596013 : mtx->locked_by = tds_thread_get_current_id();
364 596013 : }
365 :
366 452261 : static inline int tds_mutex_trylock(tds_mutex *mtx)
367 : {
368 : int ret;
369 452261 : assert(mtx);
370 904522 : ret = tds_raw_mutex_trylock(&mtx->mtx);
371 452261 : if (!ret) {
372 452031 : assert(!mtx->locked);
373 452031 : mtx->locked = 1;
374 452031 : mtx->locked_by = tds_thread_get_current_id();
375 : }
376 452261 : return ret;
377 : }
378 :
379 1048044 : static inline void tds_mutex_unlock(tds_mutex *mtx)
380 : {
381 1048044 : assert(mtx && mtx->locked);
382 1048044 : mtx->locked = 0;
383 2096088 : tds_raw_mutex_unlock(&mtx->mtx);
384 1048044 : }
385 :
386 82347 : static inline void tds_mutex_check_owned(tds_mutex *mtx)
387 : {
388 : int ret;
389 82347 : assert(mtx);
390 164694 : ret = tds_raw_mutex_trylock(&mtx->mtx);
391 82347 : assert(ret);
392 82347 : assert(mtx->locked);
393 164694 : assert(tds_thread_is_current(mtx->locked_by));
394 82347 : }
395 :
396 : static inline int tds_mutex_init(tds_mutex *mtx)
397 : {
398 79576 : mtx->locked = 0;
399 159152 : return tds_raw_mutex_init(&mtx->mtx);
400 : }
401 :
402 75773 : static inline void tds_mutex_free(tds_mutex *mtx)
403 : {
404 75773 : assert(mtx && !mtx->locked);
405 151546 : tds_raw_mutex_free(&mtx->mtx);
406 75773 : }
407 :
408 8 : static inline int tds_cond_wait(tds_condition *cond, tds_mutex *mtx)
409 : {
410 : int ret;
411 8 : assert(mtx && mtx->locked);
412 8 : mtx->locked = 0;
413 16 : ret = tds_raw_cond_wait(cond, &mtx->mtx);
414 8 : mtx->locked = 1;
415 8 : mtx->locked_by = tds_thread_get_current_id();
416 8 : return ret;
417 : }
418 :
419 32 : static inline int tds_cond_timedwait(tds_condition *cond, tds_mutex *mtx, int timeout_sec)
420 : {
421 : int ret;
422 32 : assert(mtx && mtx->locked);
423 32 : mtx->locked = 0;
424 32 : ret = tds_raw_cond_timedwait(cond, &mtx->mtx, timeout_sec);
425 32 : mtx->locked = 1;
426 32 : mtx->locked_by = tds_thread_get_current_id();
427 32 : return ret;
428 : }
429 :
430 : # endif
431 :
432 : #endif
|