Open Dynamics Engine
threading_impl_win.h
1 /*************************************************************************
2  * *
3  * Open Dynamics Engine, Copyright (C) 2001-2003 Russell L. Smith. *
4  * All rights reserved. Email: russ@q12.org Web: www.q12.org *
5  * *
6  * Threading Windows implementation file. *
7  * Copyright (C) 2011-2012 Oleh Derevenko. All rights reserved. *
8  * e-mail: odar@eleks.com (change all "a" to "e") *
9  * *
10  * This library is free software; you can redistribute it and/or *
11  * modify it under the terms of EITHER: *
12  * (1) The GNU Lesser General Public License as published by the Free *
13  * Software Foundation; either version 2.1 of the License, or (at *
14  * your option) any later version. The text of the GNU Lesser *
15  * General Public License is included with this library in the *
16  * file LICENSE.TXT. *
17  * (2) The BSD-style license that is included with this library in *
18  * the file LICENSE-BSD.TXT. *
19  * *
20  * This library is distributed in the hope that it will be useful, *
21  * but WITHOUT ANY WARRANTY; without even the implied warranty of *
22  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files *
23  * LICENSE.TXT and LICENSE-BSD.TXT for more details. *
24  * *
25  *************************************************************************/
26 
27 /*
28  * Threading Windows implementation for built-in threading support provider.
29  */
30 
31 
32 #ifndef _ODE_THREADING_IMPL_WIN_H_
33 #define _ODE_THREADING_IMPL_WIN_H_
34 
35 
36 #include <ode/common.h>
37 
38 
39 #if defined(_WIN32)
40 
41 #if dBUILTIN_THREADING_IMPL_ENABLED
42 
43 #if !defined(_WIN32_WINNT)
44 #define _WIN32_WINNT 0x0400
45 #endif
46 #include <windows.h>
47 
48 
49 #endif // #if dBUILTIN_THREADING_IMPL_ENABLED
50 
51 
52 #include "threading_impl_templates.h"
53 #include "threading_fake_sync.h"
54 #include "threading_atomics_provs.h"
55 
56 
57 #if dBUILTIN_THREADING_IMPL_ENABLED
58 
59 /************************************************************************/
60 /* dxEventWakeup class implementation */
61 /************************************************************************/
62 
63 class dxEventWakeup
64 {
65 public:
66  dxEventWakeup(): m_state_is_permanent(false), m_event_handle(NULL) {}
67  ~dxEventWakeup() { DoFinalizeObject(); }
68 
69  bool InitializeObject() { return DoInitializeObject(); }
70 
71 private:
72  bool DoInitializeObject();
73  void DoFinalizeObject();
74 
75 public:
76  void ResetWakeup();
77  void WakeupAThread();
78  void WakeupAllThreads();
79 
80  bool WaitWakeup(const dThreadedWaitTime *timeout_time_ptr);
81 
82 private:
83  bool m_state_is_permanent;
84  HANDLE m_event_handle;
85 };
86 
87 
88 bool dxEventWakeup::DoInitializeObject()
89 {
90  dIASSERT(m_event_handle == NULL);
91 
92  bool init_result = false;
93 
94  do
95  {
96  HANDLE event_handle = CreateEvent(NULL, FALSE, FALSE, NULL);
97  if (event_handle == NULL)
98  {
99  break;
100  }
101 
102  m_event_handle = event_handle;
103  init_result = true;
104  }
105  while (false);
106 
107  return init_result;
108 }
109 
110 void dxEventWakeup::DoFinalizeObject()
111 {
112  HANDLE event_handle = m_event_handle;
113 
114  if (event_handle != NULL)
115  {
116  BOOL close_result = CloseHandle(event_handle);
117  dICHECK(close_result != FALSE);
118 
119  m_event_handle = NULL;
120  }
121 }
122 
123 
124 void dxEventWakeup::ResetWakeup()
125 {
126  // Order of assignment and resetting event is not important but it is preferable to be performed this way.
127  m_state_is_permanent = false;
128 
129  BOOL event_set_result = ResetEvent(m_event_handle);
130  dICHECK(event_set_result);
131 }
132 
133 void dxEventWakeup::WakeupAThread()
134 {
135  dIASSERT(!m_state_is_permanent); // Wakeup should not be used after permanent signal
136 
137  BOOL event_reset_result = SetEvent(m_event_handle);
138  dICHECK(event_reset_result);
139 }
140 
141 void dxEventWakeup::WakeupAllThreads()
142 {
143  // Order of assignment and setting event is important!
144  m_state_is_permanent = true;
145 
146  BOOL event_set_result = SetEvent(m_event_handle);
147  dICHECK(event_set_result);
148 }
149 
150 
151 bool dxEventWakeup::WaitWakeup(const dThreadedWaitTime *timeout_time_ptr)
152 {
153  bool wait_result;
154 
155  if (timeout_time_ptr == NULL)
156  {
157  DWORD event_wait_result = WaitForSingleObject(m_event_handle, INFINITE);
158  dICHECK(event_wait_result == WAIT_OBJECT_0);
159 
160  wait_result = true;
161  }
162  else if (timeout_time_ptr->wait_sec == 0 && timeout_time_ptr->wait_nsec == 0)
163  {
164  DWORD event_wait_result = WaitForSingleObject(m_event_handle, 0);
165 
166  wait_result = event_wait_result == WAIT_OBJECT_0;
167  dICHECK(wait_result || event_wait_result == WAIT_TIMEOUT);
168  }
169  else
170  {
171  dIASSERT(timeout_time_ptr->wait_nsec < 1000000000UL);
172 
173  const DWORD max_wait_seconds_in_a_shot = ((INFINITE - 1) / 1000U) - 1;
174 
175  time_t timeout_seconds_remaining = timeout_time_ptr->wait_sec;
176  DWORD wait_timeout = timeout_time_ptr->wait_nsec != 0 ? ((timeout_time_ptr->wait_nsec + 999999UL) / 1000000UL) : 0;
177 
178  while (true)
179  {
180  if (timeout_seconds_remaining >= (time_t)max_wait_seconds_in_a_shot)
181  {
182  wait_timeout += max_wait_seconds_in_a_shot * 1000U;
183  timeout_seconds_remaining -= max_wait_seconds_in_a_shot;
184  }
185  else
186  {
187  wait_timeout += (DWORD)timeout_seconds_remaining * 1000U;
188  timeout_seconds_remaining = 0;
189  }
190 
191  DWORD event_wait_result = WaitForSingleObject(m_event_handle, wait_timeout);
192 
193  if (event_wait_result == WAIT_OBJECT_0)
194  {
195  wait_result = true;
196  break;
197  }
198 
199  dICHECK(event_wait_result == WAIT_TIMEOUT);
200 
201  if (timeout_seconds_remaining == 0)
202  {
203  wait_result = false;
204  break;
205  }
206 
207  wait_timeout = 0;
208  }
209  }
210 
211  if (wait_result && m_state_is_permanent)
212  {
213  // Since event is automatic it is necessary to set it back for the upcoming waiters
214  BOOL event_set_result = SetEvent(m_event_handle);
215  dICHECK(event_set_result);
216  }
217 
218  return wait_result;
219 }
220 
221 
222 /************************************************************************/
223 /* dxCriticalSectionMutex class implementation */
224 /************************************************************************/
225 
226 class dxCriticalSectionMutex
227 {
228 public:
229  dxCriticalSectionMutex() { InitializeCriticalSection(&m_critical_section); }
230  ~dxCriticalSectionMutex() { DeleteCriticalSection(&m_critical_section); }
231 
232  bool InitializeObject() { return true; }
233 
234 public:
235  void LockMutex() { EnterCriticalSection(&m_critical_section); }
236  bool TryLockMutex() { return TryEnterCriticalSection(&m_critical_section) != FALSE; }
237  void UnlockMutex() { LeaveCriticalSection(&m_critical_section); }
238 
239 private:
240  CRITICAL_SECTION m_critical_section;
241 };
242 
243 
244 #endif // #if dBUILTIN_THREADING_IMPL_ENABLED
245 
246 
247 /************************************************************************/
248 /* Self-threaded job list definition */
249 /************************************************************************/
250 
254 
255 
256 #if dBUILTIN_THREADING_IMPL_ENABLED
257 
258 /************************************************************************/
259 /* Multi-threaded job list definition */
260 /************************************************************************/
261 
262 typedef dxtemplateJobListContainer<dxtemplateThreadedLull<dxEventWakeup, dxOUAtomicsProvider, false>, dxCriticalSectionMutex, dxOUAtomicsProvider> dxMultiThreadedJobListContainer;
263 typedef dxtemplateJobListThreadedHandler<dxEventWakeup, dxMultiThreadedJobListContainer> dxMultiThreadedJobListHandler;
265 
266 
267 #endif // #if dBUILTIN_THREADING_IMPL_ENABLED
268 
269 
270 #endif // #if defined(_WIN32)
271 
272 
273 #endif // #ifndef _ODE_THREADING_IMPL_WIN_H_
Definition: threading_impl_templates.h:209
Definition: threading_impl_templates.h:444
Definition: threading_impl_templates.h:366
Definition: threading.h:154