root/juggler/tags/1.0.5/Threads/vjThreadPosix.h

Revision 4719, 17.0 kB (checked in by patrickh, 8 years ago)

At long last, support for HP-UX 11.00 has been added! Most of the changes
had to be made to the build system which says a lot for the portability of
VR Juggler. Other changes reflect the differences between HP-UX 10.20
(where I originally tried to do the port) and HP-UX 11.00. Please note
that support for HP-UX 10.20 is now officially disabled on this branch.
There is still some hope for it in VR Juggler 1.1 and beyond where we can
run on top of NSPR.

Submitted by: Daniel Heath <DHeath@fueltechnv.com>

  • 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 /*
35  * --------------------------------------------------------------------------
36  * NOTES:
37  *    - This file (vjThreadPosix.h) MUST be included by vjThread.h, not the
38  *      other way around.
39  *    - The following libraries must be linked in at compile time:
40  *         HP-UX 10.20 --> -lcma
41  *         IRIX 6.x    --> -lpthread
42  * --------------------------------------------------------------------------
43  */
44
45 #ifndef _VJ_THREAD_POSIX_H_
46 #define _VJ_THREAD_POSIX_H_
47
48 #include <vjConfig.h>
49
50 #include <pthread.h>
51 #include <sys/types.h>
52 #include <unistd.h>
53 #include <signal.h>
54 #include <sched.h>
55
56 #ifdef HAVE_INTTYPES_H
57 #   include <inttypes.h>
58 #endif
59
60
61 #ifdef VJ_OS_Solaris
62 typedef unsigned int thread_id_t;
63 #elif defined(VJ_OS_FreeBSD)
64 typedef caddr_t thread_id_t;
65 #else
66 typedef uint32_t thread_id_t;
67 #endif
68
69 #include <Threads/vjThreadKeyPosix.h>     // To get the posix key stuff for storing self
70
71 //: Threads implementation using POSIX threads (both Draft 4 and the "final"
72 //+ draft of the standard are supported).
73 //
74 // Desc: <br>
75 //   Functions by recieving a function in the constructor that is the function
76 // to call when the new thread is created.  This function is stored internally
77 // to the class, then the class is "boot-strapped" by spawning a call
78 // to the startThread function with in turn will call the previously set thread
79 // function
80 //
81 //!PUBLIC_API:
82 class vjThreadPosix : public vjBaseThread
83 {
84 public// ---- Thread CREATION and SPAWNING -----
85     // -----------------------------------------------------------------------
86     //: Spawning constructor.
87     //
88     // This will actually start a new thread that will execute the specified
89     // function.
90     // -----------------------------------------------------------------------
91     vjThreadPosix(vj_thread_func_t func, void* arg = 0, long flags = 0,
92                   u_int priority = 0, void* stack_addr = NULL,
93                   size_t stack_size = 0);
94
95     // -----------------------------------------------------------------------
96     //: Spawning constructor with arguments (functor version).
97     //
98     // This will start a new thread that will execute the specified function.
99     // -----------------------------------------------------------------------
100     vjThreadPosix(vjBaseThreadFunctor* functorPtr, long flags = 0,
101                   u_int priority = 0, void* stack_addr = NULL,
102                   size_t stack_size = 0);
103
104     // -----------------------------------------------------------------------
105     //: Destructor.
106     //
107     //! PRE: None.
108     //! POST: This thread is removed from the thread table and from the local
109     //+       thread hash.
110     // -----------------------------------------------------------------------
111     virtual ~vjThreadPosix(void);
112
113     // -----------------------------------------------------------------------
114     //: Create a new thread that will execute functorPtr.
115     //
116     //! PRE: None.
117     //! POST: A thread (with any specified attributes) is created that begins
118     //+       executing func().  Depending on the scheduler, it may being
119     //+       execution immediately, or it may block for a short time before
120     //+       beginning execution.
121     //
122     //! ARGS: functorPtr - Function to be executed by the thread.
123     //! ARGS: flags - Flags for the thread--not currently used in this
124     //+               implementation (optional).
125     //! ARGS: priority - Priority of created thread (optional).
126     //! ARGS: stack_addr - Alternate address for thread's stack (optional).
127     //! ARGS: stack_size - Size for thread's stack (optional).
128     //
129     //! RETURNS: 0 - Successful thread creation
130     //! RETURNS: Nonzero - Error
131     //
132     //! NOTE: The pthreads implementation on HP-UX 10.20 does not allow the
133     //+       stack address to be changed.
134     // -----------------------------------------------------------------------
135     int spawn(vjBaseThreadFunctor* functorPtr, long flags = 0,
136               u_int priority = 0, void* stack_addr = NULL,
137               size_t stack_size = 0);
138
139     // Called by the spawn routine to start the user thread function
140     // PRE: Called ONLY by a new thread
141     // POST: The new thread will have started the user thread function
142     void startThread(void* null_param);
143
144 private:
145    vjBaseThreadFunctor* mUserThreadFunctor;     // The functor to call when the thread starts
146
147 public// ----- Various other thread functions ------
148
149     // -----------------------------------------------------------------------
150     //: Make the calling thread wait for the termination of this thread.
151     //
152     //! PRE: None.
153     //! POST: The caller blocks until this thread finishes its execution
154     //+       (i.e., calls the exit() method).  This routine may return
155     //+       immediately if this thread has already exited.
156     //
157     //! ARGS: status - Status value of the terminating thread when that
158     //+                thread calls the exit routine (optional).
159     //
160     //! RETURNS:  0 - Successful completion
161     //! RETURNS: -1 - Error
162     // -----------------------------------------------------------------------
163     virtual int
164     join (void** status = 0) {
165         return pthread_join(mThread, status);
166     }
167
168     // -----------------------------------------------------------------------
169     //: Resume the execution of a thread that was previously suspended using
170     //+ suspend().
171     //
172     //! PRE: This thread was previously suspended using the suspend() member
173     //+      function.
174     //! POST: This thread is sent the SIGCONT signal and is allowed to begin
175     //+       executing again.
176     //
177     //! RETURNS:  0 - Successful completion
178     //! RETURNS: -1 - Error
179     //
180     //! NOTE: This is not currently supported on HP-UX 10.20.
181     // -----------------------------------------------------------------------
182     virtual int
183     resume (void) {
184         return kill(SIGCONT);
185     }
186
187     // -----------------------------------------------------------------------
188     //: Suspend the execution of this thread.
189     //
190     //! PRE: None.
191     //! POST: This thread is sent the SIGSTOP signal and is thus suspended
192     //+       from execution until the member function resume() is called.
193     //
194     //! RETURNS:  0 - Successful completion
195     //! RETURNS: -1 - Error
196     //
197     //! NOTE: This is not currently supported on HP-UX 10.20.
198     // -----------------------------------------------------------------------
199     virtual int
200     suspend (void) {
201         return kill(SIGSTOP);
202     }
203
204     // -----------------------------------------------------------------------
205     //: Get this thread's priority.
206     //
207     //! PRE: None.
208     //! POST: The priority of this thread is returned in the integer pointer
209     //+       variable.
210     //
211     //! ARGS: prio - Pointer to an int variable that will have the thread's
212     //+              priority stored in it.
213     //
214     //! RETURNS:  0 - Successful completion
215     //! RETURNS: -1 - Error
216     //
217     //! NOTE: This is only supported on systems that support thread priority
218     //+       scheduling in their pthreads implementation.
219     // -----------------------------------------------------------------------
220     virtual int getPrio(int* prio);
221
222     // -----------------------------------------------------------------------
223     //: Set this thread's priority.
224     //
225     //! PRE: None.
226     //! POST: This thread has its priority set to the specified value.
227     //
228     //! ARGS: prio - The new priority for this thread.
229     //
230     //! RETURNS:  0 - Successful completion
231     //! RETURNS: -1 - Error
232     //
233     //! NOTE: This is only supported on systems that support thread priority
234     //+       scheduling in their pthreads implementation.
235     // -----------------------------------------------------------------------
236     virtual int setPrio(int prio);
237
238     // -----------------------------------------------------------------------
239     //: Set the CPU affinity for this thread (the CPU on which this thread
240     //+ will exclusively run).
241     //
242     //! PRE: The thread must have been set to be a system-scope thread.
243     //! POST: The CPU affinity is set or an error status is returned.
244     //
245     //! ARGS: cpu - The CPU on which this thread will run exclusively.
246     //
247     //! RETURNS:  0 - Successful completion
248     //! RETURNS: -1 - Error
249     //
250     //! NOTE: This is currently only available on IRIX 6.5 and is
251     //+       non-portable.
252     // -----------------------------------------------------------------------
253     virtual int
254     setRunOn (int cpu) {
255 #ifdef VJ_OS_IRIX
256         int ret_val;
257
258         if ( mScope == PTHREAD_SCOPE_SYSTEM ) {
259             ret_val = pthread_setrunon_np(cpu);
260         } else {
261             std::cerr << "This thread is not a system-scope thread!\n";
262             ret_val = -1;
263         }
264
265         return ret_val;
266 #else
267         std::cerr << "vjThreadPosix::setRunOn(): Not available on this system.\n";
268
269         return -1;
270 #endif
271     }
272
273     // -----------------------------------------------------------------------
274     //: Get the CPU affinity for this thread (the CPU on which this thread
275     //+ exclusively runs).
276     //
277     //! PRE: The thread must have been set to be a system-scope thread, and
278     //+      a previous affinity must have been set using setRunOn().
279     //! POST: The CPU affinity for this thread is stored in the cur_cpu
280     //+       pointer.
281     //
282     //! ARGS: cur_cpu - The CPU affinity for this thread (set by a previous
283     //+                 call to setRunOn().
284     //
285     //! RETURNS:  0 - Successful completion
286     //! RETURNS: -1 - Error
287     //
288     //! NOTE: This is currently only available on IRIX 6.5 and is
289     //+       non-portable.
290     // -----------------------------------------------------------------------
291     virtual int
292     getRunOn (int* cur_cpu) {
293 #ifdef VJ_OS_IRIX
294         int ret_val;
295
296         if ( mScope == PTHREAD_SCOPE_SYSTEM ) {
297             ret_val = pthread_getrunon_np(cur_cpu);
298         } else {
299             std::cerr << "This thread is not a system-scope thread!\n";
300             ret_val = -1;
301         }
302
303         return ret_val;
304 #else
305         std::cerr << "vjThreadPosix::getRunOn(): Not available on this system.\n";
306
307         return -1;
308 #endif
309     }
310
311     // -----------------------------------------------------------------------
312     //: Yield execution of the calling thread to allow a different blocked
313     //+ thread to execute.
314     //
315     //! PRE: None.
316     //! POST: The caller yields its execution control to another thread or
317     //+       process.
318     // -----------------------------------------------------------------------
319     virtual void
320     yield (void) {
321         sched_yield();
322     }
323
324     // -----------------------------------------------------------------------
325     //: Send the specified signal to this thread (not necessarily SIGKILL).
326     //
327     //! PRE: None.
328     //! POST: This thread receives the specified signal.
329     //
330     //! ARGS: signum - The signal to send to the specified thread.
331     //
332     //! RETURNS:  0 - Successful completion
333     //! RETURNS: -1 - Error
334     //
335     //! NOTE: This is not currently supported on HP-UX 10.20.
336     // -----------------------------------------------------------------------
337     virtual int
338     kill (int signum) {
339 #ifdef _PTHREADS_DRAFT_4
340         std::cerr << "vjThreadPosix::kill(): Signals cannot be sent to threads "
341                   << "with this POSIX threads implementation.\n";
342
343         return -1;
344 #else
345         return pthread_kill(mThread, signum);
346 #endif
347     }
348
349     // -----------------------------------------------------------------------
350     //: Kill (cancel) this thread.
351     //
352     //! PRE: None.
353     //! POST: This thread is cancelled.  Depending on the cancellation
354     //+       attributes of the specified thread, it may terminate
355     //+       immediately, it may wait until a pre-defined cancel point to
356     //+       stop or it may ignore the cancel altogether.  Thus, immediate
357     //+       cancellation is not guaranteed.
358     //
359     //! NOTE: For the sake of clarity, it is probably better to use the
360     //+       cancel() routine instead of kill() because a two-argument
361     //+       version of kill() is also used for sending signals to threads.
362     //+       This kill() and cancel() do exactly the same thing.
363     // -----------------------------------------------------------------------
364     virtual void
365     kill (void) {
366         pthread_cancel(mThread);
367     }
368
369     // -----------------------------------------------------------------------
370     //: Get a ptr to the thread we are in.
371     //
372     //! RETURNS: NULL - Thread is not in global table
373     //! RETURNS: NonNull - Ptr to the thread that we are running within
374     // -----------------------------------------------------------------------
375     static vjBaseThread* self(void);
376
377     // -----------------------------------------------------------------------
378     //: Provide a way of printing the process ID neatly.
379     // -----------------------------------------------------------------------
380     std::ostream&
381     outStream (std::ostream& out) {
382         out.setf(std::ios::right);
383         out << std::setw(7) << std::setfill('0') << getpid() << "/";
384         out.unsetf(std::ios::right);
385         vjBaseThread::outStream(out);
386         out << std::setfill(' ');
387         return out;
388     }
389
390 // All private member variables and functions.
391 private:
392     pthread_t   mThread;        //: pthread_t data structure for this thread
393     int         mScope;         //: Scope (process or system) of this thread
394
395     //void checkRegister(int status);
396
397     // -----------------------------------------------------------------------
398     //: Get a hash index for this thread.  This will always be a nonzero
399     //+ value.
400     //
401     //! PRE: None.
402     //! POST: The hash index for this thread is returned to the caller.
403     //
404     //! RETURNS: Nonzero - The hash index of this tread.
405     // -----------------------------------------------------------------------
406     inline thread_id_t
407     hash (void) {
408 #if defined(VJ_OS_IRIX)
409         return mThread;
410 #else
411         // This works on Linux, Solaris and FreeBSD.
412         return (thread_id_t) mThread;
413 #endif    /* VJ_OS_IRIX */
414     }
415
416     // -----------------------------------------------------------------------
417     //: Get a hash index for the given thread.  This will always be a nonzero
418     //+ value.
419     //
420     //! PRE: None.
421     //! POST: The hash index for the given thread is returned to the caller.
422     //
423     //! ARGS: thread: A pthread_t structure whose hash index will be
424     //+       determined and returned.
425     //
426     //! RETURNS: Nonzero - The hash index of the given tread.
427     // -----------------------------------------------------------------------
428     inline static thread_id_t
429     hash (pthread_t thread) {
430 #ifdef VJ_OS_IRIX
431         return thread;
432 #else
433         // This works on Linux, Solaris and FreeBSD.
434         return (thread_id_t) thread;
435 #endif
436     }
437
438     // -----------------------------------------------------------------------
439     //: Get this thread's ID (i.e., its hash index for the thread table).  It
440     //+ will always be greater than 0.
441     //
442     //! PRE: None.
443     //! POST: The hash index ID for this thread is returned to the caller.
444     //
445     //! RETURNS: Nonzero - The hash index of this tread.
446     // -----------------------------------------------------------------------
447     inline static thread_id_t
448     gettid (void) {
449         pthread_t me;
450
451         me = pthread_self();
452
453         return hash(me);
454     }
455
456 public:
457     struct staticWrapper
458     {
459        staticWrapper() : mStaticsInitialized(1221), mThreadIdKey(NULL)
460        {;}
461
462        unsigned          mStaticsInitialized;    // Just a debug helper to try to find times when people call us before the statics are created   
463        vjThreadKeyPosix  mThreadIdKey;           // Key for the id of the local thread
464     };
465
466     static vjThreadKeyPosix& threadIdKey()
467     {
468       return statics.mThreadIdKey;
469     }
470
471     static staticWrapper statics;
472 };
473
474
475 #endif   /* _VJ_THREAD_POSIX_H_ */
Note: See TracBrowser for help on using the browser.