root/juggler/tags/1.0.5/Threads/vjThreadPool.cpp

Revision 7539, 8.4 kB (checked in by anonymous, 7 years ago)

This commit was manufactured by cvs2svn to create tag
'RELENG_1_0_5_RELEASE'.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1 /*************** <auto-copyright.pl BEGIN do not edit this line> **************
2  *
3  * VR Juggler is (C) Copyright 1998, 1999, 2000 by Iowa State University
4  *
5  * Original Authors:
6  *   Allen Bierbaum, Christopher Just,
7  *   Patrick Hartling, Kevin Meinert,
8  *   Carolina Cruz-Neira, Albert Baker
9  *
10  * This library is free software; you can redistribute it and/or
11  * modify it under the terms of the GNU Library General Public
12  * License as published by the Free Software Foundation; either
13  * version 2 of the License, or (at your option) any later version.
14  *
15  * This library is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18  * Library General Public License for more details.
19  *
20  * You should have received a copy of the GNU Library General Public
21  * License along with this library; if not, write to the
22  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
23  * Boston, MA 02111-1307, USA.
24  *
25  * -----------------------------------------------------------------
26  * File:          $RCSfile$
27  * Date modified: $Date$
28  * Version:       $Revision$
29  * -----------------------------------------------------------------
30  *
31  *************** <auto-copyright.pl END do not edit this line> ***************/
32
33
34 #include <vjConfig.h>
35 #include <new.h>
36 #include <stdlib.h>
37 #include <stdio.h>
38 #include <errno.h>
39 #include <sys/types.h>
40 //#include <unistd.h>
41
42 #ifdef HAVE_SYS_TIME_H
43 #   include <sys/time.h>
44 #endif
45
46 #ifndef VJ_OS_Win32
47 #   include <sys/resource.h>
48 #endif
49
50 #include <Threads/vjThreadPool.h>
51 #include <Threads/vjThread.h>
52 #include <SharedMem/vjMemory.h>
53 #include <Sync/vjGuard.h>
54 #include <Kernel/vjDebug.h>
55
56 // XXX: There is a bug that causes a memory leak
57 //   - We never delete the Functors
58
59 // ---------------------------------------------------------------------------
60 // Constructor.
61 // ---------------------------------------------------------------------------
62 vjThreadPool::vjThreadPool (int numToStartWith) : readyThreads(0) {
63     //DebugLock.acquire();
64       vjDEBUG(vjDBG_ALL, vjDBG_DETAILED_LVL)
65          << "vjThreadPool::vjThreadPool: Entering.\n" << vjDEBUG_FLUSH;
66       vjDEBUG(vjDBG_ALL, vjDBG_HVERB_LVL)
67          << "\tvjThreadPool::vjThreadPool: Number threads: " << numToStartWith
68          << std::endl << vjDEBUG_FLUSH;
69     //DebugLock.release();
70
71     listHead = NULL;
72     workingCount = 0;
73     listLock.release();             // release threadList
74     finishedLock.release();         // Initialize if to threads being done
75
76        //-- Start the initial # of threads ---//
77     for (int index=0;index < numToStartWith;index++)
78     {
79         addThread();
80     }
81 }
82
83
84 /* Why did I have to hard code number in sproc group?
85   Why aren't I tracking the number of threads started? */
86
87 // ---------------------------------------------------------------------------
88 // Body of a general-purpose child process. The argument, which must be
89 // declared void* to match the func prototype, is the vjOneThread structure
90 // that represents this process.   The contents of that struct, in
91 // particular threadWait, MUST be initialized by the parent.
92 // ---------------------------------------------------------------------------
93 void
94 vjThreadPool::threadLoop(void* theThreadAsVoid) {
95 //   DebugLock.acquire();
96    vjDEBUG(vjDBG_ALL, vjDBG_DETAILED_LVL) << vjThread::self()
97                                           << " vjThreadPool::threadLoop: Entering."
98                                           << std::endl << vjDEBUG_FLUSH;
99 //      vjDEBUG(vjDBG_ALL, vjDBG_HVERB_LVL) << vjThread::self()
100 //      << " vjThreadPool::threadLoop: theThreadAsVoid:"
101 //      << theThreadAsVoid << endl << vjDEBUG_FLUSH;
102 //   DebugLock.release();
103
104    listLock.acquire();
105    listLock.release();     // Do this to make sure addThread is done
106
107    vjOneThread* myThread = (vjOneThread*)theThreadAsVoid;
108
109 #ifdef VJ_IRIX_SPROC
110    // --- SIGNAL Handlers ---- //
111    prctl(PR_TERMCHILD);       // What should I do with. FIX - Allen
112 #endif
113
114    for (;;)
115    {
116       // --- WAIT FOR WORK --- //
117       threadSleep(myThread);
118       // ASSERT:  We now have work to do...
119       // --- PROCESS ENTRY OVERHEAD --- //
120       workingCountLock.acquire();     // Get access to the working thread count
121       if (workingCount == 0)
122       {
123          finishedLock.acquire();       // Now there are threads working
124       }
125       workingCount = workingCount + 1;    // Update thread count
126       workingCountLock.release();
127
128       // --- DO THE WORK --- //
129       myThread->functor->operator()();
130
131       // --- PROCESS EXIT OVERHEAD --- //
132       workingCountLock.acquire();     // Get access to the working count
133       workingCount = workingCount - 1;
134       if (workingCount == 0)
135       {
136          finishedLock.release();       // Now there are no threads working
137       }
138       workingCountLock.release();
139    }
140 }
141
142 // ---------------------------------------------------------------------------
143 // Wait for work to do.  Put a vjOneThread structure on the ready list and
144 // sleep on it.  Called by a child process when its work is done.
145 // ---------------------------------------------------------------------------
146 void
147 vjThreadPool::threadSleep(vjOneThread* theThread) {
148     listLock.acquire();               // acquire exclusive rights to threadList
149         theThread->next = listHead;   // put self on head of the list
150         listHead = theThread;
151     listLock.release();               // release threadList
152
153     readyThreads.release();           // notify master, at least 1 on the list
154
155     theThread->threadWait.acquire();  // sleep until master needs/releases me
156 }
157
158 // ---------------------------------------------------------------------------
159 // Get a process to run.  Acquire a vjOneThread structure from the ready list,
160 // waiting if necessary.  Called by the master process as part of
161 // dispatching a thread.
162 // ---------------------------------------------------------------------------
163 vjOneThread*
164 vjThreadPool::getThread (void) {
165     vjOneThread* theThread;
166
167     readyThreads.acquire();           // wait until at least 1 thread is free
168
169     listLock.acquire();               // acquire exclusive rights to threadList
170         theThread = listHead;         // get address of first free vjOneThread
171         listHead = theThread->next;   // make next in list, the head of list
172     listLock.release();               // release threadList
173
174     return theThread;
175 }
176
177 // ---------------------------------------------------------------------------
178 // ---------------------------------------------------------------------------
179 void
180 vjThreadPool::printList (void) {
181     vjOneThread* curThread = listHead;
182     int counter = 0;
183
184     std::cerr << "----- Thread List -----\n";
185
186     while(curThread != NULL) {
187         std::cerr << "Thread: " << counter++ << std::endl;
188         std::cerr << "\tpid: " << *curThread << std::endl;
189         curThread = curThread->next;
190     }
191 }
192
193 // ---------------------------------------------------------------------------
194 // ---------------------------------------------------------------------------
195 vjOneThread* vjThreadPool::addThread (void)
196 {
197     static int numTimes = 0;
198 //    DebugLock.acquire();
199       vjDEBUG(vjDBG_ALL, vjDBG_DETAILED_LVL) << vjThread::self()
200                                              << " vjThreadPool::addThread: Entering: "
201                                              << ++numTimes << std::endl
202                                              << vjDEBUG_FLUSH;
203 //    DebugLock.release();
204
205     vjGuard<vjMutex> guard(listLock);   // Protect the head
206
207     //vjOneThread* newThread = new (this->getMyMemPool()->allocate(sizeof(vjOneThread))) vjOneThread;    // Used placement new
208     vjOneThread* newThread = new vjOneThread;
209     newThread->next = NULL;
210
211 //    vjThreadMemberFunctor<vjThreadPool>* memberFunctor = new vjThreadMemberFunctor<vjThreadPool>(this, vjThreadPool::threadLoop, (void*)newThread);
212     vjThreadMemberFunctor<vjThreadPool>* memberFunctor = new vjThreadMemberFunctor<vjThreadPool>(this, &vjThreadPool::threadLoop, (void*)newThread);
213
214     newThread->thread = new vjThread(memberFunctor, 0);
215
216 //    DebugLock.acquire();
217         vjDEBUG(vjDBG_ALL, vjDBG_HVERB_LVL) << newThread->thread
218                                             << " vjThreadPool::addThread: List at end\n"
219                                             << vjDEBUG_FLUSH;
220         printList();
221 //    DebugLock.release();
222
223     return listHead;
224 }
225
226 std::ostream& operator<< (std::ostream& outfile, vjOneThread& thread)
227 {
228     outfile << thread.thread;
229     return outfile;
230 }
Note: See TracBrowser for help on using the browser.