Cosmetic: Cosmetic code corrections in QuickStep
[ode.git] / ode / src / threading_impl_win.h
blobf3cb489116c3ae0b3b68db6be2b4009815e6197e
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-2019 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 *************************************************************************/
28 * Threading Windows implementation for built-in threading support provider.
32 #ifndef _ODE_THREADING_IMPL_WIN_H_
33 #define _ODE_THREADING_IMPL_WIN_H_
36 #include <ode/common.h>
39 #if defined(_WIN32)
41 #if dBUILTIN_THREADING_IMPL_ENABLED
43 #if !defined(_WIN32_WINNT)
44 #define _WIN32_WINNT 0x0400
45 #endif
46 #include <windows.h>
49 #endif // #if dBUILTIN_THREADING_IMPL_ENABLED
52 #include "threading_impl_templates.h"
53 #include "threading_fake_sync.h"
54 #include "threading_atomics_provs.h"
57 #if dBUILTIN_THREADING_IMPL_ENABLED
59 /************************************************************************/
60 /* dxEventWakeup class implementation */
61 /************************************************************************/
63 class dxEventWakeup
65 public:
66 dxEventWakeup(): m_state_is_permanent(false), m_event_handle(NULL) {}
67 ~dxEventWakeup() { DoFinalizeObject(); }
69 bool InitializeObject() { return DoInitializeObject(); }
71 private:
72 bool DoInitializeObject();
73 void DoFinalizeObject();
75 public:
76 void ResetWakeup();
77 void WakeupAThread();
78 void WakeupAllThreads();
80 bool WaitWakeup(const dThreadedWaitTime *timeout_time_ptr);
82 private:
83 bool m_state_is_permanent;
84 HANDLE m_event_handle;
88 bool dxEventWakeup::DoInitializeObject()
90 dIASSERT(m_event_handle == NULL);
92 bool init_result = false;
96 HANDLE event_handle = CreateEvent(NULL, FALSE, FALSE, NULL);
97 if (event_handle == NULL)
99 break;
102 m_event_handle = event_handle;
103 init_result = true;
105 while (false);
107 return init_result;
110 void dxEventWakeup::DoFinalizeObject()
112 HANDLE event_handle = m_event_handle;
114 if (event_handle != NULL)
116 BOOL close_result = CloseHandle(event_handle);
117 dICHECK(close_result != FALSE);
119 m_event_handle = NULL;
124 void dxEventWakeup::ResetWakeup()
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;
129 BOOL event_set_result = ResetEvent(m_event_handle);
130 dICHECK(event_set_result);
133 void dxEventWakeup::WakeupAThread()
135 dIASSERT(!m_state_is_permanent); // Wakeup should not be used after permanent signal
137 BOOL event_reset_result = SetEvent(m_event_handle);
138 dICHECK(event_reset_result);
141 void dxEventWakeup::WakeupAllThreads()
143 // Order of assignment and setting event is important!
144 m_state_is_permanent = true;
146 BOOL event_set_result = SetEvent(m_event_handle);
147 dICHECK(event_set_result);
151 bool dxEventWakeup::WaitWakeup(const dThreadedWaitTime *timeout_time_ptr)
153 bool wait_result;
155 if (timeout_time_ptr == NULL)
157 DWORD event_wait_result = WaitForSingleObject(m_event_handle, INFINITE);
158 dICHECK(event_wait_result == WAIT_OBJECT_0);
160 wait_result = true;
162 else if (timeout_time_ptr->wait_sec == 0 && timeout_time_ptr->wait_nsec == 0)
164 DWORD event_wait_result = WaitForSingleObject(m_event_handle, 0);
166 wait_result = event_wait_result == WAIT_OBJECT_0;
167 dICHECK(wait_result || event_wait_result == WAIT_TIMEOUT);
169 else
171 dIASSERT(timeout_time_ptr->wait_nsec < 1000000000UL);
173 const DWORD max_wait_seconds_in_a_shot = ((INFINITE - 1) / 1000U) - 1;
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;
178 while (true)
180 if (timeout_seconds_remaining >= (time_t)max_wait_seconds_in_a_shot)
182 wait_timeout += max_wait_seconds_in_a_shot * 1000U;
183 timeout_seconds_remaining -= max_wait_seconds_in_a_shot;
185 else
187 wait_timeout += (DWORD)timeout_seconds_remaining * 1000U;
188 timeout_seconds_remaining = 0;
191 DWORD event_wait_result = WaitForSingleObject(m_event_handle, wait_timeout);
193 if (event_wait_result == WAIT_OBJECT_0)
195 wait_result = true;
196 break;
199 dICHECK(event_wait_result == WAIT_TIMEOUT);
201 if (timeout_seconds_remaining == 0)
203 wait_result = false;
204 break;
207 wait_timeout = 0;
211 if (wait_result && m_state_is_permanent)
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);
218 return wait_result;
222 /************************************************************************/
223 /* dxCriticalSectionMutex class implementation */
224 /************************************************************************/
226 class dxCriticalSectionMutex
228 public:
229 dxCriticalSectionMutex() { InitializeCriticalSection(&m_critical_section); }
230 ~dxCriticalSectionMutex() { DeleteCriticalSection(&m_critical_section); }
232 bool InitializeObject() { return true; }
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); }
239 private:
240 CRITICAL_SECTION m_critical_section;
244 #endif // #if dBUILTIN_THREADING_IMPL_ENABLED
247 /************************************************************************/
248 /* Self-threaded job list definition */
249 /************************************************************************/
251 typedef dxtemplateJobListContainer<dxFakeLull, dxFakeMutex, dxFakeAtomicsProvider> dxSelfThreadedJobListContainer;
252 typedef dxtemplateJobListSelfHandler<dxSelfWakeup, dxSelfThreadedJobListContainer> dxSelfThreadedJobListHandler;
253 typedef dxtemplateThreadingImplementation<dxSelfThreadedJobListContainer, dxSelfThreadedJobListHandler> dxSelfThreadedThreading;
256 #if dBUILTIN_THREADING_IMPL_ENABLED
258 /************************************************************************/
259 /* Multi-threaded job list definition */
260 /************************************************************************/
262 typedef dxtemplateJobListContainer<dxtemplateThreadedLull<dxEventWakeup, dxOUAtomicsProvider, false>, dxCriticalSectionMutex, dxOUAtomicsProvider> dxMultiThreadedJobListContainer;
263 typedef dxtemplateJobListThreadedHandler<dxEventWakeup, dxMultiThreadedJobListContainer> dxMultiThreadedJobListHandler;
264 typedef dxtemplateThreadingImplementation<dxMultiThreadedJobListContainer, dxMultiThreadedJobListHandler> dxMultiThreadedThreading;
267 #endif // #if dBUILTIN_THREADING_IMPL_ENABLED
270 #endif // #if defined(_WIN32)
273 #endif // #ifndef _ODE_THREADING_IMPL_WIN_H_