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