source: Sophya/trunk/SophyaExt/JThreadsC++/JTCSrc/Thread.cpp@ 2937

Last change on this file since 2937 was 1016, checked in by ansari, 25 years ago

Creation du module JThreadsC++, importation du code des classes
de Thread a la Java de Object Oriented Concepts Inc - Reza 19/5/2000

File size: 33.0 KB
Line 
1// **********************************************************************
2//
3// Copyright (c) 2000
4// Object Oriented Concepts, Inc.
5// Billerica, MA, USA
6//
7// All Rights Reserved
8//
9// **********************************************************************
10
11#include <JTC/Types.h>
12#include <JTC/Syscall.h>
13#include <JTC/Mutex.h>
14#include <JTC/Event.h>
15#include <JTC/Handle.h>
16#include <JTC/HandleI.h>
17#include <JTC/Cond.h>
18#include <JTC/Thread.h>
19#include <JTC/Monitor.h>
20#include <JTC/Sync.h>
21#include <JTC/Exception.h>
22#include <JTC/ThreadGroup.h>
23#include <JTC/TSS.h>
24#include <JTC/Runnable.h>
25
26#include <TSSManager.h>
27
28#include <string.h>
29#include <stdlib.h>
30#include <errno.h>
31#include <assert.h>
32
33#if defined(HAVE_POSIX_THREADS) || defined(HAVE_DCE_THREADS)
34# ifdef HAVE_SCHED_H
35# include <sched.h>
36# else
37# ifdef HAVE_SYS_SCHED_H
38# include <sys/sched.h>
39# endif
40# endif
41# include <unistd.h>
42#endif
43
44#if defined(HAVE_POSIX_THREADS)
45# include <sys/time.h>
46# include <sys/types.h>
47#endif
48
49#if defined(WIN32)
50# include <sys/timeb.h>
51# include <process.h>
52#endif
53
54#if defined(HAVE_EXCEPTION)
55# include <exception>
56#endif
57
58#ifdef HAVE_STD_IOSTREAM
59using namespace std;
60#endif
61
62#if defined(HAVE_EXCEPTION_H)
63# include <exception.h>
64#elif defined(HAVE_UNEXPECTED_H)
65# include <unexpected.h>
66#endif
67
68#ifdef HAVE_TERMINATE_H
69# include <terminate.h>
70#endif
71
72#ifndef HAVE_NO_EXPLICIT_TEMPLATES
73template class JTCHandleT<JTCThread>;
74#else
75# ifdef HAVE_PRAGMA_DEFINE
76# pragma define(JTCHandleT<JTCThread>)
77# endif
78#endif
79
80#ifndef HAVE_NO_EXPLICIT_TEMPLATES
81template class JTCHandleT<JTCRunnable>;
82#else
83# ifdef HAVE_PRAGMA_DEFINE
84# pragma define(JTCHandleT<JTCRunnable>)
85# endif
86#endif
87
88//
89// This class keeps track of the number of running threads. When the
90// last JTCInititalize object is destroyed it waits for all running
91// threads to terminate.
92//
93class JTCThreadCounter : public JTCMonitor
94{
95 int threads_;
96public:
97 JTCThreadCounter()
98 : threads_(0)
99 {
100 }
101
102 //
103 // Called when each new thread is started.
104 //
105 void threadStart()
106 {
107 JTCSynchronized guard(*this, true);
108 ++threads_;
109 }
110
111 //
112 // Called when each thread is terminated. If there are no more
113 // running threads then notify any threads waiting in waitZero.
114 //
115 void threadEnd()
116 {
117 JTCSynchronized guard(*this, true);
118 --threads_;
119 if(threads_ == 0)
120 {
121 notify();
122 }
123 }
124
125 //
126 // Wait for all threads to terminate.
127 //
128 void waitZero()
129 {
130 JTCSynchronized guard(*this, true);
131 while(threads_ > 0)
132 {
133 try
134 {
135 wait();
136 }
137 catch(const JTCInterruptedException&)
138 {
139 }
140 }
141 }
142};
143
144//
145// Global instance JTCThreadCounter.
146//
147static JTCThreadCounter* threadCounter = 0;
148
149static size_t initialStackSize = 0;
150
151#if defined(__sgi) && !defined(__GNUC__)
152static long
153_jtc_threadId()
154{
155 return pthread_self();
156}
157#endif
158
159//
160// This is used as a hook from the WIN32 threading library, and the
161// POSIX threading library into JTC. It's better not to use a static
162// member of the JTCThread class since they are not guaranteed to be C
163// callable.
164//
165#ifndef WIN32
166extern "C"
167#else
168static
169#endif
170void*
171_JTC_threadAdapter(void* arg)
172{
173 //
174 // Ensure that unexpected exceptions cause an abort.
175 //
176 set_terminate(abort);
177 set_unexpected(abort);
178
179#if defined(__sgi) && !defined(__GNUC__)
180 //
181 // SGI needs this to handle multiple exceptions in threads.
182 //
183 set_thread_id_function(_jtc_threadId);
184#endif
185
186 //
187 // The arg is a pointer to the JTCThread class.
188 //
189 JTCThread* thr = (JTCThread*)arg;
190 try
191 {
192 //
193 // Invoke the _JTC_startThreadHook.
194 //
195 thr -> _JTC_startThreadHook();
196 }
197 catch(...)
198 {
199 }
200
201 try
202 {
203 //
204 // Call the exit method of the thread.
205 //
206 thr -> _JTC_exit();
207 }
208 catch(...)
209 {
210 }
211
212 //
213 //
214 // No return value.
215 //
216 return 0;
217}
218
219// ----------------------------------------------------------------------
220// JTCThread private member implementation
221// ----------------------------------------------------------------------
222
223//
224// TSS key. This key is used to store a pointer to the JTCThread
225// object.
226//
227JTCThreadKey JTCThread::thrKey_;
228#if defined(HAVE_POSIX_THREADS) || defined(HAVE_DCE_THREADS)
229JTCAttrHook JTCThread::attrHook_ = 0;
230#endif
231
232#ifdef HAVE_JTC_STOP
233//
234// Check the running status of this thread. This determines whether
235// the thread needs to be suspended, or terminated.
236//
237void
238JTCThread::_checkRunningStatus() const
239{
240 JTCThread* This = (JTCThread*)this;
241 JTCSynchronized guard(resumeMut_);
242
243 //
244 // If this thread is the same as the current thread, and the
245 // thread isn't dead yet then check suspended, and terminated.
246 //
247 if(getId() == JTCThreadId::self() && state_ != JTCThread::Dead)
248 {
249 //
250 // Thread suspended?
251 //
252 if(This -> suspended_)
253 {
254 //
255 // If so then wait for the resume condition variable to be
256 // signalled.
257 //
258 This -> resumeCond_.wait();
259 }
260
261 //
262 // Thread terminated, but ThreadDeath exception not thrown
263 // yet?
264 //
265 if(This -> terminated_ == terminated)
266 {
267 //
268 // If so note that the ThreadDeath exception has been
269 // thrown, and throw the exception.
270 //
271 This -> terminated_ = throw_termination;
272 throw JTCThreadDeath();
273 }
274 }
275}
276
277//
278// Set the monitor of the current thread. This is used for suspend and
279// stop functionality. If the thread currently has a monitor then we
280// need to signal it so that the thread can be terminated in a timely
281// fashion.
282//
283void
284JTCThread::setMonitor(JTCMonitor* monitor)
285{
286 JTCSynchronized guard(monMutex_);
287 monitor_ = monitor;
288}
289
290//
291// Get the monitor of the current thread.
292//
293JTCMonitor*
294JTCThread::getMonitor()
295{
296 JTCSynchronized guard(monMutex_);
297 return monitor_;
298}
299#endif
300
301//
302// IOstream operator for pointer to void function taking a pointer
303// to void.
304//
305/*
306ostream&
307operator<<(ostream& os, void * (fn)(void *))
308{
309 os << (void*)fn;
310 return os;
311}
312*/
313#if defined(HAVE_POSIX_THREADS)
314#define PTHREAD_ATTR_INIT(a) pthread_attr_init(a)
315#define PTHREAD_ATTR_DESTROY(a) pthread_attr_destroy(a)
316#define PTHREAD_CREATE(a,b,c,d) \
317 JTC_SYSCALL_4(pthread_create, &a, &b, c, d,!= 0)
318#endif
319#if defined(HAVE_DCE_THREADS)
320#define PTHREAD_ATTR_INIT(a) pthread_attr_create(a)
321#define PTHREAD_ATTR_DESTROY(a) pthread_attr_delete(a)
322#define PTHREAD_CREATE(a,b,c,d) \
323 JTC_SYSCALL_4(pthread_create, &a, b, c, d,!= 0)
324#endif
325
326//
327// Start the thread. The entry point into the JTC library is the C
328// call-style function _JTC_threadAdapter. This in turn calls
329// _JTC_startThreadHook.
330//
331void
332JTCThread::spawnThread()
333{
334#if defined(HAVE_POSIX_THREADS) || defined(HAVE_DCE_THREADS)
335 pthread_attr_t attr;
336 try
337 {
338 JTC_SYSCALL_1(PTHREAD_ATTR_INIT, &attr, != 0)
339 }
340 catch(const JTCSystemCallException& e)
341 {
342 if(e.getError() == ENOMEM)
343 {
344 throw JTCOutOfMemoryError(e.getMessage());
345 }
346 throw;
347 }
348# if defined(_AIX)
349 //
350 // On AIX threads are created by default DETACHED. This makes
351 // it kinda tough to join with them. Best change this.
352 //
353 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_UNDETACHED);
354# endif
355# ifdef HAVE_PTHREAD_ATTR_SETSTACKSIZE
356 if(initialStackSize != 0)
357 pthread_attr_setstacksize(&attr, initialStackSize);
358# endif
359
360 //
361 // Call the custom pthread attribute hook, if defined.
362 //
363 if(attrHook_ != 0)
364 (*attrHook_)(&attr);
365
366 pthread_t threadId;
367 try
368 {
369 PTHREAD_CREATE(threadId, attr, _JTC_threadAdapter, this)
370 }
371 catch(const JTCSystemCallException& e)
372 {
373 PTHREAD_ATTR_DESTROY(&attr);
374 if(e.getError() == EAGAIN || e.getError() == ENOMEM)
375 {
376 throw JTCOutOfMemoryError(e.getMessage());
377 }
378 throw;
379 }
380
381 PTHREAD_ATTR_DESTROY(&attr);
382
383 thrId_ = JTCThreadId(threadId);
384#endif
385
386#if defined(HAVE_WIN32_THREADS)
387 DWORD threadId;
388 HANDLE handle;
389 try
390 {
391 JTC_SYSCALL_6(
392 handle = (HANDLE)::_beginthreadex,
393 NULL, initialStackSize,
394 (unsigned (__stdcall*)(void*))_JTC_threadAdapter, (LPVOID)this,
395 0, (unsigned int*)&threadId, == NULL)
396 }
397 catch(const JTCSystemCallException& e)
398 {
399 if(e.getError() == ERROR_NOT_ENOUGH_MEMORY ||
400 e.getError() == ERROR_OUTOFMEMORY)
401 {
402 throw JTCOutOfMemoryError(e.getMessage());
403 }
404 throw;
405 }
406 thrId_ = JTCThreadId(threadId, handle);
407#endif
408
409 //
410 // Wait for the TSS data to be set by the running thread.
411 //
412 setInitialData_.wait();
413}
414
415//
416// Helper for the constructor.
417//
418void
419JTCThread::init(const JTCThreadGroupHandle& group, JTCRunnableHandle target,
420 const char* name)
421{
422 //
423 // Set default values for the thread state flags.
424 //
425 terminated_ = not_terminated;
426#ifdef HAVE_JTC_STOP
427 monitor_ = 0;
428 suspended_ = false;
429#endif
430 name_ = 0;
431 target_ = target;
432 state_ = NewThread;
433 thrId_ = JTCThreadId();
434 ++_jtc_refCount_; // We're referencing outself. Boost the reference count.
435 adopted_ = false; // The thread was not adopted
436
437 //
438 // Group of 0 means that we inherit the thread group from the creating
439 // thread.
440 //
441 group_ = group;
442 if(group_.get() == 0)
443 {
444 group_ = currentThread() -> getThreadGroup();
445 }
446
447 //
448 // We create the thread on construction. Note that the thread
449 // doesn't invoke run until JTCThread::start is called. We cannot
450 // start the thread until a later point since we need the thread
451 // id one the constructor is called.
452 //
453 spawnThread();
454
455 //
456 // Set the threads name.
457 //
458 setName(name);
459
460 //
461 // Add this thread to the group.
462 //
463 group_ -> add(this);
464}
465
466// ----------------------------------------------------------------------
467// JTCThread private constructor
468// ----------------------------------------------------------------------
469
470//
471// This is called to initialize the JTC thread system.
472//
473JTCThread::JTCThread(JTCThreadId id, bool main)
474 : name_(0),
475#ifdef HAVE_JTC_STOP
476 resumeCond_(resumeMut_),
477#endif
478 joinCond_(joinMut_)
479{
480 //
481 // We need to create the key that contains the current thread
482 // data.
483 //
484 if(main)
485 {
486 thrKey_ = JTCTSS::allocate();
487 adopted_ = false;
488 }
489 else
490 adopted_ = true;
491
492 //
493 // Initialize to default state. Remember that this thread doesn't
494 // need to be spawned since it represents the main thread of the
495 // application.
496 //
497
498 //
499 // Set default values for the thread state variables.
500 //
501#ifdef HAVE_JTC_STOP
502 suspended_ = false;
503 monitor_ = 0;
504#endif
505 terminated_ = not_terminated;
506 thrId_ = id;
507 state_ = JTCThread::Runnable;
508
509 //
510 // Set the TSS data for this thread.
511 //
512 JTCTSS::set(thrKey_, this);
513 setName(0);
514 ++_jtc_refCount_; // We're referencing outself. Boost the reference count.
515
516 //
517 // Create the default `system' thread group.
518 //
519 group_ = new JTCThreadGroup(main);
520 group_ -> add(this);
521
522 //
523 // The main thread runs at normal priority. This may or may not be
524 // the default for the OS.
525 //
526 setPriority(JTC_NORM_PRIORITY);
527}
528
529// ----------------------------------------------------------------------
530// JTCThread constructor and destructor
531// ----------------------------------------------------------------------
532
533JTCThread::JTCThread(const char* name)
534 :
535#ifdef HAVE_JTC_STOP
536 resumeCond_(resumeMut_),
537#endif
538 joinCond_(joinMut_)
539{
540 init(JTCThreadGroupHandle(0), JTCRunnableHandle(0), name);
541}
542
543JTCThread::JTCThread(JTCRunnableHandle target, const char* name)
544 :
545#ifdef HAVE_JTC_STOP
546 resumeCond_(resumeMut_),
547#endif
548 joinCond_(joinMut_)
549{
550 init(JTCThreadGroupHandle(0), target, name);
551}
552
553JTCThread::JTCThread(JTCThreadGroupHandle& group, const char* name)
554 :
555#ifdef HAVE_JTC_STOP
556 resumeCond_(resumeMut_),
557#endif
558 joinCond_(joinMut_)
559{
560 init(group, JTCRunnableHandle(0), name);
561}
562
563JTCThread::JTCThread(JTCThreadGroupHandle& group, JTCRunnableHandle target,
564 const char* name)
565 :
566#ifdef HAVE_JTC_STOP
567 resumeCond_(resumeMut_),
568#endif
569 joinCond_(joinMut_)
570{
571 init(group, target, name);
572}
573
574JTCThread::~JTCThread()
575{
576 try
577 {
578 //
579 // The group needs to be defererences *before* the Thread
580 // object is destructed since if the ThreadGroup is
581 // destroyed a synchronization primitive is called
582 // which uses _JTC_checkRunningStatus. The bad news
583 // is at this point the thread has been destructed.
584 //
585 group_._jtc_deref();
586
587 delete[] name_;
588 }
589 catch(...)
590 {
591 }
592}
593
594// ----------------------------------------------------------------------
595// JTCThread public member implementation
596// ----------------------------------------------------------------------
597
598//
599// Get a handle to this threads ThreadGroup.
600//
601JTCThreadGroupHandle
602JTCThread::getThreadGroup()
603{
604 return group_;
605}
606
607//
608// Set the name of the current thread.
609//
610void
611JTCThread::setName(const char* name)
612{
613 char buf[1024];
614
615 //
616 // 0 means use the default name of the thread. That is
617 // Thread-<THR-ID>
618 //
619 if(name == 0)
620 {
621 ostrstream os(buf, sizeof(buf));
622 os << "Thread-" << thrId_ << ends;
623 name = buf;
624 }
625
626 JTCSynchronized guard(resumeMut_);
627
628 char* newName = new char[strlen(name) + 1];
629 strcpy(newName, name);
630
631 delete[] name_;
632 name_ = newName;
633}
634
635//
636// Return the name of the thread.
637//
638const char*
639JTCThread::getName() const
640{
641 JTCSynchronized guard(resumeMut_);
642 return name_;
643}
644
645#ifdef HAVE_JTC_STOP
646//
647// Suspend execution of this thread.
648//
649void
650JTCThread::suspend()
651{
652 JTCSynchronized guard(resumeMut_);
653 _checkRunningStatus();
654 if(!suspended_)
655 {
656 suspended_ = true;
657 if(getId() == JTCThreadId::self())
658 {
659 resumeCond_.wait();
660 _checkRunningStatus();
661 }
662 }
663}
664
665//
666// Resume execution of this thread.
667//
668void
669JTCThread::resume()
670{
671 JTCSynchronized guard(resumeMut_);
672 if(suspended_)
673 {
674 resumeCond_.broadcast();
675 suspended_ = false;
676 }
677}
678
679//
680// Stop execution of this thread.
681//
682void
683JTCThread::stop()
684{
685 JTCMonitor* currentMonitor = 0;
686 {
687 JTCSynchronized guard(resumeMut_);
688
689 //
690 // First check if the thread hasn't already been terminated.
691 //
692 if(terminated_ == not_terminated)
693 {
694 //
695 // Mark state as terminated, but ThreadDeath exception not
696 // yet thrown.
697 //
698 terminated_ = terminated;
699
700 //
701 // Terminate immediately if the calling thread is stopping
702 // itself.
703 //
704 if(getId() == JTCThreadId::self() && terminated_ == not_terminated)
705 {
706 terminated_ = throw_termination;
707 throw JTCThreadDeath();
708 }
709 //
710 // these conditions are all mutually exclusive. the
711 // thread cannot be stopping itself if it hasn't been
712 // started. The thread cannot be suspended if it's
713 // stopping itself, or if it hasn't yet been started.
714 //
715 else if(state_ == JTCThread::NewThread)
716 {
717 //
718 // If the thread hasn't been started yet, then start
719 // it.
720 //
721 startRequest_.post();
722 }
723 else if (suspended_)
724 {
725 resume();
726 }
727 else
728 {
729 currentMonitor = getMonitor();
730 }
731 }
732 }
733
734 //
735 // If the thread has an associated monitor, then notify to allow
736 // termination in a timely fashion. Note that this needs to be
737 // notified outside of the resumeMut_ mutex lock.
738 //
739 if(currentMonitor != 0)
740 {
741 JTCSynchronized monGuard(*currentMonitor, true);
742 currentMonitor -> notifyAll();
743 }
744}
745#endif
746
747//
748// Start execution of the thread.
749//
750void
751JTCThread::start()
752{
753 if(state_ != JTCThread::NewThread)
754 {
755 throw JTCIllegalThreadStateException("state is not NewThread");
756 }
757
758 //
759 // State is runnable.
760 //
761 state_ = JTCThread::Runnable;
762
763 //
764 // Tell the thread counter that a new thread has started.
765 // We don't up the running thread count until *after*
766 // start() has been called since we don't want unstarted
767 // threads to block JTCInitialize::~JTCInitialize()
768 //
769 threadCounter -> threadStart();
770
771 startRequest_.post();
772}
773
774//
775// The run method of the thread. If the thread has an associated
776// target (that is the thread has a Runnable object), then invoke it's
777// run method.
778//
779void
780JTCThread::run()
781{
782 if(target_)
783 {
784 target_ -> run();
785 }
786}
787
788//
789// The thread is alive if runnable or not runnable.
790//
791bool
792JTCThread::isAlive() const
793{
794 JTCSynchronized guard(resumeMut_);
795 return state_ == JTCThread::Runnable || state_ == JTCThread::NotRunnable;
796}
797
798//
799// Wait for termination of this thread.
800//
801void
802JTCThread::join()
803{
804 join(0,0);
805}
806
807static unsigned long
808currentTimeMillis()
809{
810 unsigned long t;
811#ifdef WIN32
812 struct _timeb timebuffer;
813 _ftime(&timebuffer);
814 t = timebuffer.time * 1000;
815 t += timebuffer.millitm;
816#else
817 struct timeval tv;
818 gettimeofday(&tv, 0);
819 t = tv.tv_sec * 1000;
820 t += tv.tv_usec/1000;
821#endif
822 return t;
823}
824
825//
826// Wait at most millis milliseconds for termination of this thread.
827//
828void
829JTCThread::join(long millis)
830{
831 if(millis < 0)
832 {
833 throw JTCIllegalArgumentException
834 ("timeout value is negative");
835 }
836
837#ifdef HAVE_JTC_STOP
838 _checkRunningStatus();
839#endif
840
841 unsigned long base = currentTimeMillis();
842 unsigned long now = 0;
843
844 JTCSynchronized guard(joinMut_);
845
846 if(millis == 0)
847 {
848 while(isAlive())
849 {
850 joinCond_.wait();
851 }
852 }
853 else
854 {
855 while(isAlive())
856 {
857 long delay = millis - now;
858 if(delay <= 0)
859 {
860 break;
861 }
862 joinCond_.wait(delay);
863 now = currentTimeMillis() - base;
864 }
865 }
866
867#ifdef HAVE_JTC_STOP
868 _checkRunningStatus();
869#endif
870}
871
872//
873// Wait at most millis milliseconds plus nanos nanoseconds for termination
874// of this thread.
875//
876void
877JTCThread::join(long millis, int nanos)
878{
879 if(millis < 0)
880 {
881 throw JTCIllegalArgumentException
882 ("timeout value is negative");
883 }
884 if(nanos > 999999)
885 {
886 throw JTCIllegalArgumentException
887 ("nanosecond timeout out of range");
888 }
889 if(nanos >= 500000 || (nanos != 0 && millis == 0))
890 {
891 ++millis;
892 }
893 join(millis);
894}
895
896static int levelMap[] =
897{
898#if defined(HAVE_DCE_THREADS)
899
900 PRI_OTHER_MIN,
901 ( PRI_OTHER_MIN + PRI_OTHER_MAX + 1 ) / 2,
902 PRI_OTHER_MAX
903
904#elif defined(HAVE_WIN32_THREADS)
905
906 THREAD_PRIORITY_LOWEST,
907 THREAD_PRIORITY_NORMAL,
908 THREAD_PRIORITY_HIGHEST
909
910#else // defined(HAVE_POSIX_THREADS)
911# if defined(__sun) && defined(__SVR4)
912 //
913 // Solaris.
914 //
915 5,
916 3,
917 1
918# elif defined(HAVE_FSU_THREADS)
919 0,
920 1,
921 2
922# elif defined(__linux__)
923 //
924 // Linux has no priorities under LinuxThreads.
925 //
926 0,
927 0,
928 0
929# elif defined(__sgi)
930 -20,
931 0,
932 20
933# elif defined(_AIX)
934 //
935 // AIX doesn't appear to have priorities either.
936 //
937 //PTHREAD_PRIO_MIN,
938 //( PTHREAD_PRIO_MIN + PTHREAD_PRIO_MAX ) / 2,
939 //PTHREAD_PRIO_MAX
940 1,
941 1,
942 1
943# elif defined(__osf__)
944 PRI_OTHER_MIN,
945 ( PRI_OTHER_MIN + PRI_OTHER_MAX + 1 ) / 2,
946 PRI_OTHER_MAX
947#elif defined(__hpux) && defined(HAVE_POSIX_THREADS)
948 //
949 // No thread priorities under HPUX 11.x.
950 //
951 0,
952 0,
953 0
954# else
955# error "No known priority levels!"
956# endif
957#endif
958};
959
960#if defined(HAVE_FSU_THREADS)
961ostream&
962operator<<(ostream& os, const pthread_attr_t& attr)
963{
964 os << "sched: " << attr.sched << " prio: " << attr.prio;
965 return os;
966}
967#endif
968
969//
970// Set the threads priority.
971//
972void
973JTCThread::setPriority(int newPri)
974{
975 if(newPri < JTC_MIN_PRIORITY || newPri > JTC_MAX_PRIORITY)
976 {
977 throw JTCIllegalArgumentException("priority out of range");
978 }
979 if(newPri > group_ -> getMaxPriority())
980 {
981 newPri = group_ -> getMaxPriority();
982 }
983#if defined(HAVE_POSIX_THREADS)
984# if defined(HAVE_FSU_THREADS)
985 pthread_attr_t attr;
986 JTC_SYSCALL_2(pthread_getschedattr, thrId_, &attr, != 0);
987 attr.prio = levelMap[newPri];
988 JTC_SYSCALL_2(pthread_setschedattr, thrId_, attr, != 0);
989# elif !defined(__hpux)
990 sched_param param;
991 int policy = 0;
992 JTC_SYSCALL_3(pthread_getschedparam, thrId_, &policy, &param, != 0)
993 param.sched_priority = levelMap[newPri];
994 JTC_SYSCALL_3(pthread_setschedparam, thrId_, policy, &param, != 0)
995# endif
996#endif
997#if defined(HAVE_DCE_THREADS)
998 JTC_SYSCALL_2(pthread_setprio, thrId_, levelMap[newPri], == -1)
999#endif
1000#if defined(HAVE_WIN32_THREADS)
1001 JTC_SYSCALL_2(SetThreadPriority, thrId_.handle_, levelMap[newPri],
1002 == 0)
1003#endif
1004}
1005
1006//
1007// Get the threads priority.
1008//
1009int
1010JTCThread::getPriority() const
1011{
1012#if defined(HAVE_POSIX_THREADS) || defined(HAVE_DCE_THREADS)
1013 int prio;
1014# if defined(HAVE_FSU_THREADS)
1015 pthread_attr_t attr;
1016 JTC_SYSCALL_2(pthread_getschedattr, thrId_, &attr, != 0)
1017 prio = attr.prio;
1018# elif defined(HAVE_POSIX_THREADS)
1019 sched_param param;
1020 int policy;
1021 JTC_SYSCALL_3(pthread_getschedparam, thrId_, &policy, &param, != 0)
1022 prio = param.sched_priority;
1023# elif defined(HAVE_DCE_THREADS)
1024 JTC_SYSCALL_1(prio = pthread_getprio, thrId_, != 0)
1025# endif
1026 if(prio <= 0)
1027 {
1028 return JTC_MIN_PRIORITY;
1029 }
1030 else if(prio == 1)
1031 {
1032 return JTC_NORM_PRIORITY;
1033 }
1034 return JTC_MAX_PRIORITY;
1035#endif
1036#if defined(HAVE_WIN32_THREADS)
1037 DWORD rc;
1038 JTC_SYSCALL_1(rc = GetThreadPriority, thrId_.handle_,
1039 == THREAD_PRIORITY_ERROR_RETURN);
1040 switch(rc)
1041 {
1042 case THREAD_PRIORITY_HIGHEST:
1043 case THREAD_PRIORITY_ABOVE_NORMAL:
1044 return JTC_MAX_PRIORITY;
1045 case THREAD_PRIORITY_NORMAL:
1046 return JTC_NORM_PRIORITY;
1047 case THREAD_PRIORITY_BELOW_NORMAL:
1048 case THREAD_PRIORITY_LOWEST:
1049 return JTC_MIN_PRIORITY;
1050 }
1051 return JTC_NORM_PRIORITY;
1052#endif
1053}
1054
1055//
1056// Enumerate the set of threads in this group.
1057//
1058int
1059JTCThread::enumerate(JTCThreadHandle* list, int len)
1060{
1061 return currentThread() -> getThreadGroup() -> enumerate(list, len);
1062}
1063
1064//
1065// Get a pointer to the current thread.
1066//
1067JTCThread*
1068JTCThread::currentThread()
1069{
1070 JTCThread* current = (JTCThread*)JTCTSS::get(JTCThread::thrKey_);
1071 if(current == 0)
1072 throw JTCUnknownThreadException();
1073 return current;
1074}
1075
1076#if defined(HAVE_MIT_THREADS)
1077extern "C" { void usleep(unsigned); };
1078int
1079nanosleep(struct timespec* tv, int)
1080{
1081 unsigned nsecs = tv -> tv_sec * 1000000;
1082 nsecs += tv -> tv_nsec / 1000;
1083 usleep(nsecs);
1084 return 0;
1085}
1086#endif
1087
1088//
1089// Put the current thread to sleep for millis millseconds and nano
1090// nanoseconds.
1091//
1092void
1093JTCThread::sleep(long millis, int nano)
1094{
1095#ifdef HAVE_JTC_STOP
1096 _JTC_checkRunningStatus();
1097#endif
1098
1099 if(millis < 0)
1100 {
1101 throw JTCIllegalArgumentException
1102 ("timeout value is negative");
1103 }
1104 if(nano > 999999)
1105 {
1106 throw JTCIllegalArgumentException
1107 ("nanosecond timeout out of range");
1108 }
1109
1110 //state_ = JTCThread::NotRunnable;
1111
1112#if defined(HAVE_PTHREAD_DELAY_NP)
1113 struct timespec tv;
1114 tv.tv_sec = millis/1000;
1115 tv.tv_nsec = (millis% 1000)*1000000 + nano;
1116 JTC_SYSCALL_1(pthread_delay_np, &tv, != 0);
1117
1118#elif defined(HAVE_POSIX_THREADS)
1119
1120 struct timespec tv;
1121 tv.tv_sec = millis/1000;
1122 tv.tv_nsec = (millis% 1000)*1000000 + nano;
1123 if(nanosleep(&tv, 0) < 0 && errno == EINTR)
1124 {
1125 throw JTCInterruptedException();
1126 }
1127#endif
1128
1129#if defined(HAVE_WIN32_THREADS)
1130 Sleep(millis);
1131#endif
1132 //state_ = JTCThread::Runnable;
1133
1134#ifdef HAVE_JTC_STOP
1135 _JTC_checkRunningStatus();
1136#endif
1137}
1138
1139//
1140// Provide definition for sched_yield under SGI.
1141//
1142#ifdef __sgi
1143extern "C" { int sched_yield(void); };
1144#endif
1145
1146//
1147// Yield the current threads timeslice.
1148//
1149void
1150JTCThread::yield()
1151{
1152#ifdef HAVE_JTC_STOP
1153 _JTC_checkRunningStatus();
1154#endif
1155
1156#if defined(HAVE_POSIX_THREADS) || defined(HAVE_DCE_THREADS)
1157# if defined(HAVE_SCHED_YIELD)
1158 sched_yield();
1159# elif defined(HAVE_PTHREAD_YIELD)
1160 pthread_yield();
1161# endif
1162#endif
1163
1164#if defined(HAVE_WIN32_THREADS)
1165 Yield();
1166#endif
1167
1168#ifdef HAVE_JTC_STOP
1169 _JTC_checkRunningStatus();
1170#endif
1171}
1172
1173//
1174// Return the number of active threads in the current thread group.
1175//
1176int
1177JTCThread::activeCount()
1178{
1179 return currentThread() -> getThreadGroup() -> activeCount();
1180}
1181
1182//
1183// Get the id of this thread. thrId_ is immutable so this method
1184// doesn't need to be mutex protected.
1185//
1186JTCThreadId
1187JTCThread::getId() const
1188{
1189 return thrId_;
1190}
1191
1192#if defined(HAVE_POSIX_THREADS) || defined(HAVE_DCE_THREADS)
1193void
1194JTCThread::setAttrHook(JTCAttrHook attrHook)
1195{
1196 attrHook_ = attrHook;
1197}
1198#endif
1199
1200//
1201// This method is called by the external "C" calling function used by
1202// the native thread package. This is the entrance point from the
1203// native thread library into the sane world of JTC.
1204//
1205void
1206JTCThread::_JTC_startThreadHook()
1207{
1208 //
1209 // Flag to indicate that we want to lower the thread counter
1210 // at thread termination.
1211 //
1212 bool lowerCounter = false;
1213
1214 try
1215 {
1216 //
1217 // Set the TSS data for this thread. This should a pointer to
1218 // this thread data.
1219 //
1220 JTCTSS::set(thrKey_, this);
1221
1222 setInitialData_.post();
1223
1224 //cout << "Start: " << name_ << endl;
1225 //
1226 // Wait for the user to actually `start' the thread. That is
1227 // call the start method for this thread object.
1228 //
1229 startRequest_.wait();
1230
1231 //
1232 // We want to lower the threadCounter if JTCThread::start()
1233 // has been called.
1234 //
1235 lowerCounter = (state_ != JTCThread::NewThread);
1236
1237 //
1238 // Make sure that the thread didn't `start' because the user
1239 // stopped the thread.
1240 //
1241 if(terminated_ == not_terminated)
1242 {
1243 //
1244 // It's not possible to set the priority until after the
1245 // start request has been sent, since under WIN32 the handle
1246 // may not have been set yet.
1247 //
1248 setPriority(JTC_NORM_PRIORITY);
1249
1250
1251 //
1252 // Call the run method of the thread.
1253 //
1254 run();
1255 }
1256 }
1257 catch(const JTCThreadDeath&)
1258 {
1259 //
1260 // This exception is thrown when stop() is called.
1261 //
1262 }
1263 catch(const JTCException& e)
1264 {
1265 group_ -> uncaughtException(this, e);
1266 }
1267 catch(...)
1268 {
1269 group_ -> uncaughtException(this);
1270 }
1271
1272#if defined(HAVE_WIN32_THREADS)
1273 //
1274 // Under WIN32 we must now close the thread handle, or suffer
1275 // the consequences.
1276 //
1277 CloseHandle(thrId_.handle_);
1278 thrId_.handle_ = 0;
1279#endif
1280
1281 //
1282 // Run the TSS cleanup hooks. The TSSManager should always
1283 // be present at this point. Note that the thrKey_ is cleared
1284 // out below and not at this point. However, this shouldn't make
1285 // any difference since the thrKey_ doesn't have an associated
1286 // data destructor.
1287 //
1288 JTCTSSManager* manager = JTCTSSManager::instance();
1289 assert(manager != 0);
1290 manager -> cleanup();
1291
1292 if (lowerCounter)
1293 {
1294 //
1295 // Inform the counter that this thread died. This has to be
1296 // done before _JTC_exit is called since the current thread
1297 // object could be deleted if the reference count drops to
1298 // zero.
1299 //
1300 threadCounter -> threadEnd();
1301 }
1302}
1303
1304void
1305JTCThread::_JTC_exit()
1306{
1307 {
1308 //
1309 // Set the state to Dead. This needs to be done before the
1310 // removal from the ThreadGroup since this eventually ends up
1311 // calling _checkRunningStatus, which if the state isn't dead
1312 // may end up throwing a JTCThreadDeath exception. We'll keep
1313 // the join and internal mutex locked to stop a join from
1314 // proceeding until _JTC_exit is completed. Ensure that
1315 // joinMut_ is aquired before resumeMut_ else a race can occur
1316 // between isAlive() and join().
1317 //
1318 JTCSynchronized joinGuard(joinMut_);
1319 JTCSynchronized guard(resumeMut_);
1320
1321 state_ = JTCThread::Dead;
1322 joinCond_.broadcast();
1323
1324 //
1325 // Detach the thread, assuming it was not adopted. That is
1326 // ensures that the thread resources are freed once the thread
1327 // terminates.
1328 //
1329 if(!adopted_)
1330 {
1331#if defined(HAVE_DCE_THREADS)
1332 pthread_t id = thrId_;
1333 JTC_SYSCALL_1(pthread_detach, &id, != 0)
1334#elif defined(HAVE_POSIX_THREADS)
1335 JTC_SYSCALL_1(pthread_detach, thrId_, != 0)
1336#endif
1337 }
1338
1339 //
1340 // Remove this thread from its ThreadGroup.
1341 //
1342 group_ -> remove(this);
1343 }
1344
1345 //
1346 // Lower the reference count.
1347 //
1348 if (--_jtc_refCount_ == 0)
1349 delete this;
1350
1351 //
1352 // Clear the current value after the reference count has been
1353 // lowered. This ensures that the currentThread is available in
1354 // the thread objects destructor.
1355 //
1356 JTCTSS::set(thrKey_, 0);
1357}
1358
1359#ifdef HAVE_JTC_STOP
1360//
1361// Check the running status of the currently active thread.
1362//
1363void
1364JTCThread::_JTC_checkRunningStatus()
1365{
1366 JTCThreadHandle current((JTCThread*)JTCTSS::get(JTCThread::thrKey_));
1367 if (current)
1368 current -> _checkRunningStatus();
1369}
1370
1371//
1372// Set a monitor for the currently running thread.
1373//
1374void
1375JTCThread::_JTC_setMonitor(JTCMonitor* monitor)
1376{
1377 JTCThreadHandle current((JTCThread*)JTCTSS::get(JTCThread::thrKey_));
1378 if (current)
1379 current -> setMonitor(monitor);
1380}
1381#endif
1382
1383//
1384// IOstream operator for the thread class.
1385//
1386ostream&
1387operator<<(ostream& os, const JTCThread& thr)
1388{
1389 os << "Thread: " << thr.getName();
1390 return os;
1391}
1392
1393//
1394// This represents the number of times that the thread has been
1395// initialized.
1396//
1397int JTCInitialize::init_ = 0;
1398
1399// ----------------------------------------------------------------------
1400// JTCThread private member implementation
1401// ----------------------------------------------------------------------
1402
1403void
1404JTCInitialize::initialize()
1405{
1406 manager_ = new JTCTSSManager;
1407
1408 //
1409 // Create ThreadCounter.
1410 //
1411 threadCounter = new JTCThreadCounter;
1412 try
1413 {
1414 //
1415 // Create entry for main thread.
1416 //
1417 mainThread_ = new JTCThread(JTCThreadId::self(), true);
1418 }
1419 catch(const JTCSystemCallException& e)
1420 {
1421 cerr << "JTC failed initialization:\n"
1422 << "\t" << e.getMessage()
1423 << endl;
1424 abort();
1425 }
1426 catch(...)
1427 {
1428 cerr << "Caught unexpected exception in initialization" << endl;
1429 abort();
1430 }
1431}
1432
1433// ----------------------------------------------------------------------
1434// JTCInitialize constructor and destructor
1435// ----------------------------------------------------------------------
1436
1437JTCInitialize::JTCInitialize()
1438{
1439 if(init_++ != 0)
1440 {
1441 return;
1442 }
1443 initialize();
1444}
1445
1446JTCInitialize::JTCInitialize(int& argc, char** argv)
1447{
1448 //
1449 // Only initialize on first call. Subsequent attempts do nothing.
1450 //
1451 if(init_++ != 0)
1452 {
1453 return;
1454 }
1455
1456 int i = 0;
1457 while(i < argc)
1458 {
1459 //
1460 // Initial stack size in kilobytes.
1461 //
1462 if(strcmp(argv[i], "-JTCss") == 0)
1463 {
1464 int ssTmp;
1465 if(i + 1 < argc)
1466 ssTmp = atoi(argv[i + 1]);
1467 else
1468 {
1469 cerr << "JTCInitialize:: argument expected for -JTCss" << endl;
1470 exit(1);
1471 }
1472 if(ssTmp <= 0)
1473 {
1474 cout << "JTCInitialize:: stack size must be positive." << endl;
1475 exit(1);
1476 }
1477 initialStackSize = ssTmp * 1024;
1478 for(int j = i ; j + 2 < argc ; j++)
1479 argv[j] = argv[j + 2];
1480
1481 argc -= 2;
1482 }
1483 else if(strcmp(argv[i], "-JTCversion") == 0)
1484 {
1485 extern const char* JTCVersion;
1486 cout << JTCVersion << endl;
1487
1488 for(int j = i ; j + 1 < argc ; j++)
1489 argv[j] = argv[j + 1];
1490
1491 argc -= 1;
1492 }
1493 else if(strcmp(argv[i], "-JTClicense") == 0)
1494 {
1495 extern const char* JTCLicense;
1496 cout << JTCLicense << endl;
1497
1498 for(int j = i ; j + 1 < argc ; j++)
1499 argv[j] = argv[j + 1];
1500
1501 argc -= 1;
1502 }
1503 else if(strncmp(argv[i], "-JTC", strlen("-JTC")) == 0)
1504 {
1505 cout << "JTCInitialize:: unknown option: " << argv[i] << endl;
1506
1507 for(int j = i ; j + 1 < argc ; j++)
1508 argv[j] = argv[j + 1];
1509
1510 argc -= 1;
1511 }
1512 else
1513 {
1514 i++;
1515 }
1516 }
1517 initialize();
1518}
1519
1520JTCInitialize::~JTCInitialize()
1521{
1522 //
1523 // On terminate on last call.
1524 //
1525 if(--init_ > 0)
1526 return;
1527
1528 //
1529 // Wait for all threads to disappear.
1530 //
1531 threadCounter -> waitZero();
1532
1533 //
1534 // Clean up main thread, and the ThreadCounter.
1535 //
1536 mainThread_ -> _JTC_exit();
1537 delete threadCounter;
1538
1539 delete manager_;
1540}
1541
1542// ----------------------------------------------------------------------
1543// JTCInitialize public member implementation
1544// ----------------------------------------------------------------------
1545
1546//
1547// Wait for all running threads to terminate.
1548//
1549void
1550JTCInitialize::waitTermination()
1551{
1552 threadCounter -> waitZero();
1553}
1554
1555//
1556// Determine if the JTC library has been initialized.
1557//
1558bool
1559JTCInitialize::initialized()
1560{
1561 return init_ > 0;
1562}
1563
1564// ----------------------------------------------------------------------
1565// JTCAdoptCurrentThread constructor and destructor
1566// ----------------------------------------------------------------------
1567
1568JTCAdoptCurrentThread::JTCAdoptCurrentThread()
1569{
1570 try
1571 {
1572 //
1573 // Create entry for adopted thread.
1574 //
1575 adoptedThread_ = new JTCThread(JTCThreadId::self(), false);
1576 }
1577 catch(const JTCSystemCallException& e)
1578 {
1579 cerr << "JTC failed initialization:\n"
1580 << "\t" << e.getMessage()
1581 << endl;
1582 abort();
1583 }
1584 catch(...)
1585 {
1586 cerr << "Caught unexpected exception in initialization" << endl;
1587 abort();
1588 }
1589}
1590
1591JTCAdoptCurrentThread::~JTCAdoptCurrentThread()
1592{
1593 //
1594 // Clean up main thread, and the ThreadCounter.
1595 //
1596 adoptedThread_ -> _JTC_exit();
1597}
Note: See TracBrowser for help on using the repository browser.