root/OpenSceneGraph/trunk/src/OpenThreads/sproc/SprocThread.c++ @ 9076

Revision 9076, 17.3 kB (checked in by robert, 6 years ago)

Warning fixes

  • Property svn:eol-style set to native
  • Property svn:executable set to *
  • Property svn:keywords set to Author Date Id Revision
Line 
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// SprocThread.c++ - C++ Thread class built on top of IRIX sproc.
17// ~~~~~~~~~~~~~~~
18
19#include <stdlib.h>
20#include <stdio.h>
21#include <sched.h>
22#include <sys/types.h>
23#include <sys/prctl.h>
24#include <sys/wait.h>
25#include <sys/sysmp.h>
26#include <signal.h>
27#include <unistd.h>
28#include <list>
29#include <OpenThreads/Thread>
30#include "SprocMutexPrivateData.h"
31#include "SprocThreadPrivateData.h"
32#include "SprocThreadPrivateActions.h"
33
34using namespace OpenThreads;
35
36extern int errno;
37const char *OPENTHREAD_VERSION_STRING = "Sproc Thread Model, v1.1 ("__DATE__" "__TIME__")";
38
39#ifdef DEBUG
40#define DPRINTF(arg) printf arg; fflush(stdout);
41#else
42#define DPRINTF(ARG)
43#endif
44
45static void sproc_dead_child_sig_handler(int sigid);
46
47//-----------------------------------------------------------------------------
48// Initialize the static unique ids.
49//
50int SprocThreadPrivateData::nextId = 0;
51
52//-----------------------------------------------------------------------------
53// Initialize thread master priority level
54//
55Thread::ThreadPriority Thread::s_masterThreadPriority =
56                                          Thread::THREAD_PRIORITY_MAX;
57
58bool Thread::s_isInitialized = false;
59
60std::list<Thread *> ThreadPrivateActions::s_threadList;
61
62void ThreadPrivateActions::ThreadCancelTest() {
63
64    OpenThreads::Thread *t = GetThread(getpid());
65
66    if(t != 0L) {
67
68        SprocThreadPrivateData *pd =
69            static_cast<SprocThreadPrivateData *>(t->_prvData);
70
71        bool *dieflag = GetDeathFlag(t);
72
73        if(*dieflag==false) return;
74
75        DPRINTF(("(SPROC THREAD) Thread Cancel Test Passed for %d\n",
76                 getpid()));
77
78        if(!pd->cancelFuncStack.empty())
79            pd->cancelFuncStack.top().routine(pd->cancelFuncStack.top().arg);
80
81        t->cancelCleanup();
82        pd->isRunning = false;
83
84        exit(1);
85    }
86}
87
88bool *ThreadPrivateActions::GetDeathFlag(Thread *thread) {
89
90    SprocThreadPrivateData *pd =
91        static_cast<SprocThreadPrivateData *>(thread->_prvData);
92
93    return (bool *)(&(pd->dieFlag));
94}
95
96Thread *ThreadPrivateActions::GetThread(pid_t thread_id) {
97
98    std::list<Thread *>::iterator iter;
99    for(iter = s_threadList.begin();
100        iter != s_threadList.end();
101        ++iter) {
102
103        Thread *t = *iter;
104        if(t->getProcessId() == thread_id) return t;
105
106    }
107
108    return 0L; // no thread found;
109
110};
111
112void ThreadPrivateActions::ThreadCancelHandler(int sigid) {
113
114    Thread *t = GetThread(getpid());
115
116    if(t != 0L) {
117
118        bool * dieflag = GetDeathFlag(t);
119
120        *dieflag = true;
121
122        sigset(SIGINT, SIG_DFL);
123        unblockproc(getpid());
124    }
125}
126
127//-------------------------------------------------------------------------
128// standard start routine.
129//
130void ThreadPrivateActions::StartThread(void *data)
131{
132
133    Thread *thread = static_cast<Thread *>(data);
134
135    if (thread->_prvData==0) return;
136
137    AddThread(thread);
138
139    *((Thread **)&PRDA->usr_prda) = (Thread *)thread;
140
141    SetThreadSchedulingParams(thread);
142
143    SprocThreadPrivateData *pd =
144        static_cast<SprocThreadPrivateData *>(thread->_prvData);
145
146    sigset(SIGINT, ThreadCancelHandler);
147
148    size_t defaultStackSize;
149    prctl(PR_GETSTACKSIZE, &defaultStackSize);
150
151    if(defaultStackSize < pd->stackSize) {
152        prctl(PR_SETSTACKSIZE, pd->stackSize);
153    }
154
155    prctl(PR_GETSTACKSIZE, &pd->stackSize);
156
157    pd->stackSizeLocked = true;
158
159    pd->isRunning = true;
160   
161    // release the thread that created this thread.
162    pd->threadStartedBlock.release();
163   
164    thread->run();
165
166    pd->isRunning = false;
167
168    RemoveThread(thread);
169
170    if(pd->detached == true ) {
171        exit(0);
172    }
173
174    return;
175
176};
177
178void ThreadPrivateActions::AddThread(Thread *thread) {
179
180    s_threadList.push_front(thread);
181
182    };
183
184void ThreadPrivateActions::RemoveThread(Thread *thread) {
185    s_threadList.remove(thread);
186};
187
188void ThreadPrivateActions::PrintThreadSchedulingInfo(Thread *thread) {
189
190    int status, my_policy, min_priority, max_priority;
191    struct sched_param my_param;
192
193    status = sched_getparam(thread->getProcessId(),
194                            &my_param);
195
196    my_policy = sched_getscheduler(thread->getProcessId());
197
198    if(status != 0 || my_policy == -1) {
199
200        printf("THREAD INFO (%d) : Get sched param: %s/%s\n",
201               unsigned int(thread->getProcessId()),
202               strerror(status),
203               strerror(errno));
204    } else {
205        printf(
206            "THREAD INFO (%d) : Thread running at %s / Priority: %d\n",
207            unsigned int(thread->getProcessId()),
208            (my_policy == SCHED_FIFO ? "SCHEDULE_FIFO"
209             : (my_policy == SCHED_RR ? "SCHEDULE_ROUND_ROBIN"
210                : (my_policy == SCHED_TS ? "SCHEDULE_TIME_SHARE"
211                   : (my_policy == SCHED_OTHER ? "SCHEDULE_OTHER"
212                      : "UNKNOWN")))),
213            my_param.sched_priority);
214
215        max_priority = sched_get_priority_max(my_policy);
216        min_priority = sched_get_priority_min(my_policy);
217
218        printf(
219            "THREAD INFO (%d) : Max priority: %d, Min priority: %d\n",
220            unsigned int(thread->getProcessId()),
221            max_priority, min_priority);
222
223    }
224
225}
226
227int ThreadPrivateActions::SetThreadSchedulingParams(Thread *thread) {
228
229    int status;
230
231    int th_priority;
232    int max_priority, nominal_priority, min_priority;
233
234    max_priority = 0;  // This is as high as we can regularly go.
235    min_priority = 20;
236    nominal_priority = (max_priority + min_priority)/2;
237
238    switch(thread->getSchedulePriority()) {
239
240    case Thread::THREAD_PRIORITY_MAX:
241        th_priority = max_priority;
242        break;
243
244    case Thread::THREAD_PRIORITY_HIGH:
245        th_priority = (max_priority + nominal_priority)/2;
246        break;
247
248    case Thread::THREAD_PRIORITY_NOMINAL:
249        th_priority = nominal_priority;
250        break;
251
252    case Thread::THREAD_PRIORITY_LOW:
253        th_priority = (min_priority + nominal_priority)/2;
254        break;
255
256    case Thread::THREAD_PRIORITY_MIN:
257        th_priority =  min_priority;
258        break;
259
260    default:
261        th_priority = max_priority;
262        break;
263
264    }
265
266    status = setpriority(PRIO_PROCESS, thread->getProcessId(),
267                         th_priority);
268
269    if(getenv("OUTPUT_THREADLIB_SCHEDULING_INFO") != 0)
270        PrintThreadSchedulingInfo(thread);
271
272    return status;
273};
274
275void ThreadPrivateActions::PushCancelFunction(void (*routine)(void *), void *arg) {
276
277    Thread *thread = GetThread(getpid());
278
279    if(thread != 0L) {
280        SprocThreadPrivateData *pd =
281            static_cast<SprocThreadPrivateData *>(thread->_prvData);
282
283        SprocThreadPrivateData::CancelFuncStruct c;
284
285        pd->cancelFuncStack.push(c);
286
287        SprocThreadPrivateData::CancelFuncStruct *cft = &(pd->cancelFuncStack.top());
288
289        cft->routine = routine;
290        cft->arg = arg;
291    }
292}
293
294void ThreadPrivateActions::PopCancelFunction() {
295
296    Thread *thread = GetThread(getpid());
297
298    if(thread != 0L) {
299
300        SprocThreadPrivateData *pd =
301            static_cast<SprocThreadPrivateData *>(thread->_prvData);
302
303        if(!pd->cancelFuncStack.empty())
304            pd->cancelFuncStack.pop();
305    }
306}
307
308//----------------------------------------------------------------------------
309//
310// Description: Set the concurrency level (no-op)
311//
312// Use static public
313//
314int Thread::SetConcurrency(int concurrencyLevel) {
315
316    return -1;
317
318};
319
320//----------------------------------------------------------------------------
321//
322// Description: Get the concurrency level
323//
324// Use static public
325//
326int Thread::GetConcurrency() {
327
328    return -1;
329
330};
331
332//----------------------------------------------------------------------------
333//
334// Decription: Constructor
335//
336// Use: public.
337//
338Thread::Thread() {
339
340    if(!s_isInitialized) Init();
341
342    SprocThreadPrivateData *pd = new SprocThreadPrivateData();
343    pd->stackSize = 128*1024;    // Set a minimum of 128K bytes if possible.
344    pd->stackSizeLocked = false;
345    pd->isRunning = false;
346    pd->isCanceled = false;
347    pd->idSet = false;
348    pd->cancelActive = true;
349    pd->detached = false;
350    pd->uniqueId = pd->nextId;
351    pd->nextId++;
352    pd->threadPriority = Thread::THREAD_PRIORITY_DEFAULT;
353    pd->threadPolicy = Thread::THREAD_SCHEDULE_DEFAULT;
354
355    _prvData = static_cast<void *>(pd);
356}
357
358//----------------------------------------------------------------------------
359//
360// Decription: Destructor
361//
362// Use: public.
363//
364Thread::~Thread()
365{
366    DPRINTF(("(SPROC THREAD) %s:%d, In OpenThreads::Thread destructor\n",
367        __FILE__, __LINE__));
368
369    SprocThreadPrivateData *pd =
370        static_cast<SprocThreadPrivateData *>(_prvData);
371
372    if(pd->isRunning)
373    {
374
375        DPRINTF(("(SPROC THREAD) %s:%d, about to kill OpenThreads::Thread\n",
376                 __FILE__, __LINE__));
377
378
379        //-------------------------------------------------------------------
380        //  Kill the process when the thread is destroyed.
381        //
382        cancel();
383
384        while (pd->isRunning == true) {
385            ::usleep(1);
386        }
387
388    }
389
390
391    DPRINTF(("(SPROC THREAD) %s:%d, Thread destroying private data.\n",
392             __FILE__, __LINE__));
393
394
395    delete pd;
396
397    _prvData = 0;
398}
399
400//-----------------------------------------------------------------------------
401//
402// Description: Initialize Threading
403//
404// Use: public.
405//
406void Thread::Init() {
407
408    if(s_isInitialized) return;
409
410#ifdef GP_DEBUG
411    fprintf(stderr, "%s\n", OPENTHREAD_VERSION_STRING);
412#endif
413
414    s_masterThreadPriority = Thread::THREAD_PRIORITY_MAX;
415
416    s_isInitialized = true;
417
418}
419
420//-----------------------------------------------------------------------------
421//
422// Description: Return a pointer to the currently executing thread
423//
424// Use: public
425//
426Thread *Thread::CurrentThread() {
427
428    return (*(Thread **)&PRDA->usr_prda);
429
430}
431
432//-----------------------------------------------------------------------------
433//
434// Description: Get a unique identifier for this thread.
435//
436// Use: public
437//
438int Thread::getThreadId() {
439
440    SprocThreadPrivateData *pd =
441        static_cast<SprocThreadPrivateData *> (_prvData);
442    return pd->uniqueId;
443}
444
445//-----------------------------------------------------------------------------
446//
447// Description: Get the thread's process id
448//
449// Use: public
450//
451size_t Thread::getProcessId() {
452
453    SprocThreadPrivateData *pd =
454        static_cast<SprocThreadPrivateData *> (_prvData);
455
456    if(pd->idSet == false) return getpid();
457
458    return (size_t)(pd->pid);
459
460}
461
462//-----------------------------------------------------------------------------
463//
464// Description: Determine if the thread is running
465//
466// Use: public
467//
468bool Thread::isRunning() {
469
470    SprocThreadPrivateData *pd =
471        static_cast<SprocThreadPrivateData *> (_prvData);
472
473    return pd->isRunning;
474
475}
476
477//-----------------------------------------------------------------------------
478//
479// Description: Start the thread.
480//
481// Use: public
482//
483int Thread::start() {
484
485    SprocThreadPrivateData *pd =
486        static_cast<SprocThreadPrivateData *> (_prvData);
487
488    pd->threadStartedBlock.reset();
489
490    int pid = sproc(ThreadPrivateActions::StartThread,
491                    PR_SALL,
492                    static_cast<void *>(this));
493
494    // PR_SADDR | PR_SDIR | PR_SUMASK | PR_SULIMIT | PR_SID,
495
496    if(pid < 0) {
497        perror("sproc encountered an error");
498        return -1;
499    }
500
501    //-----------------------------------------------------------------
502    // Make the thread runnable anywhere.
503    //
504    sysmp(MP_RUNANYWHERE_PID, pid);
505
506    pd->pid = pid;
507    pd->idSet = true;
508
509    // wait till the thread has actually started.
510    pd->threadStartedBlock.block();
511
512    return 0;
513
514}
515
516//-----------------------------------------------------------------------------
517//
518// Description: Alternate thread start routine.
519//
520// Use: public
521//
522int Thread::startThread()
523{
524    if (_prvData) return start();
525    else return 0;
526}
527
528//-----------------------------------------------------------------------------
529//
530// Description: Join the thread.
531//
532// Use: public
533//
534int Thread::detach() {
535
536    int status = 0;
537
538    SprocThreadPrivateData *pd =
539        static_cast<SprocThreadPrivateData *> (_prvData);
540
541    pd->detached=true;
542    sigset(SIGCLD, sproc_dead_child_sig_handler);
543
544    return status;
545
546}
547
548//-----------------------------------------------------------------------------
549//
550// Description: Join the thread.
551//
552// Use: public
553//
554int Thread::join() {
555
556    int status;
557
558    return waitpid((pid_t)getProcessId(), &status, 0);
559    //return status;
560
561}
562
563//-----------------------------------------------------------------------------
564//
565// Description: test the cancel state of the thread.
566//
567// Use: public
568//
569int Thread::testCancel() {
570
571    if(getpid() != getProcessId()) return -1;
572
573    ThreadPrivateActions::ThreadCancelTest();
574
575    return 0;
576}
577
578//-----------------------------------------------------------------------------
579//
580// Description: Cancel the thread.
581//
582// Use: public
583//
584int Thread::cancel() {
585
586    int status = 0;
587
588    SprocThreadPrivateData *pd =
589        static_cast<SprocThreadPrivateData *> (_prvData);
590
591    if(pd->cancelActive) {
592
593        status = kill((pid_t)getProcessId(), SIGINT);
594    };
595
596    return status;
597
598}
599
600//-----------------------------------------------------------------------------
601//
602// Description: Disable cancelibility
603//
604// Use: public
605//
606int Thread::setCancelModeDisable() {
607
608    SprocThreadPrivateData *pd =
609        static_cast<SprocThreadPrivateData *> (_prvData);
610
611    pd->cancelActive = false;
612
613    return 0;
614
615}
616
617//-----------------------------------------------------------------------------
618//
619// Description: set the thread to cancel immediately
620//
621// Use: public
622//
623int Thread::setCancelModeAsynchronous() {
624
625    SprocThreadPrivateData *pd =
626        static_cast<SprocThreadPrivateData *> (_prvData);
627
628    pd->cancelActive = true;
629
630    return 0;
631}
632
633//-----------------------------------------------------------------------------
634//
635// Description: set the thread to cancel at the next convienent point.
636//
637// Use: public
638//
639int Thread::setCancelModeDeferred() {
640
641    SprocThreadPrivateData *pd =
642        static_cast<SprocThreadPrivateData *> (_prvData);
643
644    pd->cancelActive = true;
645
646    return 0;
647
648}
649
650//-----------------------------------------------------------------------------
651//
652// Description: Set the thread's schedule priority (if able)
653//
654// Use: public
655//
656int Thread::setSchedulePriority(ThreadPriority priority) {
657
658    SprocThreadPrivateData *pd =
659        static_cast<SprocThreadPrivateData *> (_prvData);
660
661    pd->threadPriority = priority;
662
663    if(pd->isRunning)
664        return ThreadPrivateActions::SetThreadSchedulingParams(this);
665    else
666        return 0;
667
668}
669
670//-----------------------------------------------------------------------------
671//
672// Description: Get the thread's schedule priority (if able)
673//
674// Use: public
675//
676int Thread::getSchedulePriority() {
677
678    SprocThreadPrivateData *pd =
679        static_cast<SprocThreadPrivateData *> (_prvData);
680
681    return pd->threadPriority;
682
683}
684
685//-----------------------------------------------------------------------------
686//
687// Description: Set the thread's scheduling policy (if able)
688//
689// Use: public
690//
691int Thread::setSchedulePolicy(ThreadPolicy policy) {
692
693    return 0;
694
695}
696
697//-----------------------------------------------------------------------------
698//
699// Description: Set the thread's scheduling policy (if able)
700//
701// Use: public
702//
703int Thread::getSchedulePolicy() {
704
705    SprocThreadPrivateData *pd =
706        static_cast<SprocThreadPrivateData *> (_prvData);
707
708    return pd->threadPolicy;
709
710}
711
712//-----------------------------------------------------------------------------
713//
714// Description: Set the thread's desired stack size
715//
716// Use: public
717//
718int Thread::setStackSize(size_t stackSize) {
719
720    SprocThreadPrivateData *pd =
721        static_cast<SprocThreadPrivateData *> (_prvData);
722
723    if(pd->stackSizeLocked == true) return 13;  // EACESS
724
725    pd->stackSize = stackSize;
726
727    return 0;
728
729}
730
731//-----------------------------------------------------------------------------
732//
733// Description: Get the thread's stack size.
734//
735// Use: public
736//
737size_t Thread::getStackSize() {
738
739   SprocThreadPrivateData *pd =
740       static_cast<SprocThreadPrivateData *> (_prvData);
741
742   return pd->stackSize;
743
744}
745
746//-----------------------------------------------------------------------------
747//
748// Description:  Print the thread's scheduling information to stdout.
749//
750// Use: public
751//
752void Thread::printSchedulingInfo() {
753
754    ThreadPrivateActions::PrintThreadSchedulingInfo(this);
755
756}
757
758//-----------------------------------------------------------------------------
759//
760// Description:  Yield the processor
761//
762// Use: protected
763//
764int Thread::YieldCurrentThread() {
765
766    return sched_yield();
767
768}
769
770//-----------------------------------------------------------------------------
771// Description:  sleep
772//
773// Use: public
774//
775int Thread::microSleep(unsigned int microsec)
776{
777    return ::usleep(microsec);
778}
779
780static void sproc_dead_child_sig_handler(int sigid) {
781
782#ifdef DEBUG
783    int pid, status;
784    pid = wait(&status);
785    DPRINTF(("(SPROC THREAD) Dead Child Handler Caught Signal, Reaped %d\n",
786             pid));
787#endif
788
789    sigset(SIGCLD, sproc_dead_child_sig_handler);
790
791}
792
793int Thread::setProcessorAffinity( unsigned int cpunum )
794{
795    return -1;
796}
797
798//-----------------------------------------------------------------------------
799//
800// Description:  Get the number of processors
801//
802int OpenThreads::GetNumberOfProcessors()
803{
804    return 1;
805}
806
807int OpenThreads::SetProcessorAffinityOfCurrentThread(unsigned int cpunum)
808{
809    Thread::Init();
810
811    Thread* thread = Thread::CurrentThread();
812    if (thread)
813    {
814        return thread->setProcessorAffinity(cpunum);
815    }
816    else
817    {
818        // non op right now, needs implementation.
819        return -1;
820    }
821}
Note: See TracBrowser for help on using the browser.