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