Line data Source code
1 : /// Thread.cpp
2 : ///
3 : /// @author Paul Grenz
4 : ///
5 : ////////////////////////////////////////////////////////////////////////////////
6 :
7 : #include <iostream>
8 : #include "Thread.hpp"
9 : #ifdef WIN32
10 : #include <windows.h>
11 : #else
12 : #include <errno.h>
13 : #include <signal.h>
14 : #include <unistd.h>
15 : #include <sys/types.h>
16 : #include <sys/time.h>
17 : #include <pthread.h>
18 : #include <string.h>
19 : #include <sched.h>
20 : #endif
21 :
22 : using std::string;
23 : using pcf::Thread;
24 : using pcf::SystemSocket;
25 :
26 : ////////////////////////////////////////////////////////////////////////////////
27 : /// pcf::Thread::sm_nStopSignal is the signal sent to ensure that
28 : /// system calls exit with a 'EINTR' error.
29 :
30 : int pcf::Thread::sm_nStopSignal = SIGQUIT;
31 :
32 : ////////////////////////////////////////////////////////////////////////////////
33 : /// Standard constructor.
34 :
35 12 : Thread::Thread() : m_idThis(0), m_uiInterval(1000), m_tState(Idle), m_oStop(true),
36 12 : m_oOneShot(false), m_oIsRunning(false), m_oIsPaused(false), m_psocTrigger(NULL)
37 : {
38 : // We are not running in 'execute' yet.
39 12 : m_mutReady.lock();
40 :
41 12 : setupPipe();
42 12 : }
43 :
44 : ////////////////////////////////////////////////////////////////////////////////
45 : /// Standard destructor. Will stop any thread automatically.
46 :
47 12 : Thread::~Thread()
48 : {
49 12 : stop();
50 12 : join();
51 :
52 12 : ::close( m_pfdPipe[0] );
53 12 : ::close( m_pfdPipe[1] );
54 12 : m_pfdPipe[0] = -1;
55 12 : m_pfdPipe[1] = -1;
56 12 : }
57 :
58 : ////////////////////////////////////////////////////////////////////////////////
59 : /// Assignment operator.
60 : /// @param copy An existing Thread that is being copied. This one will be
61 : /// stopped if it is currently running, and once assigned will not initially
62 : /// be running.
63 : /// @return A reference to this Thread object.
64 :
65 0 : const Thread &Thread::operator=( const Thread © )
66 : {
67 0 : if ( © != this )
68 : {
69 0 : stop();
70 0 : join();
71 :
72 0 : m_uiInterval = copy.m_uiInterval;
73 0 : m_oOneShot = copy.m_oOneShot;
74 0 : m_idThis = 0;
75 0 : m_oStop = true;
76 0 : m_oIsRunning = false;
77 0 : m_oIsPaused = false;
78 0 : m_psocTrigger = NULL;
79 0 : m_tState = Idle;
80 :
81 : // We are not running in 'execute' yet.
82 0 : m_mutReady.lock();
83 : }
84 0 : return *this;
85 : }
86 :
87 : ////////////////////////////////////////////////////////////////////////////////
88 : /// Copy constructor.
89 : /// @param copy An existing Thread that will be used to initialize this one. The
90 : /// parameters will be copied, but if the original is running, this one will not
91 : /// be.
92 :
93 0 : Thread::Thread( const Thread © ) : m_idThis(0), m_uiInterval(copy.m_uiInterval), m_tState(Idle), m_oStop(true),
94 0 : m_oOneShot(copy.m_oOneShot), m_oIsRunning(false), m_oIsPaused(false), m_psocTrigger(NULL)
95 : {
96 : // We are not running in 'execute' yet.
97 0 : m_mutReady.lock();
98 :
99 0 : setupPipe();
100 0 : }
101 :
102 : ////////////////////////////////////////////////////////////////////////////////
103 : /// Setup the pipe - this is used to kick the thread out of 'select';
104 : /// (the infamous 'self-pipe' trick)
105 :
106 12 : void Thread::setupPipe()
107 : {
108 : // Set the file descriptors to an invald value.
109 : // If we cannot initialize the fd's correctly, we will fail when we try
110 : // to pause.
111 12 : m_pfdPipe[0] = -1;
112 12 : m_pfdPipe[1] = -1;
113 :
114 12 : if ( ::pipe( m_pfdPipe ) == 0 )
115 : {
116 : // Set both the read and write ends non-blocking.
117 36 : for ( uint64_t ii = 0; ii < 2; ii++ )
118 : {
119 24 : int iFlags = 0;
120 24 : if ( ( iFlags = ::fcntl( m_pfdPipe[ii], F_GETFL ) ) == -1 )
121 : {
122 0 : ::close( m_pfdPipe[0] );
123 0 : ::close( m_pfdPipe[1] );
124 0 : m_pfdPipe[0] = -1;
125 0 : m_pfdPipe[1] = -1;
126 0 : break;
127 : }
128 24 : iFlags |= O_NONBLOCK;
129 24 : if ( ::fcntl( m_pfdPipe[ii], F_SETFL, iFlags ) == -1 )
130 : {
131 0 : ::close( m_pfdPipe[0] );
132 0 : ::close( m_pfdPipe[1] );
133 0 : m_pfdPipe[0] = -1;
134 0 : m_pfdPipe[1] = -1;
135 0 : break;
136 : }
137 : }
138 : }
139 12 : }
140 :
141 : ////////////////////////////////////////////////////////////////////////////////
142 : /// @return The interval to wait in between 'execute' calls.
143 :
144 0 : unsigned int Thread::getInterval() const
145 : {
146 0 : return m_uiInterval;
147 : }
148 :
149 : ////////////////////////////////////////////////////////////////////////////////
150 : /// @return The current state the running thread is in.
151 :
152 0 : Thread::State Thread::getState() const
153 : {
154 0 : return m_tState;
155 : }
156 :
157 : ////////////////////////////////////////////////////////////////////////////////
158 : /// Sets the socket file descriptor which will be used to cause the 'execute'
159 : /// method to run. If the socket descriptor is valid, the 'runLoop' will
160 : /// check to see if there is data waiting to be read on the socket and will
161 : /// not call 'execute' until there is.
162 : ///
163 0 : void Thread::setTrigger( pcf::SystemSocket *psocTrigger )
164 : {
165 0 : m_psocTrigger = psocTrigger;
166 0 : }
167 :
168 : ////////////////////////////////////////////////////////////////////////////////
169 : /// Sets the interval to wait in between 'execute' calls.
170 :
171 12 : void Thread::setInterval( const unsigned int &uiInterval )
172 : {
173 12 : m_uiInterval = uiInterval;
174 12 : }
175 :
176 : ////////////////////////////////////////////////////////////////////////////////
177 : /// Returns true if the 'stop' flag has been set to true. The thread
178 : /// may still be running its last iteration, though. (see 'isRunning').
179 :
180 0 : bool Thread::isStopping() const
181 : {
182 0 : return m_oStop;
183 : }
184 :
185 : ////////////////////////////////////////////////////////////////////////////////
186 : /// Returns whether or not the Thread is running. "isRunning" will still return
187 : /// true, even if the Thread is paused.
188 : /// @return True if the Thread is running, false if it is not.
189 :
190 30 : bool Thread::isRunning() const
191 : {
192 30 : return m_oIsRunning;
193 : }
194 :
195 : ////////////////////////////////////////////////////////////////////////////////
196 : /// Returns whether or not the Thread is paused. "isRunning" will still return
197 : /// true, even if the Thread is paused.
198 : /// @return True if the Thread is paused, false if it is not.
199 :
200 0 : bool Thread::isPaused() const
201 : {
202 0 : return m_oIsPaused;
203 : }
204 :
205 : ////////////////////////////////////////////////////////////////////////////////
206 : /// Pauses the Thread. "stop" will still end it. Calling 'pause' twice or more
207 : /// will have no effect.
208 :
209 0 : void Thread::pause()
210 : {
211 0 : m_oIsPaused = true;
212 0 : }
213 :
214 : ////////////////////////////////////////////////////////////////////////////////
215 : /// Resumes the Thread if it is paused. Calling 'resume' twice or more will have
216 : /// no effect.
217 :
218 0 : void Thread::resume()
219 : {
220 0 : m_oIsPaused = false;
221 :
222 : // Write a char to the pipe to kick the thread out of the 'select' call.
223 0 : int rv = ::write( m_pfdPipe[1], "A", 1 );
224 0 : if(rv < 0) std::cerr << __FILE__ << " " << __LINE__ << " " << strerror(errno) << "\n";
225 0 : }
226 :
227 : ////////////////////////////////////////////////////////////////////////////////
228 : /// Resumes the thread if it is paused, but only for one iteration. Calling
229 : /// 'resumeOnce' twice or more will have no effect.
230 :
231 0 : void Thread::resumeOnce()
232 : {
233 : // Write a char to the pipe to kick the thread out of the 'select' call.
234 0 : int rv = ::write( m_pfdPipe[1], "A", 1 );
235 0 : if(rv < 0) std::cerr << __FILE__ << " " << __LINE__ << " " << strerror(errno) << "\n";
236 0 : }
237 :
238 : ////////////////////////////////////////////////////////////////////////////////
239 : /// Sets the flag to stop the Thread. This will cause 'afterExecute' to be
240 : /// called.
241 :
242 15 : void Thread::stop()
243 : {
244 15 : m_oStop = true;
245 :
246 : // Send a signal to ensure that any system calls return and enable
247 : // the checking of the stop flag.
248 15 : if ( m_idThis != 0 )
249 6 : ::pthread_kill( m_idThis, Thread::sm_nStopSignal );
250 15 : }
251 :
252 : ////////////////////////////////////////////////////////////////////////////////
253 : /// Puts the calling thread to sleep for uiSeconds seconds.
254 : /// @param uiSeconds The number of seconds to go to sleep.
255 : /// @return An error code. See 'nanosleep' for more details.
256 :
257 0 : int Thread::sleep( const unsigned int &uiSeconds )
258 : {
259 0 : return nanosleep( uiSeconds, 0 );
260 : }
261 :
262 : ////////////////////////////////////////////////////////////////////////////////
263 : /// Puts the calling thread to sleep for uiMillis milliseconds.
264 : /// @param uiMillis The number of milliseconds to go to sleep.
265 : /// @return An error code. See 'nanosleep' for more details.
266 :
267 3 : int Thread::msleep( const unsigned int &uiMillis )
268 : {
269 3 : return nanosleep( uiMillis / 1000, uiMillis % 1000 * 1000000 );
270 : }
271 :
272 : ////////////////////////////////////////////////////////////////////////////////
273 : /// Puts the calling thread to sleep for uiMicros microseconds.
274 : /// @param uiMicros The number of microseconds to go to sleep.
275 : /// @return An error code. See 'nanosleep' for more details.
276 :
277 0 : int Thread::usleep( const unsigned int &uiMicros )
278 : {
279 0 : return nanosleep( uiMicros / 1000000, uiMicros % 1000000 * 1000 );
280 : }
281 :
282 : ////////////////////////////////////////////////////////////////////////////////
283 : /// Puts the calling thread to sleep for uiNanos nanoseconds.
284 : /// @param uiNanos The number of nanoseconds to go to sleep.
285 : /// @return An error code. See 'nanosleep' for more details.
286 :
287 0 : int Thread::nsleep( const unsigned int &uiNanos )
288 : {
289 0 : return nanosleep( uiNanos / 1000000000, uiNanos % 1000000000 );
290 : }
291 :
292 : ////////////////////////////////////////////////////////////////////////////////
293 : /// Puts the calling thread to sleep for a specific amount of time. Under
294 : /// windows, the best we can do is a millisecond resolution without a third
295 : /// party library, so the other calls will be estimated. This will always
296 : /// return ErrNone under windows, as no error information is available.
297 : /// @param uiSeconds The number of seconds to go to sleep.
298 : /// @param uiNanos An additional number of nanoseconds to sleep.
299 : /// @return ErrNone The sleep occurred successfully.
300 : /// @return ErrInterrupted The sleep was interupted by a system call (signal).
301 : /// @return ErrInvalidParameter Invalid parameter to function call.
302 : /// @return ErrCopy
303 :
304 3 : int Thread::nanosleep( const unsigned int &uiSeconds,
305 : const unsigned int &uiNanos )
306 : {
307 3 : int nErr = ErrNone;
308 :
309 : #ifdef WIN32
310 : DWORD uiMillis = uiSeconds * 1000 + uiNanos / 1000000;
311 : Sleep( uiMillis );
312 : #else
313 : timespec ts;
314 3 : ts.tv_sec = uiSeconds;
315 3 : ts.tv_nsec = uiNanos;
316 :
317 : // Minus sign to convert to our error code.
318 3 : nErr = - ::nanosleep( &ts, NULL );
319 :
320 : #endif
321 :
322 3 : return nErr;
323 : }
324 :
325 : ////////////////////////////////////////////////////////////////////////////////
326 : /// Suspends the calling thread until the thread managed by this object
327 : /// finishes.
328 : /// @return ErrNone
329 : /// @return ErrThreadUnjoinable
330 : /// @return ErrBadThreadId
331 : /// @return ErrDeadlock
332 :
333 15 : int Thread::join()
334 : {
335 : // The pthread_join() function shall suspend execution of the calling thread
336 : // until the target thread terminates, unless the target thread
337 : // has already terminated. On return from a successful pthread_join()
338 : // call with a non-NULL value_ptr argument, the value passed to
339 : // pthread_exit() by the terminating thread shall be made available in
340 : // the location referenced by value_ptr. When a pthread_join() returns
341 : // successfully, the target thread has been terminated. The results of
342 : // multiple simultaneous calls to pthread_join() specifying the same target
343 : // thread are undefined. If the thread calling pthread_join() is canceled,
344 : // then the target thread shall not be detached.
345 : // It is unspecified whether a thread that has exited but remains
346 : // unjoined counts against {PTHREAD_THREADS_MAX}.
347 :
348 15 : int nErr = ErrNone;
349 :
350 15 : if ( m_oIsRunning == false )
351 : {
352 12 : nErr = -EHOSTDOWN;
353 : }
354 : #ifdef WIN32
355 : else if ( m_idThis != NULL )
356 : {
357 : // throw away the result of the thread.
358 : nErr = WaitForSingleObject( m_idThis, INFINITE );
359 :
360 : switch ( nErr )
361 : {
362 : case WAIT_ABANDONED:
363 : nErr = -EINTR;
364 : break;
365 : case WAIT_OBJECT_0:
366 : nErr = ErrNone;
367 : break;
368 : case WAIT_TIMEOUT:
369 : nErr = -ETIMEDOUT;
370 : break;
371 : case WAIT_FAILED:
372 : nErr = -EINVAL;
373 : break;
374 : default:
375 : nErr = ErrUnknown;
376 : break;
377 : }
378 : Thread::msleep( 1 );
379 : // Do not set the thread id back to 0, as this will cause a mem leak!
380 : //m_idThis = 0;
381 : }
382 : #else
383 3 : else if ( m_idThis != 0 )
384 : {
385 : // Throw away the result of the thread.
386 : void *pResult;
387 : // Minus sign to convert to our error code.
388 3 : nErr = - ::pthread_join( m_idThis, &pResult );
389 : // Do not set the thread id back to 0, as this will cause a mem leak!
390 : //m_idThis = 0;
391 : // Convert to our error code as necessary.
392 3 : nErr = ( nErr == -EINVAL ) ? ( -ENODEV ) : ( nErr );
393 : }
394 : #endif
395 :
396 15 : return nErr;
397 : }
398 :
399 : ////////////////////////////////////////////////////////////////////////////////
400 : /// Override this function to do something before the thread has been told to
401 : /// start, like allocate memory.
402 :
403 0 : void Thread::beforeExecute()
404 : {
405 0 : }
406 :
407 : ////////////////////////////////////////////////////////////////////////////////
408 : /// Override this function to do something after the thread has been told to
409 : /// stop, like clean up allocated memory.
410 :
411 0 : void Thread::afterExecute()
412 : {
413 0 : }
414 :
415 : ////////////////////////////////////////////////////////////////////////////////
416 : /// Override in derived class, place the code to do something here.
417 :
418 0 : void Thread::execute()
419 : {
420 0 : }
421 :
422 : ////////////////////////////////////////////////////////////////////////////////
423 : /// Waits for the 'ready' mutex to be unlocked. This indicates that the
424 : /// 'execute' function is about to be run.
425 :
426 0 : void Thread::waitForReady()
427 : {
428 : // We will wait here until we can get the lock.
429 0 : m_mutReady.lock();
430 : // unlock it immediately, we can can continue now.
431 0 : m_mutReady.unlock();
432 0 : }
433 :
434 : ////////////////////////////////////////////////////////////////////////////////
435 : /// Initializes the Thread by calling 'beforeExecute', then loops, calling
436 : /// 'execute' until 'm_oStop' is true. Then calls 'afterExecute' and ends.
437 :
438 3 : void Thread::runLoop()
439 : {
440 : // Make sure we can handle the signal which will come when we want to stop.
441 : // This is signal will ensure that we are not stuck waiting on I/O.
442 : // Any system calls in progress should return with an "EINTR" error.
443 3 : ::memset( &m_saStop, 0, sizeof( struct sigaction ) );
444 3 : m_saStop.sa_handler = Thread::processSignalHandler;
445 3 : sigemptyset( &m_saStop.sa_mask );
446 3 : ::sigaction( Thread::sm_nStopSignal, &m_saStop, 0 );
447 :
448 : // Ensure the loop starts.
449 3 : m_oStop = false;
450 3 : m_oIsRunning = true;
451 :
452 : // Call function to allow user to set things up before the
453 : // main loop starts.
454 3 : m_tState = BeforeExecute;
455 3 : beforeExecute();
456 :
457 : // Once we are about to enter the 'execute' method, we are ready to do
458 : // whatever this thread needs to do!
459 3 : m_mutReady.unlock();
460 :
461 : // The main loop.
462 3 : m_tState = Execute;
463 6 : while ( m_oStop == false )
464 : {
465 : // This is a loop that is entered pausing the polling
466 : // and processing. quitting will end it as well.
467 3 : if ( m_oIsPaused == true )
468 : {
469 : // Create and clear out the FD set.
470 : fd_set fdsRead;
471 0 : FD_ZERO( &fdsRead );
472 0 : FD_SET( m_pfdPipe[0], &fdsRead);
473 0 : int nHighestNumberedFd = m_pfdPipe[0];
474 : // Wait for it....
475 0 : ::select( nHighestNumberedFd+1, &fdsRead, NULL, NULL, NULL );
476 : // Did we get knocked out of 'select' by something on the pipe?
477 0 : if ( FD_ISSET( m_pfdPipe[0], &fdsRead ) )
478 : {
479 : // Read the single char sent.
480 : char ch;
481 0 : int rv = ::read( m_pfdPipe[0], &ch, 1 );
482 0 : if(rv < 0) std::cerr << __FILE__ << " " << __LINE__ << " " << strerror(errno) << "\n";
483 : }
484 : }
485 :
486 : // Check to see if we should stop looping, since the flag may have
487 : // toggled while we were paused, above.
488 3 : if ( m_oStop == true )
489 0 : break;
490 :
491 : // Do we have a trigger? In this case, we have a socket which
492 : // we will use to signal the "execute" method to run. This will
493 : // happen if we have data available to be read on said socket.
494 3 : if ( m_psocTrigger != NULL && m_psocTrigger->isValid() == true )
495 : {
496 : // Create and clear out the FD set.
497 : fd_set fdsRead;
498 0 : FD_ZERO( &fdsRead );
499 : // Watch the to see when we get some input.
500 0 : FD_SET( m_psocTrigger->getFd(), &fdsRead );
501 0 : int nHighestNumberedFd = m_psocTrigger->getFd();
502 : // Wait for it....
503 0 : ::select( nHighestNumberedFd+1, &fdsRead, NULL, NULL, NULL );
504 : }
505 :
506 : // Check to see if we should stop looping, since the flag may have
507 : // toggled while we were waiting for a trigger, above.
508 3 : if ( m_oStop == true )
509 0 : break;
510 :
511 : // Wait for a bit....
512 : // If we have set a trigger, above, we may not want to wait here.
513 3 : if ( m_uiInterval > 0 )
514 3 : msleep( m_uiInterval );
515 :
516 : // Check to see if we should stop looping, since the flag may have
517 : // toggled while we were sleeping, above.
518 3 : if ( m_oStop == true )
519 0 : break;
520 :
521 : // Call the function to actually do something.
522 3 : execute();
523 :
524 : // If this is a one-shot Thread, 'stop' will become true here.
525 3 : m_oStop = ( m_oOneShot || m_oStop );
526 : }
527 :
528 : // Call function to allow user to clean things up before the
529 : // thread exits. There must be nothing done after this.
530 3 : m_tState = AfterExecute;
531 3 : afterExecute();
532 :
533 3 : m_oIsRunning = false;
534 :
535 3 : m_tState = Idle;
536 3 : }
537 :
538 : ////////////////////////////////////////////////////////////////////////////////
539 : /// Code to get a new Thread running.
540 : /// We need a static function for the 'pthread_create' or 'CreateThread'
541 : /// call - see below. We can also pass in a CPU number to set the affinity
542 : /// of this thread to a particular CPU.
543 : /// @param iCpuAffinity The CPU to run this thread on.
544 : /// @return ErrNone
545 : /// @return ErrAlreadyRunning
546 : /// @return ErrCouldNotCreateThread
547 : /// @return ErrInvalidParameter
548 : /// @return ErrWrongPermission
549 :
550 3 : int Thread::start( const int &iCpuAffinity,
551 : const ScheduleType &tSchedule )
552 : {
553 : // The pthread_create() function shall create a new thread, with
554 : // attributes specified by attr, within a process. If attr is NULL, the
555 : // default attributes shall be used. If the attributes specified by attr
556 : // are modified later, the thread’s attributes shall not be affected.
557 : // Upon successful completion, pthread_create() shall store the ID of the
558 : // created thread in the location referenced by thread.
559 : //
560 : // The thread is created executing start_routine with arg as its sole
561 : // argument. If the start_routine returns, the effect shall be as if
562 : // there was an implicit call to pthread_exit() using the return value of
563 : // start_routine as the exit status. Note that the thread in which main()
564 : // was originally invoked differs from this. When it returns from main(),
565 : // the effect shall be as if there was an implicit call to exit() using
566 : // the return value of main() as the exit status.
567 :
568 3 : int nErr = ErrNone;
569 :
570 3 : if ( m_oIsRunning != false )
571 : {
572 0 : nErr = -EALREADY;
573 : }
574 : else
575 : {
576 : #ifdef WIN32
577 : DWORD idDummy;
578 : m_idThis = CreateThread( NULL, 0, Thread::threadFuncWin,
579 : this, 0, &idDummy );
580 : nErr = ( m_idThis == 0 ) ? ( -EAGAIN ) : ( ErrNone );
581 : #else
582 : #ifndef __APPLE__
583 :
584 : // We need an attributes object to modify the behavior of the new thread.
585 : sched_param param;
586 : pthread_attr_t attr;
587 3 : ::pthread_attr_init( &attr );
588 :
589 : // Should we set the affinity of this thread to a particular CPU?
590 3 : if ( iCpuAffinity > -1 )
591 : {
592 : // Get the number of CPU's on this system.
593 0 : int iCpuCount = ::sysconf( _SC_NPROCESSORS_ONLN );
594 :
595 : // Make sure we have chosen a CPU that exists. If it doesn't,
596 : // we will fail silently and run on whatever CPU the scheduler decrees.
597 0 : if ( iCpuAffinity < iCpuCount )
598 : {
599 : // Create a CPU set containing the current cpu index.
600 : cpu_set_t setCpu;
601 0 : CPU_ZERO( &setCpu );
602 0 : CPU_SET( iCpuAffinity, &setCpu );
603 0 : ::pthread_attr_setaffinity_np( &attr, sizeof( cpu_set_t ), &setCpu );
604 : }
605 : }
606 :
607 : // Set the scheduler attributes for the thread we are about to create.
608 3 : switch ( tSchedule )
609 : {
610 : // Nothing special for this thread; just use whatever is set here.
611 3 : case Inherit:
612 3 : ::pthread_attr_setinheritsched( &attr, PTHREAD_INHERIT_SCHED );
613 3 : break;
614 : // Specifically ask for normal scheduling and priority.
615 0 : case Normal:
616 0 : ::pthread_attr_setinheritsched( &attr, PTHREAD_EXPLICIT_SCHED );
617 0 : param.sched_priority = 0;
618 0 : ::pthread_attr_setschedparam( &attr, ¶m);
619 0 : ::pthread_attr_setschedpolicy( &attr, SCHED_OTHER );
620 0 : break;
621 : // Ask for better scheduling and priority.
622 0 : case Turbo:
623 0 : ::pthread_attr_setinheritsched( &attr, PTHREAD_EXPLICIT_SCHED );
624 0 : param.sched_priority = ::sched_get_priority_max( SCHED_FIFO );
625 0 : ::pthread_attr_setschedparam( &attr, ¶m);
626 0 : ::pthread_attr_setschedpolicy( &attr, SCHED_FIFO );
627 : }
628 :
629 : // Minus sign to convert to our error code.
630 3 : nErr = - ::pthread_create( &m_idThis, &attr, Thread::pthreadFunc, this );
631 :
632 : #endif
633 : #endif
634 : }
635 3 : return nErr;
636 : }
637 :
638 : #ifdef WIN32
639 : ////////////////////////////////////////////////////////////////////////////////
640 : /// 'CreateThread' needs a static function to get the
641 : /// thread going. Passing a pointer back to the Thread object allows us to
642 : /// call the 'runLoop' function from within the new thread.
643 : /// @param A pointer to this class that the thread function can use.
644 :
645 : DWORD WINAPI Thread::threadFuncWin( void *pUnknown )
646 : {
647 : // do a static cast to get the pointer back to a "Thread" object.
648 : Thread *pThis = static_cast<Thread *>( pUnknown );
649 :
650 : // we are now within the new thread and up and running.
651 : pThis->runLoop();
652 :
653 : /// no return is necessary, since it is not examined.
654 : return 0;
655 : }
656 :
657 : #else
658 : ////////////////////////////////////////////////////////////////////////////////
659 : /// 'pthread_create' needs a static function to get the
660 : /// thread going. Passing a pointer back to the Thread object allows us to
661 : /// call the 'runLoop' function from within the new thread.
662 : /// @param A pointer to this class that the thread function can use.
663 :
664 3 : void *Thread::pthreadFunc( void *pUnknown )
665 : {
666 : // do a static cast to get the pointer back to a "Thread" object.
667 3 : Thread *pThis = static_cast<Thread *>( pUnknown );
668 :
669 : // we are now within the new thread and up and running.
670 : try
671 : {
672 3 : pThis->runLoop();
673 : }
674 0 : catch ( const std::exception &excep )
675 : {
676 0 : std::cerr << "Thread exited: " << excep.what() << std::endl;
677 0 : }
678 0 : catch ( ... )
679 : {
680 0 : std::cerr << "An exception was thrown, exiting the thread." << std::endl;
681 0 : }
682 :
683 : /// no return is necessary, since it is not examined.
684 3 : return NULL;
685 : }
686 : #endif
687 :
688 : ////////////////////////////////////////////////////////////////////////////////
689 : /// This variable and function are used to trap a signal to tell the thread
690 : /// to return from any system calls gracefully.
691 :
692 3 : void Thread::processSignalHandler( int nSignal )
693 : {
694 : static_cast<void>(nSignal);
695 : // The signal handler is not re-installed, so it will not work again.
696 3 : }
697 :
698 : ////////////////////////////////////////////////////////////////////////////////
699 : /// Returns a message associated with an error code.
700 : /// @param nErr The error code.
701 : /// @return A message associated with the error.
702 :
703 0 : string Thread::getErrorMsg( const int &nErr )
704 : {
705 0 : switch ( nErr )
706 : {
707 0 : case ErrNone:
708 0 : return string( "No Error." );
709 : break;
710 0 : case ErrThreadUnjoinable:
711 0 : return string( "Thread unjoinable." );
712 : break;
713 0 : case ErrBadThreadId:
714 0 : return string( "Bad thread Id." );
715 : break;
716 0 : case ErrDeadlock:
717 0 : return string( "Operation would deadlock." );
718 : break;
719 0 : case ErrCouldNotCreateThread:
720 0 : return string( "Could not create thread." );
721 : break;
722 0 : case ErrInvalidParameter:
723 0 : return string( "Invalid parameter to function call." );
724 : break;
725 0 : case ErrWrongPermission:
726 0 : return string( "Wrong permission." );
727 : break;
728 0 : case ErrAlreadyRunning:
729 0 : return string( "Thread already running." );
730 : break;
731 0 : case ErrInterrupted:
732 0 : return string( "Sleep was interrupted before it could complete." );
733 : break;
734 0 : case ErrCopy:
735 0 : return string( "Information could not be copied from user space." );
736 : break;
737 0 : case ErrTimedOut:
738 0 : return string( "Timed out waiting for thread." );
739 : break;
740 0 : case ErrNotRunning:
741 0 : return string( "Thread is not running." );
742 : break;
743 0 : case ErrUnknown:
744 0 : return string( "Unknown error." );
745 : break;
746 : }
747 0 : return string( "" );
748 : }
749 :
750 : ////////////////////////////////////////////////////////////////////////////////
|