1 /* -*-c++-*- OpenThreads library, Copyright (C) 2002 - 2007 The Open Thread Group
2 *
3 * This library is open source and may be redistributed and/or modified under
4 * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or
5 * (at your option) any later version. The full license is in LICENSE file
6 * included with this distribution, and on the openscenegraph.org website.
7 *
8 * This library is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * OpenSceneGraph Public License for more details.
12 */
13
14
15 //
16 // Win32Thread.c++
17 // ~~~~~~~~~~~
18 #include <memory>
19 #include <string>
20 #include <iostream>
21 #include <process.h>
22 #include <stdlib.h>
23
24 #if defined(_MSC_VER) && (_MSC_VER < 1300)
25 #ifdef __SGI_STL
26 using std::size_t;
27 #endif
28 #else
29 using std::size_t;
30 #endif
31
32 #if defined(_MSC_VER)
33 #pragma warning( disable : 4996 )
34 #endif
35
36 #include "Win32ThreadPrivateData.h"
37
38 struct Win32ThreadCanceled{};
39
40 using namespace OpenThreads;
41
cooperativeWait(HANDLE waitHandle,unsigned long timeout)42 DWORD OpenThreads::cooperativeWait(HANDLE waitHandle, unsigned long timeout){
43 Thread* current = Thread::CurrentThread();
44 DWORD dwResult ;
45 if(current)
46 {
47 HANDLE cancelHandle = static_cast<Win32ThreadPrivateData*>(current->getImplementation())->cancelEvent.get();
48 HANDLE handleSet[2] = {waitHandle, cancelHandle};
49
50 dwResult = WaitForMultipleObjects(2,handleSet,FALSE,timeout);
51 if(dwResult == WAIT_OBJECT_0 + 1 ) throw Win32ThreadCanceled();
52 }
53 else
54 {
55 dwResult = WaitForSingleObject(waitHandle,timeout);
56 }
57
58 return dwResult;
59 }
60
61 Win32ThreadPrivateData::TlsHolder Win32ThreadPrivateData::TLS;
62
~Win32ThreadPrivateData()63 Win32ThreadPrivateData::~Win32ThreadPrivateData()
64 {
65 }
66
67 //-----------------------------------------------------------------------------
68 // Initialize thread master priority level
69 //
70 Thread::ThreadPriority Thread::s_masterThreadPriority = Thread::THREAD_PRIORITY_DEFAULT;
71
72 bool Thread::s_isInitialized = false;
73 //-----------------------------------------------------------------------------
74 // Class to support some static methods necessary for pthread's to work
75 // correctly.
76 //
77 namespace OpenThreads {
78
79 class ThreadPrivateActions {
80 //-------------------------------------------------------------------------
81 // We're friendly to Thread, so it can issue the methods.
82 //
83 friend class Thread;
84 private:
85
86 //-------------------------------------------------------------------------
87 // Win32Threads standard start routine.
88 //
StartThread(void * data)89 static unsigned int __stdcall StartThread(void *data) {
90
91 Thread *thread = static_cast<Thread *>(data);
92
93 Win32ThreadPrivateData *pd =
94 static_cast<Win32ThreadPrivateData *>(thread->_prvData);
95
96 if (thread->_prvData==0) return 0;
97
98 TlsSetValue(Win32ThreadPrivateData::TLS.getId(), data);
99 //---------------------------------------------------------------------
100 // Set the proper scheduling priorities
101 //
102 SetThreadSchedulingParams(thread);
103
104 pd->isRunning = true;
105
106 // release the thread that created this thread.
107 pd->threadStartedBlock.release();
108
109 if (0 <= pd->cpunum)
110 thread->setProcessorAffinity(pd->cpunum);
111
112 try{
113 thread->run();
114 }
115 catch(Win32ThreadCanceled&)
116 {
117 // thread is canceled do cleanup
118 try {
119 thread->cancelCleanup();
120 } catch(...) { }
121 }
122 catch(...)
123 {
124 // abnormal termination but must be caught in win32 anyway
125 }
126
127 TlsSetValue(Win32ThreadPrivateData::TLS.getId(), 0);
128 pd->isRunning = false;
129
130 return 0;
131 };
132
133 //-------------------------------------------------------------------------
134 // Print information related to thread schduling parameters.
135 //
PrintThreadSchedulingInfo(Thread * thread)136 static void PrintThreadSchedulingInfo(Thread *thread) {
137
138 // Win32ThreadPrivateData *pd = static_cast<Win32ThreadPrivateData *>(thread->_prvData);
139
140 std::cout<<"Thread "<< thread <<" priority : ";
141
142 switch(thread->getSchedulePriority()) {
143 case Thread::THREAD_PRIORITY_MAX:
144 std::cout<<"MAXIMAL"<<std::endl;
145 break;
146 case Thread::THREAD_PRIORITY_HIGH:
147 std::cout<<"HIGH"<<std::endl;
148 break;
149 case Thread::THREAD_PRIORITY_DEFAULT:
150 case Thread::THREAD_PRIORITY_NOMINAL:
151 std::cout<<"NORMAL"<<std::endl;
152 break;
153 case Thread::THREAD_PRIORITY_LOW:
154 std::cout<<"LOW"<<std::endl;
155 break;
156 case Thread::THREAD_PRIORITY_MIN:
157 std::cout<<"MINIMAL"<<std::endl;
158 break;
159 }
160 }
161
162 //--------------------------------------------------------------------------
163 // Set thread scheduling parameters.
164 // Note that time-critical priority is omitted :
165 // 1) It's not sensible thing to do
166 // 2) there's no enum for that in Thread interface
167 // Also, on Windows, effective thread priority is :
168 // process priority (manipulated with Get/SetProrityClass) + thread priority (here).
169 //
170 //
SetThreadSchedulingParams(Thread * thread)171 static int SetThreadSchedulingParams(Thread *thread) {
172
173 Win32ThreadPrivateData *pd =
174 static_cast<Win32ThreadPrivateData *>(thread->_prvData);
175
176 int prio = THREAD_PRIORITY_NORMAL;
177
178 switch(thread->getSchedulePriority()) {
179 case Thread::THREAD_PRIORITY_MAX:
180 prio = THREAD_PRIORITY_HIGHEST;
181 break;
182 case Thread::THREAD_PRIORITY_HIGH:
183 prio = THREAD_PRIORITY_ABOVE_NORMAL;
184 break;
185 case Thread::THREAD_PRIORITY_NOMINAL:
186 prio = THREAD_PRIORITY_NORMAL;
187 break;
188 case Thread::THREAD_PRIORITY_LOW:
189 prio = THREAD_PRIORITY_BELOW_NORMAL;
190 break;
191 case Thread::THREAD_PRIORITY_MIN:
192 prio = THREAD_PRIORITY_IDLE;
193 break;
194 }
195
196 int status = SetThreadPriority( pd->tid.get(), prio);
197
198 if(getenv("OUTPUT_THREADLIB_SCHEDULING_INFO") != 0)
199 PrintThreadSchedulingInfo(thread);
200
201 return status!=0;
202 };
203 };
204 }
205
CurrentThread()206 Thread* Thread::CurrentThread()
207 {
208 DWORD ID = Win32ThreadPrivateData::TLS.getId();
209 if (ID == TLS_OUT_OF_INDEXES)
210 return 0;
211 return (Thread* )TlsGetValue(ID);
212 }
213
214 //----------------------------------------------------------------------------
215 //
216 // Description: Set the concurrency level (no-op)
217 //
218 // Use static public
219 //
SetConcurrency(int)220 int Thread::SetConcurrency(int) {
221 return -1;
222 }
223
224 //----------------------------------------------------------------------------
225 //
226 // Description: Get the concurrency level
227 //
228 // Use static public
229 //
GetConcurrency()230 int Thread::GetConcurrency() {
231 return -1;
232 }
233
Win32ThreadPrivateData()234 Win32ThreadPrivateData::Win32ThreadPrivateData()
235 {
236 stackSize = 0;
237 isRunning = false;
238 cancelMode = 0;
239 uniqueId = 0;
240 threadPriority = Thread::THREAD_PRIORITY_DEFAULT;
241 threadPolicy = Thread::THREAD_SCHEDULE_DEFAULT;
242 detached = false;
243 cancelEvent.set(CreateEvent(NULL,TRUE,FALSE,NULL));
244 cpunum = -1;
245 }
246
247 //----------------------------------------------------------------------------
248 //
249 // Description: Constructor
250 //
251 // Use: public.
252 //
Thread()253 Thread::Thread() {
254
255 // there's no need for this
256 // if(!s_isInitialized) Init();
257
258 Win32ThreadPrivateData *pd = new Win32ThreadPrivateData();
259
260 _prvData = static_cast<void *>(pd);
261 }
262
263
264 //----------------------------------------------------------------------------
265 //
266 // Description: Destructor
267 //
268 // Use: public.
269 //
~Thread()270 Thread::~Thread()
271 {
272 Win32ThreadPrivateData *pd = static_cast<Win32ThreadPrivateData *>(_prvData);
273
274 if(pd->isRunning)
275 {
276 std::cout<<"Error: Thread "<<this<<" still running in destructor"<<std::endl;
277 pd->cancelMode = 0;
278 cancel();
279
280 join();
281 }
282
283 delete pd;
284
285 _prvData = 0;
286 }
287 //-----------------------------------------------------------------------------
288 //
289 // Description: Initialize Threading
290 //
291 // Use: public.
292 //
Init()293 void Thread::Init() {
294 // if(s_isInitialized) return;
295 // s_masterThreadPriority = Thread::THREAD_PRIORITY_DEFAULT;
296 s_isInitialized = true;
297 }
298
299 //-----------------------------------------------------------------------------
300 //
301 // Description: Get a unique identifier for this thread.
302 //
303 // Use: public
304 //
getThreadId()305 int Thread::getThreadId() {
306 Win32ThreadPrivateData *pd = static_cast<Win32ThreadPrivateData *> (_prvData);
307 return pd->uniqueId;
308 }
309 //-----------------------------------------------------------------------------
310 //
311 // Description: Get the thread's process id
312 //
313 // Use: public
314 //
getProcessId()315 size_t Thread::getProcessId() {
316
317 return (size_t) GetCurrentProcessId();
318
319 }
320 //-----------------------------------------------------------------------------
321 //
322 // Description: Determine if the thread is running
323 //
324 // Use: public
325 //
isRunning()326 bool Thread::isRunning() {
327 Win32ThreadPrivateData *pd = static_cast<Win32ThreadPrivateData *> (_prvData);
328 return pd->isRunning;
329 }
330 //-----------------------------------------------------------------------------
331 //
332 // Description: Start the thread.
333 //
334 // Use: public
335 //
start()336 int Thread::start() {
337
338 Win32ThreadPrivateData *pd = static_cast<Win32ThreadPrivateData *> (_prvData);
339 //-------------------------------------------------------------------------
340 // Prohibit the stack size from being changed.
341 // (bb 5/13/2005) it actually doesn't matter.
342 // 1) usually setStackSize()/start() sequence is serialized.
343 // 2) if not than we're in trouble anyway - nothing is protected
344 // pd->stackSizeLocked = true;
345 unsigned int ID;
346
347 pd->threadStartedBlock.reset();
348
349 pd->tid.set( (void*)_beginthreadex(NULL,static_cast<unsigned>(pd->stackSize),ThreadPrivateActions::StartThread,static_cast<void *>(this),CREATE_SUSPENDED,&ID));
350 ResumeThread(pd->tid.get());
351
352 pd->uniqueId = (int)ID;
353
354 if(!pd->tid) {
355 return -1;
356 }
357
358 // wait till the thread has actually started.
359 pd->threadStartedBlock.block();
360
361 return 0;
362
363 }
364
startThread()365 int Thread::startThread()
366 {
367 if (_prvData) return start();
368 else return 0;
369 }
370
371 //-----------------------------------------------------------------------------
372 //
373 // Description: Join the thread.
374 //
375 // Use: public
376 //
join()377 int Thread::join() {
378 Win32ThreadPrivateData *pd = static_cast<Win32ThreadPrivateData *> (_prvData);
379 if( pd->detached )
380 return -1; // cannot wait for detached ;
381
382 if( WaitForSingleObject(pd->tid.get(),INFINITE) != WAIT_OBJECT_0)
383 return -1 ;
384
385 return 0;
386 }
387
388
389
detach()390 int Thread::detach()
391 {
392 Win32ThreadPrivateData *pd = static_cast<Win32ThreadPrivateData *> (_prvData);
393 pd->detached = true;
394 return 0;
395 }
396
397
398 //-----------------------------------------------------------------------------
399 //
400 // Description: Cancel the thread.
401 //
402 // Use: public
403 //
cancel()404 int Thread::cancel()
405 {
406 Win32ThreadPrivateData *pd = static_cast<Win32ThreadPrivateData *> (_prvData);
407
408 if (pd->isRunning)
409 {
410 if( pd->cancelMode == 2 )
411 return -1;
412
413 // signal all interested parties that we are going to exit
414 SetEvent(pd->cancelEvent.get());
415
416 // cancelMode == 1 (asynch)-> kill em
417 // cancelMode == 0 (deffered) -> wait a little then kill em
418
419 // if( (pd->cancelMode == 1) || (WaitForSingleObject(pd->tid,INFINITE)!=WAIT_OBJECT_0) )
420 if( pd->cancelMode == 1 )
421 {
422 // did not terminate cleanly force termination
423 pd->isRunning = false;
424 return TerminateThread(pd->tid.get(),(DWORD)-1);
425 }
426 }
427
428 return 0;
429 }
430
431
432
testCancel()433 int Thread::testCancel()
434 {
435 Win32ThreadPrivateData *pd = static_cast<Win32ThreadPrivateData *> (_prvData);
436
437 if(WaitForSingleObject(pd->cancelEvent.get(),0) != WAIT_OBJECT_0) return 0;
438
439 if(pd->cancelMode == 2)
440 return 0;
441
442 DWORD curr = GetCurrentThreadId();
443
444 if( pd->uniqueId != (int)curr )
445 return -1;
446
447 // pd->isRunning = false;
448 // ExitThread(0);
449 throw Win32ThreadCanceled();
450
451 // return 0;
452 }
453
454
455
456 //-----------------------------------------------------------------------------
457 //
458 // Description: Disable cancelibility
459 //
460 // Use: public
461 //
setCancelModeDisable()462 int Thread::setCancelModeDisable() {
463 Win32ThreadPrivateData *pd = static_cast<Win32ThreadPrivateData *> (_prvData);
464 pd->cancelMode = 2;
465 return 0;
466 }
467
468 //-----------------------------------------------------------------------------
469 //
470 // Description: set the thread to cancel immediately
471 //
472 // Use: public
473 //
setCancelModeAsynchronous()474 int Thread::setCancelModeAsynchronous() {
475 Win32ThreadPrivateData *pd = static_cast<Win32ThreadPrivateData *> (_prvData);
476 pd->cancelMode = 1;
477 return 0;
478 }
479
480 //-----------------------------------------------------------------------------
481 //
482 // Description: set the thread to cancel at the next convenient point.
483 //
484 // Use: public
485 //
setCancelModeDeferred()486 int Thread::setCancelModeDeferred() {
487 Win32ThreadPrivateData *pd = static_cast<Win32ThreadPrivateData *> (_prvData);
488 pd->cancelMode = 0;
489 return 0;
490 }
491
492 //-----------------------------------------------------------------------------
493 //
494 // Description: Set the thread's schedule priority (if able)
495 //
496 // Use: public
497 //
setSchedulePriority(ThreadPriority priority)498 int Thread::setSchedulePriority(ThreadPriority priority) {
499 Win32ThreadPrivateData *pd = static_cast<Win32ThreadPrivateData *> (_prvData);
500
501 pd->threadPriority = priority;
502
503 if(pd->isRunning)
504 return ThreadPrivateActions::SetThreadSchedulingParams(this);
505 else
506 return 0;
507 }
508
509
510 //-----------------------------------------------------------------------------
511 //
512 // Description: Get the thread's schedule priority (if able)
513 //
514 // Use: public
515 //
getSchedulePriority()516 int Thread::getSchedulePriority() {
517 Win32ThreadPrivateData *pd = static_cast<Win32ThreadPrivateData *> (_prvData);
518 return pd->threadPriority;
519 }
520
521 //-----------------------------------------------------------------------------
522 //
523 // Description: Set the thread's scheduling policy (if able)
524 //
525 // Use: public
526 //
setSchedulePolicy(ThreadPolicy policy)527 int Thread::setSchedulePolicy(ThreadPolicy policy) {
528 Win32ThreadPrivateData *pd = static_cast<Win32ThreadPrivateData *> (_prvData);
529
530 pd->threadPolicy = policy;
531
532 if(pd->isRunning)
533 return ThreadPrivateActions::SetThreadSchedulingParams(this);
534 else
535 return 0;
536 }
537
538 //-----------------------------------------------------------------------------
539 //
540 // Description: Set the thread's scheduling policy (if able)
541 //
542 // Use: public
543 //
getSchedulePolicy()544 int Thread::getSchedulePolicy() {
545 Win32ThreadPrivateData *pd = static_cast<Win32ThreadPrivateData *> (_prvData);
546 return pd->threadPolicy;
547 }
548
549 //-----------------------------------------------------------------------------
550 //
551 // Description: Set the thread's desired stack size
552 //
553 // Use: public
554 //
setStackSize(size_t stackSize)555 int Thread::setStackSize(size_t stackSize) {
556 Win32ThreadPrivateData *pd = static_cast<Win32ThreadPrivateData *> (_prvData);
557 if(pd->isRunning) return 13; // cannot set stack size of running thread return EACESS
558 pd->stackSize = stackSize;
559 return 0;
560 }
561 //-----------------------------------------------------------------------------
562 //
563 // Description: Get the thread's stack size.
564 //
565 // Use: public
566 //
getStackSize()567 size_t Thread::getStackSize() {
568 Win32ThreadPrivateData *pd = static_cast<Win32ThreadPrivateData *> (_prvData);
569 return pd->stackSize;
570 }
571
572 //-----------------------------------------------------------------------------
573 //
574 // Description: set processor affinity for the thread
575 //
576 // Use: public
577 //
setProcessorAffinity(unsigned int cpunum)578 int Thread::setProcessorAffinity( unsigned int cpunum )
579 {
580 Win32ThreadPrivateData *pd = static_cast<Win32ThreadPrivateData *> (_prvData);
581 pd->cpunum = cpunum;
582 if (!pd->isRunning)
583 return 0;
584
585 if (pd->tid.get() == INVALID_HANDLE_VALUE)
586 return -1;
587
588
589 DWORD affinityMask = 0x1 << cpunum ; // thread affinity mask
590 DWORD_PTR res =
591 SetThreadAffinityMask
592 (
593 pd->tid.get(), // handle to thread
594 affinityMask // thread affinity mask
595 );
596 /*
597 This one is funny.
598 This is "non-mandatory" affinity , windows will try to use dwIdealProcessor
599 whenever possible ( when Bill's account is over 50B, maybe :-) ).
600
601 DWORD SetThreadIdealProcessor(
602 HANDLE hThread, // handle to the thread
603 DWORD dwIdealProcessor // ideal processor number
604 );
605 */
606 // return value 1 means call is ignored ( 9x/ME/SE )
607 if( res == 1 ) return -1;
608 // return value 0 is failure
609 return (res == 0) ? GetLastError() : 0 ;
610 }
611
612 //-----------------------------------------------------------------------------
613 //
614 // Description: Print the thread's scheduling information to stdout.
615 //
616 // Use: public
617 //
printSchedulingInfo()618 void Thread::printSchedulingInfo() {
619 ThreadPrivateActions::PrintThreadSchedulingInfo(this);
620 }
621
622
623 //-----------------------------------------------------------------------------
624 //
625 // Description: Yield the processor
626 //
627 // Use: protected
628 //
629 #if _WIN32_WINNT < 0x0400 // simulate
SwitchToThread(void)630 int SwitchToThread (void)
631 {
632 ::Sleep(10);
633 return 0;
634 };
635 #endif
636
YieldCurrentThread()637 int Thread::YieldCurrentThread()
638 {
639 return SwitchToThread();
640 }
641
microSleep(unsigned int microsec)642 int Thread::microSleep(unsigned int microsec)
643 {
644 #if _WIN32_WINNT < 0x0400 // simulate
645 ::Sleep(microsec/1000);
646 return 0;
647 #else
648 HandleHolder sleepTimer(CreateWaitableTimer(NULL, TRUE, NULL));
649
650 if( !sleepTimer )
651 return -1;
652
653 LARGE_INTEGER t;
654
655 t.QuadPart= -(LONGLONG)microsec*10; // in 100ns units
656 // negative sign means relative,
657
658 if (!SetWaitableTimer(sleepTimer.get(), &t, 0, NULL, NULL, 0))
659 {
660 return -1;
661 }
662
663 // Wait for the timer.
664 if (WaitForSingleObject(sleepTimer.get(), INFINITE) != WAIT_OBJECT_0)
665 {
666 return -1;
667 }
668 return 0;
669 #endif
670 }
671
672
673 //-----------------------------------------------------------------------------
674 //
675 // Description: Get the number of processors
676 //
GetNumberOfProcessors()677 int OpenThreads::GetNumberOfProcessors()
678 {
679 SYSTEM_INFO sysInfo;
680 GetSystemInfo(&sysInfo);
681
682 return sysInfo.dwNumberOfProcessors;
683 }
684
SetProcessorAffinityOfCurrentThread(unsigned int cpunum)685 int OpenThreads::SetProcessorAffinityOfCurrentThread(unsigned int cpunum)
686 {
687 Thread::Init();
688
689 Thread* thread = Thread::CurrentThread();
690 if (thread)
691 {
692 return thread->setProcessorAffinity(cpunum);
693 }
694 else
695 {
696 // non op right now, needs implementation.
697 return -1;
698 }
699 }
700