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

Revision 8789, 8.4 kB (checked in by patrickh, 7 years ago)

Copyright update.

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