MySQL 5.6.14 Source Code Document
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
my_wincond.c
1 /* Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved.
2 
3  This program is free software; you can redistribute it and/or modify
4  it under the terms of the GNU General Public License as published by
5  the Free Software Foundation; version 2 of the License.
6 
7  This program is distributed in the hope that it will be useful,
8  but WITHOUT ANY WARRANTY; without even the implied warranty of
9  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10  GNU General Public License for more details.
11 
12  You should have received a copy of the GNU General Public License
13  along with this program; if not, write to the Free Software
14  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
15 
16 /*****************************************************************************
17 ** The following is a simple implementation of posix conditions
18 *****************************************************************************/
19 #if defined(_WIN32)
20 
21 #undef SAFE_MUTEX /* Avoid safe_mutex redefinitions */
22 #include "mysys_priv.h"
23 #include <m_string.h>
24 #include <process.h>
25 #include <sys/timeb.h>
26 
27 
28 /*
29  Windows native condition variables. We use runtime loading / function
30  pointers, because they are not available on XP
31 */
32 
33 /* Prototypes and function pointers for condition variable functions */
34 typedef VOID (WINAPI * InitializeConditionVariableProc)
35  (PCONDITION_VARIABLE ConditionVariable);
36 
37 typedef BOOL (WINAPI * SleepConditionVariableCSProc)
38  (PCONDITION_VARIABLE ConditionVariable,
39  PCRITICAL_SECTION CriticalSection,
40  DWORD dwMilliseconds);
41 
42 typedef VOID (WINAPI * WakeAllConditionVariableProc)
43  (PCONDITION_VARIABLE ConditionVariable);
44 
45 typedef VOID (WINAPI * WakeConditionVariableProc)
46  (PCONDITION_VARIABLE ConditionVariable);
47 
48 static InitializeConditionVariableProc my_InitializeConditionVariable;
49 static SleepConditionVariableCSProc my_SleepConditionVariableCS;
50 static WakeAllConditionVariableProc my_WakeAllConditionVariable;
51 static WakeConditionVariableProc my_WakeConditionVariable;
52 
53 
59 static BOOL have_native_conditions= FALSE;
60 
61 
66 static void check_native_cond_availability(void)
67 {
68  HMODULE module= GetModuleHandle("kernel32");
69 
70  my_InitializeConditionVariable= (InitializeConditionVariableProc)
71  GetProcAddress(module, "InitializeConditionVariable");
72  my_SleepConditionVariableCS= (SleepConditionVariableCSProc)
73  GetProcAddress(module, "SleepConditionVariableCS");
74  my_WakeAllConditionVariable= (WakeAllConditionVariableProc)
75  GetProcAddress(module, "WakeAllConditionVariable");
76  my_WakeConditionVariable= (WakeConditionVariableProc)
77  GetProcAddress(module, "WakeConditionVariable");
78 
79  if (my_InitializeConditionVariable)
80  have_native_conditions= TRUE;
81 }
82 
83 
84 
89 static DWORD get_milliseconds(const struct timespec *abstime)
90 {
91  long long millis;
92  union ft64 now;
93 
94  if (abstime == NULL)
95  return INFINITE;
96 
97  GetSystemTimeAsFileTime(&now.ft);
98 
99  /*
100  Calculate time left to abstime
101  - subtract start time from current time(values are in 100ns units)
102  - convert to millisec by dividing with 10000
103  */
104  millis= (abstime->tv.i64 - now.i64) / 10000;
105 
106  /* Don't allow the timeout to be negative */
107  if (millis < 0)
108  return 0;
109 
110  /*
111  Make sure the calculated timeout does not exceed original timeout
112  value which could cause "wait for ever" if system time changes
113  */
114  if (millis > abstime->max_timeout_msec)
115  millis= abstime->max_timeout_msec;
116 
117  if (millis > UINT_MAX)
118  millis= UINT_MAX;
119 
120  return (DWORD)millis;
121 }
122 
123 
124 /*
125  Old (pre-vista) implementation using events
126 */
127 
128 static int legacy_cond_init(pthread_cond_t *cond, const pthread_condattr_t *attr)
129 {
130  cond->waiting= 0;
131  InitializeCriticalSection(&cond->lock_waiting);
132 
133  cond->events[SIGNAL]= CreateEvent(NULL, /* no security */
134  FALSE, /* auto-reset event */
135  FALSE, /* non-signaled initially */
136  NULL); /* unnamed */
137 
138  /* Create a manual-reset event. */
139  cond->events[BROADCAST]= CreateEvent(NULL, /* no security */
140  TRUE, /* manual-reset */
141  FALSE, /* non-signaled initially */
142  NULL); /* unnamed */
143 
144 
145  cond->broadcast_block_event= CreateEvent(NULL, /* no security */
146  TRUE, /* manual-reset */
147  TRUE, /* signaled initially */
148  NULL); /* unnamed */
149 
150  if( cond->events[SIGNAL] == NULL ||
151  cond->events[BROADCAST] == NULL ||
152  cond->broadcast_block_event == NULL )
153  return ENOMEM;
154  return 0;
155 }
156 
157 
158 static int legacy_cond_destroy(pthread_cond_t *cond)
159 {
160  DeleteCriticalSection(&cond->lock_waiting);
161 
162  if (CloseHandle(cond->events[SIGNAL]) == 0 ||
163  CloseHandle(cond->events[BROADCAST]) == 0 ||
164  CloseHandle(cond->broadcast_block_event) == 0)
165  return EINVAL;
166  return 0;
167 }
168 
169 
170 static int legacy_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex,
171  struct timespec *abstime)
172 {
173  int result;
174  DWORD timeout;
175 
176  timeout= get_milliseconds(abstime);
177  /*
178  Block access if previous broadcast hasn't finished.
179  This is just for safety and should normally not
180  affect the total time spent in this function.
181  */
182  WaitForSingleObject(cond->broadcast_block_event, INFINITE);
183 
184  EnterCriticalSection(&cond->lock_waiting);
185  cond->waiting++;
186  LeaveCriticalSection(&cond->lock_waiting);
187 
188  LeaveCriticalSection(mutex);
189  result= WaitForMultipleObjects(2, cond->events, FALSE, timeout);
190 
191  EnterCriticalSection(&cond->lock_waiting);
192  cond->waiting--;
193 
194  if (cond->waiting == 0)
195  {
196  /*
197  We're the last waiter to be notified or to stop waiting, so
198  reset the manual event.
199  */
200  /* Close broadcast gate */
201  ResetEvent(cond->events[BROADCAST]);
202  /* Open block gate */
203  SetEvent(cond->broadcast_block_event);
204  }
205  LeaveCriticalSection(&cond->lock_waiting);
206 
207  EnterCriticalSection(mutex);
208 
209  return result == WAIT_TIMEOUT ? ETIMEDOUT : 0;
210 }
211 
212 static int legacy_cond_signal(pthread_cond_t *cond)
213 {
214  EnterCriticalSection(&cond->lock_waiting);
215 
216  if(cond->waiting > 0)
217  SetEvent(cond->events[SIGNAL]);
218 
219  LeaveCriticalSection(&cond->lock_waiting);
220 
221  return 0;
222 }
223 
224 
225 static int legacy_cond_broadcast(pthread_cond_t *cond)
226 {
227  EnterCriticalSection(&cond->lock_waiting);
228  /*
229  The mutex protect us from broadcasting if
230  there isn't any thread waiting to open the
231  block gate after this call has closed it.
232  */
233  if(cond->waiting > 0)
234  {
235  /* Close block gate */
236  ResetEvent(cond->broadcast_block_event);
237  /* Open broadcast gate */
238  SetEvent(cond->events[BROADCAST]);
239  }
240 
241  LeaveCriticalSection(&cond->lock_waiting);
242 
243  return 0;
244 }
245 
246 
247 /*
248  Posix API functions. Just choose between native and legacy implementation.
249 */
250 
251 int pthread_cond_init(pthread_cond_t *cond, const pthread_condattr_t *attr)
252 {
253  /*
254  Once initialization is used here rather than in my_init(), to
255  1) avoid my_init() pitfalls- undefined order in which initialization should
256  run
257  2) be potentially useful C++ (in static constructors that run before main())
258  3) just to simplify the API.
259  Also, the overhead of my_pthread_once is very small.
260  */
261  static my_pthread_once_t once_control= MY_PTHREAD_ONCE_INIT;
262  my_pthread_once(&once_control, check_native_cond_availability);
263 
264  if (have_native_conditions)
265  {
266  my_InitializeConditionVariable(&cond->native_cond);
267  return 0;
268  }
269  else
270  return legacy_cond_init(cond, attr);
271 }
272 
273 
274 int pthread_cond_destroy(pthread_cond_t *cond)
275 {
276  if (have_native_conditions)
277  return 0; /* no destroy function */
278  else
279  return legacy_cond_destroy(cond);
280 }
281 
282 
283 int pthread_cond_broadcast(pthread_cond_t *cond)
284 {
285  if (have_native_conditions)
286  {
287  my_WakeAllConditionVariable(&cond->native_cond);
288  return 0;
289  }
290  else
291  return legacy_cond_broadcast(cond);
292 }
293 
294 
295 int pthread_cond_signal(pthread_cond_t *cond)
296 {
297  if (have_native_conditions)
298  {
299  my_WakeConditionVariable(&cond->native_cond);
300  return 0;
301  }
302  else
303  return legacy_cond_signal(cond);
304 }
305 
306 
307 int pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex,
308  struct timespec *abstime)
309 {
310  if (have_native_conditions)
311  {
312  DWORD timeout= get_milliseconds(abstime);
313  if (!my_SleepConditionVariableCS(&cond->native_cond, mutex, timeout))
314  return ETIMEDOUT;
315  return 0;
316  }
317  else
318  return legacy_cond_timedwait(cond, mutex, abstime);
319 }
320 
321 
322 int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex)
323 {
324  return pthread_cond_timedwait(cond, mutex, NULL);
325 }
326 
327 
328 int pthread_attr_init(pthread_attr_t *connect_att)
329 {
330  connect_att->dwStackSize = 0;
331  connect_att->dwCreatingFlag = 0;
332  return 0;
333 }
334 
335 int pthread_attr_setstacksize(pthread_attr_t *connect_att,DWORD stack)
336 {
337  connect_att->dwStackSize=stack;
338  return 0;
339 }
340 
341 int pthread_attr_destroy(pthread_attr_t *connect_att)
342 {
343  memset(connect_att, 0, sizeof(*connect_att));
344  return 0;
345 }
346 
347 /****************************************************************************
348 ** Fix localtime_r() to be a bit safer
349 ****************************************************************************/
350 
351 struct tm *localtime_r(const time_t *timep,struct tm *tmp)
352 {
353  if (*timep == (time_t) -1) /* This will crash win32 */
354  {
355  memset(tmp, 0, sizeof(*tmp));
356  }
357  else
358  {
359  struct tm *res=localtime(timep);
360  if (!res) /* Wrong date */
361  {
362  memset(tmp, 0, sizeof(*tmp)); /* Keep things safe */
363  return 0;
364  }
365  *tmp= *res;
366  }
367  return tmp;
368 }
369 #endif /* __WIN__ */