1 /*************************************************************************
3 * Open Dynamics Engine, Copyright (C) 2001-2003 Russell L. Smith. *
4 * All rights reserved. Email: russ@q12.org Web: www.q12.org *
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") *
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 *
17 * (2) The BSD-style license that is included with this library in *
18 * the file LICENSE-BSD.TXT. *
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. *
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>
41 #if dBUILTIN_THREADING_IMPL_ENABLED
43 #if !defined(_WIN32_WINNT)
44 #define _WIN32_WINNT 0x0400
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 /************************************************************************/
66 dxEventWakeup(): m_state_is_permanent(false), m_event_handle(NULL
) {}
67 ~dxEventWakeup() { DoFinalizeObject(); }
69 bool InitializeObject() { return DoInitializeObject(); }
72 bool DoInitializeObject();
73 void DoFinalizeObject();
78 void WakeupAllThreads();
80 bool WaitWakeup(const dThreadedWaitTime
*timeout_time_ptr
);
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
)
102 m_event_handle
= event_handle
;
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
)
155 if (timeout_time_ptr
== NULL
)
157 DWORD event_wait_result
= WaitForSingleObject(m_event_handle
, INFINITE
);
158 dICHECK(event_wait_result
== WAIT_OBJECT_0
);
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
);
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;
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
;
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
)
199 dICHECK(event_wait_result
== WAIT_TIMEOUT
);
201 if (timeout_seconds_remaining
== 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
);
222 /************************************************************************/
223 /* dxCriticalSectionMutex class implementation */
224 /************************************************************************/
226 class dxCriticalSectionMutex
229 dxCriticalSectionMutex() { InitializeCriticalSection(&m_critical_section
); }
230 ~dxCriticalSectionMutex() { DeleteCriticalSection(&m_critical_section
); }
232 bool InitializeObject() { return true; }
235 void LockMutex() { EnterCriticalSection(&m_critical_section
); }
236 bool TryLockMutex() { return TryEnterCriticalSection(&m_critical_section
) != FALSE
; }
237 void UnlockMutex() { LeaveCriticalSection(&m_critical_section
); }
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_