source: Sophya/trunk/SophyaExt/JThreadsC++/JTCSrc/ThreadGroup.cpp@ 2843

Last change on this file since 2843 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: 15.8 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/Handle.h>
15#include <JTC/HandleI.h>
16#include <JTC/Event.h>
17#include <JTC/Cond.h>
18#include <JTC/Monitor.h>
19#include <JTC/Exception.h>
20#include <JTC/Thread.h>
21#include <JTC/ThreadGroup.h>
22#include <JTC/Runnable.h>
23#include <JTC/Sync.h>
24
25#include <string.h>
26
27#ifndef HAVE_NO_EXPLICIT_TEMPLATES
28template class JTCHandleT<JTCThreadGroup>;
29#else
30# ifdef HAVE_PRAGMA_DEFINE
31# pragma define(JTCHandleT<JTCThreadGroup>)
32# endif
33#endif
34
35#ifdef HAVE_STD_IOSTREAM
36using namespace std;
37#endif
38
39// ----------------------------------------------------------------------
40// JTCThreadGroup::JTCThreadGroupSet public member implementation
41// ----------------------------------------------------------------------
42
43//
44// Allocate n members.
45//
46inline void
47JTCThreadGroup::JTCThreadGroupSet::allocate(int n)
48{
49 len_ = n;
50 handles_ = new JTCThreadGroupHandle[n];
51}
52
53//
54// Return the number of elements in the set.
55//
56inline int
57JTCThreadGroup::JTCThreadGroupSet::length() const
58{
59 return len_;
60}
61
62//
63// Return a reference to the i'th element.
64//
65inline JTCThreadGroupHandle&
66JTCThreadGroup::JTCThreadGroupSet::operator[](int i)
67{
68 return handles_[i];
69}
70
71// ----------------------------------------------------------------------
72// JTCThreadGroup private member implementation
73// ----------------------------------------------------------------------
74
75//
76// Create a snapshot of current child ThreadGroups.
77//
78void
79JTCThreadGroup::createGroupSnapshot(JTCThreadGroupSet& set) const
80{
81 set.allocate(ngroups_);
82 for(int i = 0; i < ngroups_; ++i)
83 {
84 set[i] = groups_[i];
85 }
86}
87
88//
89// Add a ThreadGroup to my child list.
90//
91void
92JTCThreadGroup::add(JTCThreadGroup* g)
93{
94 JTCSynchronized sync(*this);
95 if(destroyed_)
96 {
97 throw JTCIllegalThreadStateException();
98 }
99 //
100 // No children yet?
101 //
102 if(groups_ == 0)
103 {
104 groups_ = new JTCThreadGroup*[4];
105 groupsLength_ = 4;
106 }
107 //
108 // Time to grow array?
109 //
110 else if(ngroups_ == groupsLength_)
111 {
112 //
113 // Allocate memory and then copy... This is more exception
114 // safe.
115 //
116 int newGroupsLength = ngroups_*2;
117 JTCThreadGroup** newGroups = new JTCThreadGroup*[newGroupsLength];
118 for(int i = 0; i < ngroups_; ++i)
119 {
120 newGroups[i] = groups_[i];
121 }
122
123 delete[] groups_;
124 groups_ = newGroups;
125 groupsLength_ = newGroupsLength;
126 }
127
128 //
129 // Add the group to the child list.
130 //
131 groups_[ngroups_] = g;
132 ++ngroups_;
133}
134
135//
136// Remove a ThreadGroup from my child list.
137//
138void
139JTCThreadGroup::remove(JTCThreadGroup* g)
140{
141 JTCSynchronized sync(*this);
142 if(destroyed_)
143 {
144 throw JTCIllegalThreadStateException();
145 }
146
147 for(int i =0 ; i < ngroups_; ++i)
148 {
149 if(groups_[i] == g)
150 {
151 --ngroups_;
152 for(int j = i; j < ngroups_; ++j)
153 {
154 groups_[j] = groups_[j+1];
155 }
156 groups_[ngroups_] = 0;
157 }
158 }
159
160 //
161 // If we remove the last thread then notify the ThreadGroups
162 // monitor.
163 //
164 if(nthreads_ == 0)
165 {
166 notifyAll();
167 }
168
169 //
170 // If we've gotten rid of all threads and ThreadGroups then
171 // destroy the ThreadGroup.
172 //
173 if(daemon_ && nthreads_ == 0 && ngroups_ == 0)
174 {
175 destroy();
176 }
177}
178
179//
180// This code is present to deal with internal compilation errors
181// in gcc 2.7.2
182//
183void
184copy_it(JTCThreadHandle* from, int len, JTCThreadHandle* to)
185{
186 for (int i =0; i < len; ++i)
187 {
188 to[i] = from[i];
189 }
190}
191
192void
193delete_it(JTCThreadHandle* it)
194{
195 delete[] it;
196}
197
198//
199// End internal compilation error code
200//
201
202//
203// Add a thread to my thread set.
204//
205void
206JTCThreadGroup::add(JTCThreadHandle t)
207{
208 JTCSynchronized sync(*this);
209
210 if(destroyed_)
211 {
212 throw JTCIllegalThreadStateException();
213 }
214
215
216 //
217 // No threads yet?
218 //
219 if(threads_ == 0)
220 {
221 threads_ = new JTCThreadHandle[4];
222 threadsLength_ = 4;
223 }
224 //
225 // Time to grow the array?
226 //
227 else if(nthreads_ == threadsLength_)
228 {
229
230 //
231 // Allocate and then copy. This is more exception safe.
232 //
233 int newThreadLength = nthreads_*2;
234 JTCThreadHandle* newThreads = new JTCThreadHandle[newThreadLength];
235
236
237 // This generates an internal error with gcc 2.7.2
238 //for(int i = 0; i < nthreads_; ++i)
239 //{
240 // newThreads[i] = threads_[i];
241 //}
242 // Use this instead
243 copy_it(threads_, nthreads_, newThreads);
244 //
245
246 // This generates an internal error with gcc 2.7.2
247 //delete[] threads_;
248 // Use this instead
249 delete_it(threads_);
250 //
251 threads_ = newThreads;
252 threadsLength_ = newThreadLength;
253 }
254 //
255 // Add thread.
256 //
257 threads_[nthreads_] = t;
258 ++nthreads_;
259}
260
261//
262// Remove a thread from my thread set.
263//
264void
265JTCThreadGroup::remove(JTCThreadHandle t)
266{
267 JTCSynchronized sync(*this);
268 if(destroyed_)
269 {
270 throw JTCIllegalThreadStateException();
271 }
272 for(int i = 0; i < nthreads_; ++i)
273 {
274 if(threads_[i] == t)
275 {
276 --nthreads_;
277 for(int j = i; j < nthreads_; ++j)
278 {
279 threads_[j] = threads_[j+1];
280 }
281 threads_[nthreads_] = JTCThreadHandle();
282 }
283 }
284 if(nthreads_ == 0)
285 {
286 notifyAll();
287 }
288 if(daemon_ && nthreads_ == 0 && ngroups_ == 0)
289 {
290 destroy();
291 }
292}
293
294//
295// TODO: ensure that exceptions don't cause memory leaks. Currently
296// exceptions can cause the GroupSnapshot to be trashed. Some sort
297// of auto_ptr can fix this.
298//
299
300//
301// Copy threads from my thread set into the provided array.
302//
303int
304JTCThreadGroup::enumerate(JTCThreadHandle* list, int len, int n,
305 bool recurse) const
306{
307 JTCThreadGroupSet groupsSnapshot;
308
309 {
310 JTCSynchronized sync(*this);
311
312 if(destroyed_)
313 {
314 return 0;
315 }
316
317 //
318 // Copy threads into the provided list.
319 //
320 int nt = nthreads_;
321 if(nt > len - n)
322 {
323 nt = len - n;
324 }
325 if(nt > 0)
326 {
327 for(int i = 0; i < nt; ++i)
328 {
329 list[i+n] = threads_[i];
330 }
331 n += nt;
332 }
333 createGroupSnapshot(groupsSnapshot);
334 }
335
336 //
337 // Recurse into child ThreadGroups?
338 //
339 if(recurse)
340 {
341 for(int i = 0; i < groupsSnapshot.length(); ++i)
342 {
343 n = groupsSnapshot[i] -> enumerate(list, len, n, 1);
344 }
345 }
346
347 return n;
348}
349
350//
351// Copy the set of ThreadGroups into the provided array.
352//
353int
354JTCThreadGroup::enumerate(JTCThreadGroupHandle* list, int len, int n,
355 bool recurse) const
356{
357 JTCThreadGroupSet groupsSnapshot;
358
359 {
360 JTCSynchronized sync(*this);
361
362 if(destroyed_)
363 {
364 return 0;
365 }
366
367 int ng = nthreads_;
368 if(ng > len - n)
369 {
370 ng = len - n;
371 }
372 if(ng > 0)
373 {
374 for(int i = 0; i < ng; ++i)
375 {
376 list[i+n] = groups_[i];
377 }
378 n += ng;
379 }
380 createGroupSnapshot(groupsSnapshot);
381 }
382
383 //
384 // Recurse into child ThreadGroups?
385 //
386 if(recurse)
387 {
388 for(int i = 0; i < groupsSnapshot.length(); ++i)
389 {
390 n = groupsSnapshot[i] -> enumerate(list, len, n, 1);
391 }
392 }
393
394 return n;
395}
396
397//
398// Constructor helper.
399//
400void
401JTCThreadGroup::init(JTCThreadGroup* parent, const char* n)
402{
403 //
404 // Initialize state variables.
405 //
406 ngroups_ = 0;
407 groups_ = 0;
408 groupsLength_ = 0;
409 nthreads_ = 0;
410 threads_ = 0;
411 threadsLength_ = 0;
412 destroyed_ = false;
413 daemon_ = parent -> daemon_;
414
415 //
416 // Copy name.
417 //
418 name_ = new char[strlen(n)+1];
419 strcpy(name_, n);
420
421 maxPriority_ = parent -> maxPriority_;
422
423 //
424 // Add myself to my parent.
425 //
426 parent_ = parent;
427 parent -> add(this);
428}
429
430// ----------------------------------------------------------------------
431// JTCThreadGroup private constructor
432// ----------------------------------------------------------------------
433
434//
435// This is the constructor that creates the main thread group.
436//
437JTCThreadGroup::JTCThreadGroup(bool main)
438 : parent_(0),
439 destroyed_(false),
440 nthreads_(0),
441 threads_(0),
442 threadsLength_(0),
443 ngroups_(0),
444 groups_(0),
445 groupsLength_(0),
446 daemon_(false)
447{
448 //
449 // Default name of the system ThreadGroup is system, otherwise
450 // the name is adopted.
451 //
452 const char* defaultName = (main) ? "system" : "adopted";
453 name_ = new char[strlen(defaultName)+1];
454 strcpy(name_, defaultName);
455
456 maxPriority_ = JTCThread::JTC_MAX_PRIORITY;
457}
458
459// ----------------------------------------------------------------------
460// JTCThreadGroup constructors and destructor
461// ----------------------------------------------------------------------
462
463JTCThreadGroup::JTCThreadGroup(const char* name)
464{
465 init(JTCThread::currentThread() -> getThreadGroup().get(), name);
466}
467
468JTCThreadGroup::JTCThreadGroup(JTCThreadGroup* parent, const char* name)
469{
470 init(parent, name);
471}
472
473JTCThreadGroup::~JTCThreadGroup()
474{
475 try
476 {
477 JTCSynchronized sync(*this);
478 if (!destroyed_)
479 {
480 destroy();
481 }
482 }
483 catch(const JTCIllegalThreadStateException&)
484 {
485 cerr << "Unexpected JTCIllegalThreadStateException in ~JTCThreadGroup"
486 << endl;
487 }
488 delete[] name_;
489}
490
491// ----------------------------------------------------------------------
492// JTCThreadGroup public member implementation
493// ----------------------------------------------------------------------
494
495//
496// Return name of the this ThreadGroup.
497//
498const char*
499JTCThreadGroup::getName() const
500{
501 return name_;
502}
503
504//
505// Return the parent of this ThreadGroup.
506//
507JTCThreadGroupHandle
508JTCThreadGroup::getParent() const
509{
510 return JTCThreadGroupHandle(parent_);
511}
512
513//
514// Is this a daemon ThreadGroup?
515//
516bool
517JTCThreadGroup::isDaemon() const
518{
519 return daemon_;
520}
521
522//
523// Set the daemon ThreadGroup flag.
524//
525
526void
527JTCThreadGroup::setDaemon(bool daemon)
528{
529 daemon_ = daemon;
530}
531
532//
533// Called on an uncaught exception.
534//
535void
536JTCThreadGroup::uncaughtException(JTCThreadHandle t, const JTCException& e)
537{
538 if (parent_)
539 {
540 parent_ -> uncaughtException(t, e);
541 }
542 else
543 {
544 cerr << e << endl;
545 }
546}
547
548//
549// Called on an uncaught exception (... style)
550//
551void
552JTCThreadGroup::uncaughtException(JTCThreadHandle t)
553{
554 if (parent_)
555 {
556 parent_ -> uncaughtException(t);
557 }
558 else
559 {
560 cerr << "unknown exception" << endl;
561 }
562}
563
564//
565// Return the maximum priority of this ThreadGroup.
566//
567int
568JTCThreadGroup::getMaxPriority() const
569{
570 return maxPriority_;
571}
572
573#ifdef HAVE_JTC_STOP
574//
575// Stop all threads in this ThreadGroup, and child ThreadGroups.
576//
577void
578JTCThreadGroup::stop()
579{
580 JTCThreadGroupSet groupsSnapshot;
581
582 {
583 JTCSynchronized sync(*this);
584
585 //
586 // Stop all of the threads that this ThreadGroup owns.
587 //
588 for (int i = 0; i < nthreads_; ++i)
589 {
590 threads_[i] -> stop();
591 }
592 createGroupSnapshot(groupsSnapshot);
593 }
594
595 //
596 // Ask each child ThreadGroup to stop their threads.
597 //
598 for(int i = 0; i < groupsSnapshot.length(); ++i)
599 {
600 groupsSnapshot[i] -> stop();
601 }
602}
603
604//
605// Resume all threads in our ThreadGroup, and child ThreadGroups.
606//
607void
608JTCThreadGroup::resume()
609{
610 JTCThreadGroupSet groupsSnapshot;
611
612 {
613 JTCSynchronized sync(*this);
614 //
615 // Resume all threads in our ThreadGroup.
616 //
617 for (int i = 0; i < nthreads_; ++i)
618 {
619 threads_[i] -> resume();
620 }
621 createGroupSnapshot(groupsSnapshot);
622 }
623
624 //
625 // Resume all threads in our child ThreadGroups.
626 //
627 for(int i = 0; i < groupsSnapshot.length(); ++i)
628 {
629 groupsSnapshot[i] -> resume();
630 }
631}
632
633//
634// Suspend all threads in our ThreadGroup, and child ThreadGroups.
635//
636void
637JTCThreadGroup::suspend()
638{
639 JTCThreadGroupSet groupsSnapshot;
640
641 {
642 JTCSynchronized sync(*this);
643
644 //
645 // Suspend all threads in our ThreadGroup.
646 //
647 for (int i = 0; i < nthreads_; ++i)
648 {
649 threads_[i] -> suspend();
650 }
651 createGroupSnapshot(groupsSnapshot);
652 }
653
654 //
655 // Suspend all threads in our child ThreadGroups.
656 //
657 for(int i = 0; i < groupsSnapshot.length(); ++i)
658 {
659 groupsSnapshot[i] -> suspend();
660 }
661}
662#endif
663
664//
665// Has this ThreadGroup been destroyed?
666//
667bool
668JTCThreadGroup::isDestroyed() const
669{
670 JTCSynchronized sync(*this);
671 return destroyed_;
672}
673
674//
675// Destroy this ThreadGroup.
676//
677void
678JTCThreadGroup::destroy()
679{
680 JTCThreadGroupSet groupsSnapshot;
681
682 {
683 JTCSynchronized sync(*this);
684 if(destroyed_ || nthreads_ > 0)
685 {
686 throw JTCIllegalThreadStateException();
687 }
688 createGroupSnapshot(groupsSnapshot);
689
690 destroyed_ = true;
691 ngroups_ = 0;
692 delete[] groups_;
693 groups_ = 0;
694 groupsLength_ = 0;
695 nthreads_ = 0;
696 delete[] threads_;
697 threads_ = 0;
698 threadsLength_ = 0;
699 }
700
701 for(int i = 0; i < groupsSnapshot.length(); ++i)
702 {
703 groupsSnapshot[i] -> destroy();
704 }
705
706 if(parent_)
707 {
708 parent_ -> remove(this);
709 }
710}
711
712//
713// Set maximum priority value for this ThreadGroup, and our child
714// ThreadGroups.
715//
716void
717JTCThreadGroup::setMaxPriority(int pri)
718{
719 JTCThreadGroupSet groupsSnapshot;
720
721 {
722 JTCSynchronized sync(*this);
723 if(pri < JTCThread::JTC_MIN_PRIORITY)
724 {
725 maxPriority_ = JTCThread::JTC_MIN_PRIORITY;
726 }
727 else if(pri < maxPriority_)
728 {
729 maxPriority_ = pri;
730 }
731 createGroupSnapshot(groupsSnapshot);
732 }
733
734 for(int i = 0; i < groupsSnapshot.length(); ++i)
735 {
736 groupsSnapshot[i] -> setMaxPriority(pri);
737 }
738}
739
740//
741// Is this ThreadGroup a parent of handle?
742//
743bool
744JTCThreadGroup::parentOf(JTCThreadGroupHandle handle)
745{
746 JTCThreadGroup* g = handle.get();
747 for(;g != 0; g = g -> parent_.get())
748 {
749 if(g == this)
750 {
751 return true;
752 }
753 }
754 return false;
755}
756
757//
758// Determine the number of active threads in this ThreadGroup, and
759// child ThreadGroups.
760//
761int
762JTCThreadGroup::activeCount() const
763{
764 int result = 0;
765
766 JTCThreadGroupSet groupsSnapshot;
767
768 {
769 JTCSynchronized sync(*this);
770
771 if(destroyed_)
772 {
773 return 0;
774 }
775 result = nthreads_;
776
777 createGroupSnapshot(groupsSnapshot);
778 }
779
780 for(int i = 0; i < groupsSnapshot.length(); ++i)
781 {
782 result += groupsSnapshot[i] -> activeCount();
783 }
784
785 return result;
786}
787
788//
789// Determine the number of ThreadGroups in this group, and child
790// ThreadGroups.
791//
792int
793JTCThreadGroup::activeGroupCount() const
794{
795 JTCThreadGroupSet groupsSnapshot;
796
797 {
798 JTCSynchronized sync(*this);
799
800 if(destroyed_)
801 {
802 return 0;
803 }
804 createGroupSnapshot(groupsSnapshot);
805 }
806
807 int n = groupsSnapshot.length();
808 for(int i = 0; i < groupsSnapshot.length(); ++i)
809 {
810 n += groupsSnapshot[i] -> activeCount();
811 }
812 return n;
813}
814
815//
816// Copy the set of threads in this ThreadGroup, and child ThreadGroups
817// if recurse is true into array list.
818//
819int
820JTCThreadGroup::enumerate(JTCThreadHandle* list, int len, bool recurse) const
821{
822 return enumerate(list, len, 0, recurse);
823}
824
825//
826// Copy the set child ThreadGroups in this ThreadGroup, and child ThreadGroups
827// if recurse is true into array list.
828//
829int
830JTCThreadGroup::enumerate(JTCThreadGroupHandle* list, int len,
831 bool recurse) const
832{
833 return enumerate(list, len, 0, recurse);
834}
835
836//
837// Display set of threads and ThreadGroups to cout.
838//
839void
840JTCThreadGroup::list()
841{
842 list(cout, 0);
843}
844
845//
846// Display the set of threads and ThreadGroups to os, with given indent
847// level.
848//
849void
850JTCThreadGroup::list(ostream& os, int indent)
851{
852 JTCThreadGroupSet groupsSnapshot;
853
854 {
855 JTCSynchronized sync(*this);
856 for(int j = 0; j < indent; ++j)
857 {
858 os << " ";
859 }
860 os << *this << endl;
861 indent += 4;
862 for(int i = 0; i < nthreads_; ++i)
863 {
864 for(int i_level = 0; i_level < indent; ++i_level)
865 {
866 os << " ";
867 }
868 os << *threads_[i] << endl;
869 }
870 createGroupSnapshot(groupsSnapshot);
871 }
872 for(int i = 0; i < groupsSnapshot.length(); ++i)
873 {
874 groupsSnapshot[i] -> list(os, indent);
875 }
876}
877
878//
879// IOstream insertion operator for a ThreadGroup.
880//
881ostream&
882operator<<(ostream& os, const JTCThreadGroup& g)
883{
884 os << "ThreadGroup: "
885 << "[name=" << g.getName() << ",maxpri=" << g.getMaxPriority() << "]";
886 return os;
887}
Note: See TracBrowser for help on using the repository browser.