Line data Source code
1 : /* FreeTDS - Library of routines accessing Sybase and Microsoft databases
2 : * Copyright (C) 2012 Frediano Ziglio
3 : *
4 : * This library is free software; you can redistribute it and/or
5 : * modify it under the terms of the GNU Library General Public
6 : * License as published by the Free Software Foundation; either
7 : * version 2 of the License, or (at your option) any later version.
8 : *
9 : * This library is distributed in the hope that it will be useful,
10 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 : * Library General Public License for more details.
13 : *
14 : * You should have received a copy of the GNU Library General Public
15 : * License along with this library; if not, write to the
16 : * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17 : * Boston, MA 02111-1307, USA.
18 : */
19 :
20 : #include <config.h>
21 :
22 : #if HAVE_STDLIB_H
23 : #include <stdlib.h>
24 : #endif /* HAVE_STDLIB_H */
25 :
26 : #ifdef _WIN32
27 :
28 : #if HAVE_STRING_H
29 : #include <string.h>
30 : #endif /* HAVE_STRING_H */
31 :
32 : #include <freetds/thread.h>
33 : #include <freetds/time.h>
34 : #include <freetds/macros.h>
35 :
36 : /* implementation for systems that support Condition Variables */
37 : typedef VOID(WINAPI * init_cv_t) (TDS_CONDITION_VARIABLE * cv);
38 : typedef BOOL(WINAPI * sleep_cv_t) (TDS_CONDITION_VARIABLE * cv, PSRWLOCK lock, DWORD milli, ULONG flags);
39 : typedef VOID(WINAPI * wake_cv_t) (TDS_CONDITION_VARIABLE * cv);
40 : typedef VOID(WINAPI * srwinit_cv_t) (PSRWLOCK lock);
41 : typedef VOID(WINAPI * srwlock_cv_t) (PSRWLOCK lock);
42 : typedef VOID(WINAPI * srwunlock_cv_t) (PSRWLOCK lock);
43 : typedef BOOLEAN(WINAPI * srwtrylock_cv_t) (PSRWLOCK lock);
44 :
45 : static init_cv_t init_cv = NULL;
46 : static sleep_cv_t sleep_cv = NULL;
47 : static wake_cv_t wake_cv = NULL;
48 : static srwinit_cv_t srwinit_cv = NULL;
49 : static srwlock_cv_t srwlock_cv = NULL;
50 : static srwunlock_cv_t srwunlock_cv = NULL;
51 : static srwtrylock_cv_t srwtrylock_cv = NULL;
52 :
53 : static int
54 : new_mutex_init(tds_raw_mutex *mtx)
55 : {
56 : srwinit_cv(&mtx->srwlock);
57 : return 0;
58 : }
59 :
60 : static void
61 : new_mutex_free(tds_raw_mutex *mtx TDS_UNUSED)
62 : {
63 : }
64 :
65 : static void
66 : new_mutex_lock(tds_raw_mutex *mtx)
67 : {
68 : srwlock_cv(&mtx->srwlock);
69 : }
70 :
71 : static void
72 : new_mutex_unlock(tds_raw_mutex *mtx)
73 : {
74 : srwunlock_cv(&mtx->srwlock);
75 : }
76 :
77 : static int
78 : new_mutex_trylock(tds_raw_mutex *mtx)
79 : {
80 : return srwtrylock_cv(&mtx->srwlock) ? 0 : -1;
81 : }
82 :
83 : static int
84 : new_cond_init(tds_condition *cond)
85 : {
86 : init_cv(&cond->cv);
87 : return 0;
88 : }
89 :
90 : static int
91 : new_cond_destroy(tds_condition * cond TDS_UNUSED)
92 : {
93 : return 0;
94 : }
95 :
96 : static int
97 : new_cond_signal(tds_condition * cond)
98 : {
99 : wake_cv(&cond->cv);
100 : return 0;
101 : }
102 :
103 : static int
104 : new_cond_timedwait(tds_condition *cond, tds_raw_mutex *mtx, int timeout_sec)
105 : {
106 : if (sleep_cv(&cond->cv, &mtx->srwlock, timeout_sec <= 0 ? INFINITE : timeout_sec * 1000, 0))
107 : return 0;
108 : return ETIMEDOUT;
109 : }
110 :
111 :
112 : /* Implementation for systems that do not support Condition Variables.
113 : *
114 : * These are very old systems (like Windows XP), we don't care much about,
115 : * just to make them run without much expectations.
116 : *
117 : * We reuse "srwlock.Ptr" to store a pointer to a structure with a
118 : * CRITICAL_SECTION in it.
119 : */
120 : typedef struct
121 : {
122 : CRITICAL_SECTION crit;
123 : DWORD thread_id;
124 : } old_mutex;
125 :
126 : static old_mutex *
127 : old_mutex_allocate(tds_raw_mutex *mtx)
128 : {
129 : old_mutex *res, *old_mtx;
130 :
131 : /* Allocate and initialize structure. */
132 : old_mtx = calloc(1, sizeof(old_mutex));
133 : if (!old_mtx)
134 : abort();
135 : InitializeCriticalSection(&old_mtx->crit);
136 :
137 : /* Hook to srwlock.Ptr, undo if it was set in the meantime. */
138 : res = InterlockedCompareExchangePointer(&mtx->srwlock.Ptr, old_mtx, NULL);
139 : if (res == NULL)
140 : return old_mtx;
141 :
142 : DeleteCriticalSection(&old_mtx->crit);
143 : free(old_mtx);
144 : return res;
145 : }
146 :
147 : static int
148 : old_mutex_init(tds_raw_mutex *mtx)
149 : {
150 : mtx->srwlock.Ptr = NULL;
151 : old_mutex_allocate(mtx);
152 : return 0;
153 : }
154 :
155 : static void
156 : old_mutex_free(tds_raw_mutex *mtx)
157 : {
158 : old_mutex *old_mtx = InterlockedExchangePointer(&mtx->srwlock.Ptr, NULL);
159 :
160 : if (old_mtx) {
161 : DeleteCriticalSection(&old_mtx->crit);
162 : free(old_mtx);
163 : }
164 : }
165 :
166 : static void
167 : old_mutex_lock(tds_raw_mutex *mtx)
168 : {
169 : old_mutex *old_mtx = mtx->srwlock.Ptr;
170 :
171 : if (!old_mtx)
172 : old_mtx = old_mutex_allocate(mtx);
173 :
174 : EnterCriticalSection(&old_mtx->crit);
175 : old_mtx->thread_id = GetCurrentThreadId();
176 : }
177 :
178 : static void
179 : old_mutex_unlock(tds_raw_mutex *mtx)
180 : {
181 : old_mutex *old_mtx = mtx->srwlock.Ptr;
182 :
183 : old_mtx->thread_id = 0;
184 : LeaveCriticalSection(&old_mtx->crit);
185 : }
186 :
187 : static int
188 : old_mutex_trylock(tds_raw_mutex *mtx)
189 : {
190 : old_mutex *old_mtx = mtx->srwlock.Ptr;
191 :
192 : if (!old_mtx)
193 : old_mtx = old_mutex_allocate(mtx);
194 :
195 : if (TryEnterCriticalSection(&old_mtx->crit)) {
196 : DWORD thread_id = GetCurrentThreadId();
197 :
198 : if (old_mtx->thread_id == thread_id) {
199 : LeaveCriticalSection(&old_mtx->crit);
200 : return -1;
201 : }
202 : old_mtx->thread_id = thread_id;
203 : return 0;
204 : }
205 : return -1;
206 : }
207 :
208 : static int
209 : old_cond_init(tds_condition *cond)
210 : {
211 : cond->ev = CreateEvent(NULL, FALSE, FALSE, NULL);
212 : if (!cond->ev)
213 : return ENOMEM;
214 : return 0;
215 : }
216 :
217 : static int
218 : old_cond_destroy(tds_condition * cond)
219 : {
220 : CloseHandle(cond->ev);
221 : return 0;
222 : }
223 :
224 : static int
225 : old_cond_signal(tds_condition * cond)
226 : {
227 : SetEvent(cond->ev);
228 : return 0;
229 : }
230 :
231 : static int
232 : old_cond_timedwait(tds_condition *cond, tds_raw_mutex *mtx, int timeout_sec)
233 : {
234 : old_mutex *old_mtx = mtx->srwlock.Ptr;
235 : int res;
236 :
237 : LeaveCriticalSection(&old_mtx->crit);
238 : res = WaitForSingleObject(cond->ev, timeout_sec <= 0 ? INFINITE : timeout_sec * 1000);
239 : EnterCriticalSection(&old_mtx->crit);
240 : return res == WAIT_TIMEOUT ? ETIMEDOUT : 0;
241 : }
242 :
243 :
244 : /* dummy implementation used to detect which version above to use */
245 : static void
246 : detect_cond(void)
247 : {
248 : /* detect if this Windows support condition variables and SRWLocks */
249 : HMODULE mod = GetModuleHandle(TEXT("kernel32"));
250 :
251 : if (mod) {
252 : init_cv = (init_cv_t) GetProcAddress(mod, "InitializeConditionVariable");
253 : sleep_cv = (sleep_cv_t) GetProcAddress(mod, "SleepConditionVariableSRW");
254 : wake_cv = (wake_cv_t) GetProcAddress(mod, "WakeConditionVariable");
255 : srwinit_cv = (srwinit_cv_t) GetProcAddress(mod, "InitializeSRWLock");
256 : srwlock_cv = (srwlock_cv_t) GetProcAddress(mod, "AcquireSRWLockExclusive");
257 : srwunlock_cv = (srwunlock_cv_t) GetProcAddress(mod, "ReleaseSRWLockExclusive");
258 : srwtrylock_cv = (srwtrylock_cv_t) GetProcAddress(mod, "TryAcquireSRWLockExclusive");
259 : }
260 :
261 : if (init_cv && sleep_cv && wake_cv && srwinit_cv && srwlock_cv && srwunlock_cv && srwtrylock_cv) {
262 : tds_raw_mutex_init = new_mutex_init;
263 : tds_raw_mutex_free = new_mutex_free;
264 : tds_raw_mutex_lock = new_mutex_lock;
265 : tds_raw_mutex_unlock = new_mutex_unlock;
266 : tds_raw_mutex_trylock = new_mutex_trylock;
267 :
268 : tds_raw_cond_init = new_cond_init;
269 : tds_raw_cond_destroy = new_cond_destroy;
270 : tds_raw_cond_signal = new_cond_signal;
271 : tds_raw_cond_timedwait = new_cond_timedwait;
272 : } else {
273 : tds_raw_mutex_init = old_mutex_init;
274 : tds_raw_mutex_free = old_mutex_free;
275 : tds_raw_mutex_lock = old_mutex_lock;
276 : tds_raw_mutex_unlock = old_mutex_unlock;
277 : tds_raw_mutex_trylock = old_mutex_trylock;
278 :
279 : tds_raw_cond_init = old_cond_init;
280 : tds_raw_cond_destroy = old_cond_destroy;
281 : tds_raw_cond_signal = old_cond_signal;
282 : tds_raw_cond_timedwait = old_cond_timedwait;
283 : }
284 : }
285 :
286 : static int
287 : detect_mutex_init(tds_raw_mutex *mtx)
288 : {
289 : detect_cond();
290 : return tds_raw_mutex_init(mtx);
291 : }
292 :
293 : static void
294 : detect_mutex_free(tds_raw_mutex *mtx)
295 : {
296 : detect_cond();
297 : tds_raw_mutex_free(mtx);
298 : }
299 :
300 : static void
301 : detect_mutex_lock(tds_raw_mutex *mtx)
302 : {
303 : detect_cond();
304 : tds_raw_mutex_lock(mtx);
305 : }
306 :
307 : static void
308 : detect_mutex_unlock(tds_raw_mutex *mtx)
309 : {
310 : detect_cond();
311 : tds_raw_mutex_unlock(mtx);
312 : }
313 :
314 : static int
315 : detect_mutex_trylock(tds_raw_mutex *mtx)
316 : {
317 : detect_cond();
318 : return tds_raw_mutex_trylock(mtx);
319 : }
320 :
321 : static int
322 : detect_cond_init(tds_condition *cond)
323 : {
324 : detect_cond();
325 : return tds_raw_cond_init(cond);
326 : }
327 :
328 : static int
329 : detect_cond_destroy(tds_condition * cond)
330 : {
331 : detect_cond();
332 : return tds_raw_cond_destroy(cond);
333 : }
334 :
335 : static int
336 : detect_cond_signal(tds_condition * cond)
337 : {
338 : detect_cond();
339 : return tds_raw_cond_signal(cond);
340 : }
341 :
342 : static int
343 : detect_cond_timedwait(tds_condition * cond, tds_raw_mutex * mtx, int timeout_sec)
344 : {
345 : detect_cond();
346 : return tds_raw_cond_timedwait(cond, mtx, timeout_sec);
347 : }
348 :
349 : int (*tds_raw_mutex_init)(tds_raw_mutex * mtx) = detect_mutex_init;
350 : void (*tds_raw_mutex_free)(tds_raw_mutex * mtx) = detect_mutex_free;
351 : void (*tds_raw_mutex_lock)(tds_raw_mutex * mtx) = detect_mutex_lock;
352 : void (*tds_raw_mutex_unlock)(tds_raw_mutex * mtx) = detect_mutex_unlock;
353 : int (*tds_raw_mutex_trylock)(tds_raw_mutex * mtx) = detect_mutex_trylock;
354 :
355 : int (*tds_raw_cond_init)(tds_condition * cond) = detect_cond_init;
356 : int (*tds_raw_cond_destroy)(tds_condition * cond) = detect_cond_destroy;
357 : int (*tds_raw_cond_signal)(tds_condition * cond) = detect_cond_signal;
358 : int (*tds_raw_cond_timedwait) (tds_condition * cond, tds_raw_mutex * mtx, int timeout_sec) = detect_cond_timedwait;
359 :
360 : #elif defined(TDS_HAVE_PTHREAD_MUTEX) && !defined(TDS_NO_THREADSAFE)
361 :
362 : #include <freetds/thread.h>
363 : #include <freetds/time.h>
364 :
365 : /* check if we can use pthread_cond_timedwait_relative_np */
366 : #undef USE_COND_TIMEDWAIT_RELATIVE
367 : #if defined(HAVE_PTHREAD_COND_TIMEDWAIT_RELATIVE_NP) && \
368 : (!defined(__ANDROID__) || ((__ANDROID_API__ < 21) && defined(HAVE_PTHREAD_COND_TIMEDWAIT_RELATIVE)))
369 : #define USE_COND_TIMEDWAIT_RELATIVE 1
370 : #endif
371 :
372 : /* check if we can use clock_gettime */
373 : #undef USE_CLOCK_GETTIME_IN_COND
374 : #if !defined(USE_COND_TIMEDWAIT_RELATIVE) && \
375 : defined(HAVE_CLOCK_GETTIME) && (defined(CLOCK_REALTIME) || defined(CLOCK_MONOTONIC))
376 : #define USE_CLOCK_GETTIME_IN_COND 1
377 : #endif
378 :
379 : /* check if we can use CLOCK_MONOTONIC for conditions */
380 : #undef USE_MONOTONIC_CLOCK_IN_COND
381 : #if defined(USE_CLOCK_GETTIME_IN_COND) && defined(HAVE_PTHREAD_CONDATTR_SETCLOCK) && defined(CLOCK_MONOTONIC)
382 : #define USE_MONOTONIC_CLOCK_IN_COND 1
383 : #endif
384 :
385 2365 : int tds_raw_cond_init(tds_condition *cond)
386 : {
387 : #ifdef USE_MONOTONIC_CLOCK_IN_COND
388 : int res;
389 : pthread_condattr_t attr;
390 :
391 2365 : pthread_condattr_init(&attr);
392 2365 : res = pthread_condattr_setclock(&attr, CLOCK_MONOTONIC);
393 2365 : if (!res)
394 2365 : res = pthread_cond_init(cond, &attr);
395 2365 : pthread_condattr_destroy(&attr);
396 2365 : return res;
397 : #else
398 : return pthread_cond_init(cond, NULL);
399 : #endif
400 : }
401 :
402 40 : int tds_raw_cond_timedwait(tds_condition *cond, tds_raw_mutex *mtx, int timeout_sec)
403 : {
404 : struct timespec ts;
405 :
406 40 : if (timeout_sec <= 0)
407 20 : return tds_raw_cond_wait(cond, mtx);
408 :
409 : #if defined(USE_COND_TIMEDWAIT_RELATIVE)
410 : ts.tv_sec = timeout_sec;
411 : ts.tv_nsec = 0;
412 : return pthread_cond_timedwait_relative_np(cond, mtx, &ts);
413 : #else
414 :
415 : # if defined(USE_MONOTONIC_CLOCK_IN_COND)
416 20 : clock_gettime(CLOCK_MONOTONIC, &ts);
417 : # elif defined(USE_CLOCK_GETTIME_IN_COND)
418 : clock_gettime(CLOCK_REALTIME, &ts);
419 : # elif defined(HAVE_GETTIMEOFDAY)
420 : do {
421 : struct timeval tv;
422 : gettimeofday(&tv, NULL);
423 : ts.tv_sec = tv.tv_sec;
424 : ts.tv_nsec = tv.tv_usec * 1000u;
425 : } while(0);
426 : # else
427 : # error No way to get a proper time!
428 : # endif
429 :
430 20 : ts.tv_sec += timeout_sec;
431 20 : return pthread_cond_timedwait(cond, mtx, &ts);
432 : #endif
433 : }
434 :
435 : #endif
|