2 * Copyright (c) 2005, Eric Crahen
4 * Permission is hereby granted, free of charge, to any person obtaining a copy
5 * of this software and associated documentation files (the "Software"), to deal
6 * in the Software without restriction, including without limitation the rights
7 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 * copies of the Software, and to permit persons to whom the Software is furnished
9 * to do so, subject to the following conditions:
11 * The above copyright notice and this permission notice shall be included in all
12 * copies or substantial portions of the Software.
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
18 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
19 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23 #include "ThreadOps.h"
24 #include "zthread/Runnable.h"
29 const ThreadOps
ThreadOps::INVALID(0);
32 * Detect OS at runtime and attempt to locate the SwitchToThread
33 * function, which will assist in making the spin lock implementation
34 * which use ThreadOps::yield() a bit fairer.
38 typedef BOOL (*Yield
)(void);
43 YieldOps() : _fnYield(NULL
) {
46 v
.dwOSVersionInfoSize
= sizeof(OSVERSIONINFO
);
48 if(::GetVersionEx(&v
) && (v
.dwPlatformId
== VER_PLATFORM_WIN32_NT
)) {
50 // Uses GetModuleHandle() so the reference count on the dll is
51 // not affected. There is a warning about race conditions involving
52 // this function being called as FreeLibrary() completes; however
53 // nearly all win32 applications load this particular and will keep it
54 // in memory until the process exits.
55 HINSTANCE hInst
= ::GetModuleHandle("Kernel32.dll");
57 _fnYield
= (Yield
)::GetProcAddress(hInst
, "SwitchToThread");
59 // REMIND: possibly need to use _T() macro for these strings
66 // Attempt to yield using the best function available
67 if(!_fnYield
|| !_fnYield())
76 bool ThreadOps::join(ThreadOps
* ops
) {
79 assert(ops
->_tid
!= 0);
80 assert(ops
->_hThread
!= NULL
);
82 if(::WaitForSingleObjectEx(ops
->_hThread
, INFINITE
, FALSE
) != WAIT_OBJECT_0
)
85 ::CloseHandle(ops
->_hThread
);
92 bool ThreadOps::yield() {
94 static YieldOps yielder
;
102 bool ThreadOps::setPriority(ThreadOps
* impl
, Priority p
) {
106 #if !defined(ZTHREAD_DISABLE_PRIORITY)
114 n
= THREAD_PRIORITY_BELOW_NORMAL
;
117 n
= THREAD_PRIORITY_ABOVE_NORMAL
;
121 n
= THREAD_PRIORITY_NORMAL
;
125 result
= (::SetThreadPriority(impl
->_hThread
, n
) != THREAD_PRIORITY_ERROR_RETURN
);
136 bool ThreadOps::getPriority(ThreadOps
* impl
, Priority
& p
) {
141 #if !defined(ZTHREAD_DISABLE_PRIORITY)
143 // Convert to one of the PRIORITY values
144 switch(::GetThreadPriority(impl
->_hThread
)) {
145 case THREAD_PRIORITY_ERROR_RETURN
:
147 case THREAD_PRIORITY_BELOW_NORMAL
:
150 case THREAD_PRIORITY_ABOVE_NORMAL
:
153 case THREAD_PRIORITY_NORMAL
:
165 bool ThreadOps::spawn(Runnable
* task
) {
168 #if defined(HAVE_BEGINTHREADEX)
169 _hThread
= (HANDLE
)::_beginthreadex(0, 0, &_dispatch
, task
, 0, (unsigned int*)&_tid
);
171 _hThread
= CreateThread(0, 0, (LPTHREAD_START_ROUTINE
)&_dispatch
, task
, 0, (DWORD
*)&_tid
);
174 return _hThread
!= NULL
;
178 unsigned int __stdcall
ThreadOps::_dispatch(void *arg
) {
180 Runnable
* task
= reinterpret_cast<Runnable
*>(arg
);
183 // Run the task from the correct context
187 #if defined(HAVE_BEGINTHREADEX)