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, CRITICAL_SECTION * crit, DWORD milli);
39 : typedef VOID(WINAPI * wake_cv_t) (TDS_CONDITION_VARIABLE * cv);
40 :
41 : static init_cv_t init_cv = NULL;
42 : static sleep_cv_t sleep_cv = NULL;
43 : static wake_cv_t wake_cv = NULL;
44 :
45 : static int
46 : new_cond_init(tds_condition * cond)
47 : {
48 : init_cv(&cond->cv);
49 : return 0;
50 : }
51 :
52 : static int
53 : new_cond_destroy(tds_condition * cond TDS_UNUSED)
54 : {
55 : return 0;
56 : }
57 :
58 : static int
59 : new_cond_signal(tds_condition * cond)
60 : {
61 : wake_cv(&cond->cv);
62 : return 0;
63 : }
64 :
65 : static int
66 : new_cond_timedwait(tds_condition * cond, tds_raw_mutex * mtx, int timeout_sec)
67 : {
68 : if (sleep_cv(&cond->cv, &mtx->crit, timeout_sec <= 0 ? INFINITE : timeout_sec * 1000))
69 : return 0;
70 : return ETIMEDOUT;
71 : }
72 :
73 :
74 : /* implementation for systems that do not support Condition Variables */
75 : static int
76 : old_cond_init(tds_condition * cond)
77 : {
78 : cond->ev = CreateEvent(NULL, FALSE, FALSE, NULL);
79 : if (!cond->ev)
80 : return ENOMEM;
81 : return 0;
82 : }
83 :
84 : static int
85 : old_cond_destroy(tds_condition * cond)
86 : {
87 : CloseHandle(cond->ev);
88 : return 0;
89 : }
90 :
91 : static int
92 : old_cond_signal(tds_condition * cond)
93 : {
94 : SetEvent(cond->ev);
95 : return 0;
96 : }
97 :
98 : static int
99 : old_cond_timedwait(tds_condition * cond, tds_raw_mutex * mtx, int timeout_sec)
100 : {
101 : int res;
102 :
103 : LeaveCriticalSection(&mtx->crit);
104 : res = WaitForSingleObject(cond->ev, timeout_sec < 0 ? INFINITE : timeout_sec * 1000);
105 : EnterCriticalSection(&mtx->crit);
106 : return res == WAIT_TIMEOUT ? ETIMEDOUT : 0;
107 : }
108 :
109 :
110 : /* dummy implementation used to detect which version above to use */
111 : static void
112 : detect_cond(void)
113 : {
114 : /* detect if this Windows support condition variables */
115 : HMODULE mod = GetModuleHandle(TEXT("kernel32"));
116 :
117 : init_cv = (init_cv_t) GetProcAddress(mod, "InitializeConditionVariable");
118 : sleep_cv = (sleep_cv_t) GetProcAddress(mod, "SleepConditionVariableCS");
119 : wake_cv = (wake_cv_t) GetProcAddress(mod, "WakeConditionVariable");
120 :
121 : if (init_cv && sleep_cv && wake_cv) {
122 : tds_raw_cond_init = new_cond_init;
123 : tds_raw_cond_destroy = new_cond_destroy;
124 : tds_raw_cond_signal = new_cond_signal;
125 : tds_raw_cond_timedwait = new_cond_timedwait;
126 : } else {
127 : tds_raw_cond_init = old_cond_init;
128 : tds_raw_cond_destroy = old_cond_destroy;
129 : tds_raw_cond_signal = old_cond_signal;
130 : tds_raw_cond_timedwait = old_cond_timedwait;
131 : }
132 : }
133 :
134 : static int
135 : detect_cond_init(tds_condition * cond)
136 : {
137 : detect_cond();
138 : return tds_raw_cond_init(cond);
139 : }
140 :
141 : static int
142 : detect_cond_destroy(tds_condition * cond)
143 : {
144 : detect_cond();
145 : return tds_raw_cond_destroy(cond);
146 : }
147 :
148 : static int
149 : detect_cond_signal(tds_condition * cond)
150 : {
151 : detect_cond();
152 : return tds_raw_cond_signal(cond);
153 : }
154 :
155 : static int
156 : detect_cond_timedwait(tds_condition * cond, tds_raw_mutex * mtx, int timeout_sec)
157 : {
158 : detect_cond();
159 : return tds_raw_cond_timedwait(cond, mtx, timeout_sec);
160 : }
161 :
162 : int (*tds_raw_cond_init) (tds_condition * cond) = detect_cond_init;
163 : int (*tds_raw_cond_destroy) (tds_condition * cond) = detect_cond_destroy;
164 : int (*tds_raw_cond_signal) (tds_condition * cond) = detect_cond_signal;
165 : int (*tds_raw_cond_timedwait) (tds_condition * cond, tds_raw_mutex * mtx, int timeout_sec) = detect_cond_timedwait;
166 :
167 : #elif defined(TDS_HAVE_PTHREAD_MUTEX) && !defined(TDS_NO_THREADSAFE)
168 :
169 : #include <freetds/thread.h>
170 : #include <freetds/time.h>
171 :
172 : /* check if we can use pthread_cond_timedwait_relative_np */
173 : #undef USE_COND_TIMEDWAIT_RELATIVE
174 : #if defined(HAVE_PTHREAD_COND_TIMEDWAIT_RELATIVE_NP) && \
175 : (!defined(__ANDROID__) || ((__ANDROID_API__ < 21) && defined(HAVE_PTHREAD_COND_TIMEDWAIT_RELATIVE)))
176 : #define USE_COND_TIMEDWAIT_RELATIVE 1
177 : #endif
178 :
179 : /* check if we can use clock_gettime */
180 : #undef USE_CLOCK_GETTIME_IN_COND
181 : #if !defined(USE_COND_TIMEDWAIT_RELATIVE) && \
182 : defined(HAVE_CLOCK_GETTIME) && (defined(CLOCK_REALTIME) || defined(CLOCK_MONOTONIC))
183 : #define USE_CLOCK_GETTIME_IN_COND 1
184 : #endif
185 :
186 : /* check if we can use CLOCK_MONOTONIC for conditions */
187 : #undef USE_MONOTONIC_CLOCK_IN_COND
188 : #if defined(USE_CLOCK_GETTIME_IN_COND) && defined(HAVE_PTHREAD_CONDATTR_SETCLOCK) && defined(CLOCK_MONOTONIC)
189 : #define USE_MONOTONIC_CLOCK_IN_COND 1
190 : #endif
191 :
192 1946 : int tds_raw_cond_init(tds_condition *cond)
193 : {
194 : #ifdef USE_MONOTONIC_CLOCK_IN_COND
195 : int res;
196 : pthread_condattr_t attr;
197 :
198 1946 : pthread_condattr_init(&attr);
199 1946 : res = pthread_condattr_setclock(&attr, CLOCK_MONOTONIC);
200 1946 : if (!res)
201 1946 : res = pthread_cond_init(cond, &attr);
202 1946 : pthread_condattr_destroy(&attr);
203 1946 : return res;
204 : #else
205 : return pthread_cond_init(cond, NULL);
206 : #endif
207 : }
208 :
209 32 : int tds_raw_cond_timedwait(tds_condition *cond, tds_raw_mutex *mtx, int timeout_sec)
210 : {
211 : struct timespec ts;
212 :
213 32 : if (timeout_sec <= 0)
214 16 : return tds_raw_cond_wait(cond, mtx);
215 :
216 : #if defined(USE_COND_TIMEDWAIT_RELATIVE)
217 : ts.tv_sec = timeout_sec;
218 : ts.tv_nsec = 0;
219 : return pthread_cond_timedwait_relative_np(cond, mtx, &ts);
220 : #else
221 :
222 : # if defined(USE_MONOTONIC_CLOCK_IN_COND)
223 16 : clock_gettime(CLOCK_MONOTONIC, &ts);
224 : # elif defined(USE_CLOCK_GETTIME_IN_COND)
225 : clock_gettime(CLOCK_REALTIME, &ts);
226 : # elif defined(HAVE_GETTIMEOFDAY)
227 : do {
228 : struct timeval tv;
229 : gettimeofday(&tv, NULL);
230 : ts.tv_sec = tv.tv_sec;
231 : ts.tv_nsec = tv.tv_usec * 1000u;
232 : } while(0);
233 : # else
234 : # error No way to get a proper time!
235 : # endif
236 :
237 16 : ts.tv_sec += timeout_sec;
238 16 : return pthread_cond_timedwait(cond, mtx, &ts);
239 : #endif
240 : }
241 :
242 : #endif
|