CARMA C++
StartPthread.h
Go to the documentation of this file.
1 #ifndef CARMA_UTIL_START_PTHREAD_H
2 #define CARMA_UTIL_START_PTHREAD_H
3 
4 #include <stdexcept>
5 #include <string>
6 
7 #include <pthread.h>
8 
9 #include <log4cpp/NDC.hh>
10 
11 #include "carma/util/PthreadAttr.h"
12 #include "carma/util/PthreadMutex.h"
13 #include "carma/util/PthreadCond.h"
14 #include "carma/util/ScopedLock.h"
15 #include "carma/util/ScopedPthreadCancelDisable.h"
16 #include "carma/util/ThreadQuit.h"
17 
20 
21 namespace carma {
22 namespace util {
23 
24 //
25 // Basic idea here:
26 // IF:
27 // 1. You have a function F returning void and taking an argument of type
28 // reference (or const reference) to T.
29 //
30 // AND
31 //
32 // 2. You have an object X (or a reference to X or a const reference to X)
33 // of type T
34 //
35 // THEN:
36 // 3. StartPthreadWithCopy( F, X ) will start a new pthread and call F with
37 // a reference to a copy of your original X.
38 //
39 // AND/OR
40 //
41 // 4. StartPthreadWithRef( F, X ) will start a new pthread and call F with
42 // a reference to your original X.
43 //
44 
45 
59 template < typename ArgType >
60 ::pthread_t StartPthreadWithCopy(
61  void (*ep)( ArgType & a ),
62  const ArgType & arg,
63  const ::std::string & initialLogNDC = ::std::string(),
64  const ::pthread_attr_t * attr = 0,
65  bool startCancelable = false );
66 
67 // @copydoc carma::util::StartPthreadWithCopy
68 template < typename ArgType >
69 ::pthread_t StartPthreadWithCopy(
70  void (*ep)( ArgType & a ),
71  const ArgType & arg,
72  const ::std::string & initialLogNDC,
73  const PthreadAttr & attr,
74  bool startCancelable = false );
75 
76 // @copydoc carma::util::StartPthreadWithCopy
77 template < typename ArgType >
78 ::pthread_t StartPthreadWithCopy(
79  void (*ep)( const ArgType & a ),
80  const ArgType & arg,
81  const ::std::string & initialLogNDC = ::std::string(),
82  const ::pthread_attr_t * attr = 0,
83  bool startCancelable = false );
84 
85 // @copydoc carma::util::StartPthreadWithCopy
86 template < typename ArgType >
87 ::pthread_t StartPthreadWithCopy(
88  void (*ep)( const ArgType & a ),
89  const ArgType & arg,
90  const ::std::string & initialLogNDC,
91  const PthreadAttr & attr,
92  bool startCancelable = false );
93 
94 // @copydoc carma::util::StartPthreadWithCopy
95 template < typename ArgType >
96 ::pthread_t StartPthreadWithCopy(
97  void (*ep)( const ArgType * & a ),
98  ArgType * const & arg,
99  const ::std::string & initialLogNDC = ::std::string(),
100  const ::pthread_attr_t * attr = 0,
101  bool startCancelable = false );
102 
103 // @copydoc carma::util::StartPthreadWithCopy
104 template < typename ArgType >
105 ::pthread_t StartPthreadWithCopy(
106  void (*ep)( const ArgType * & a ),
107  ArgType * const & arg,
108  const ::std::string & initialLogNDC,
109  const PthreadAttr & attr,
110  bool startCancelable = false );
111 
112 
126 template < typename ArgType >
127 ::pthread_t StartPthreadWithRef(
128  void (*ep)( ArgType & a ),
129  ArgType & arg,
130  const ::std::string & initialLogNDC = ::std::string(),
131  const ::pthread_attr_t * attr = 0,
132  bool startCancelable = false );
133 
134 // @copydoc StartPthreadWithRef
135 template < typename ArgType >
136 ::pthread_t StartPthreadWithRef(
137  void (*ep)( ArgType & a ),
138  ArgType & arg,
139  const ::std::string & initialLogNDC,
140  const PthreadAttr & attr,
141  bool startCancelable = false );
142 
143 // @copydoc StartPthreadWithRef
144 template < typename ArgType >
145 ::pthread_t StartPthreadWithRef(
146  void (*ep)( const ArgType & a ),
147  const ArgType & arg,
148  const ::std::string & initialLogNDC = ::std::string(),
149  const ::pthread_attr_t * attr = 0,
150  bool startCancelable = false );
151 
152 // @copydoc StartPthreadWithRef
153 template < typename ArgType >
154 ::pthread_t StartPthreadWithRef(
155  void (*ep)( const ArgType & a ),
156  const ArgType & arg,
157  const ::std::string & initialLogNDC,
158  const PthreadAttr & attr,
159  bool startCancelable = false );
160 
161 // @copydoc StartPthreadWithRef
162 template < typename ArgType >
163 ::pthread_t StartPthreadWithRef(
164  void (*ep)( const ArgType & a ),
165  ArgType & arg,
166  const ::std::string & initialLogNDC = ::std::string(),
167  const ::pthread_attr_t * attr = 0,
168  bool startCancelable = false );
169 
170 // @copydoc StartPthreadWithRef
171 template < typename ArgType >
172 ::pthread_t StartPthreadWithRef(
173  void (*ep)( const ArgType & a ),
174  ArgType & arg,
175  const ::std::string & initialLogNDC,
176  const PthreadAttr & attr,
177  bool startCancelable = false );
178 
179 
180 // NOTE: Everything below is just implementation detail. Fugetaboutit.
181 
182 
184 namespace detail {
185 
186 
188 template < typename A, typename AT, typename AC >
190 
191 
193 template < typename I >
194 void * BoilerPlate( void * bpInfoArg );
195 
196 
198 template < typename A, typename AT, typename AC >
199 ::pthread_t StartPthreadCommon( void (*ep)( A ),
200  AT argTransfer,
201  const ::std::string & initialLogNDC,
202  const ::pthread_attr_t * attr,
203  bool startCancelable );
204 
205 
206 template < typename A, typename AT, typename AC >
207 class BoilerPlateInfo {
208  private:
209  typedef void (*EpType)( A );
210 
211  typedef AC ArgCopyType;
212 
213  friend void * BoilerPlate< BoilerPlateInfo >( void * bpInfoArg );
214 
215  friend ::pthread_t StartPthreadCommon< A, AT, AC >(
216  EpType ep,
217  AT argTransfer,
218  const ::std::string & initialLogNDC,
219  const ::pthread_attr_t * attr,
220  bool startCancelable );
221 
222  BoilerPlateInfo( EpType ep,
223  AT argTransfer,
224  const ::std::string & initialLogNDC,
225  bool startCancelable );
226 
227  PthreadMutex clientCanContinueGuard_;
228  PthreadCond clientCanContinueCond_;
229  bool clientCanContinue_;
230 
231  bool epReached_;
232 
233  const EpType ep_;
234  AT argTransfer_;
235 
236  const ::std::string & initialLogNDC_;
237  const bool startCancelable_;
238 };
239 
240 
241 } // namespace carma::util::detail
242 } // namespace carma::util
243 } // namespace carma
244 
245 
246 template < typename A, typename AT, typename AC >
247 inline
249  EpType ep,
250  AT argTransfer,
251  const ::std::string & initialLogNDC,
252  const bool startCancelable ) :
253 clientCanContinue_( false ),
254 epReached_( false ),
255 ep_( ep ),
256 argTransfer_( argTransfer ),
257 initialLogNDC_( initialLogNDC ),
258 startCancelable_( startCancelable )
259 {
260 }
261 
262 
263 template < typename I >
264 void *
265 carma::util::detail::BoilerPlate( void * const bpInfoArg )
266 {
267  bool clientCanContinueSignalled = false;
268 
269  I * info = static_cast< I * >( bpInfoArg );
270 
271  try {
272  if ( info->initialLogNDC_.empty() == false )
273  log4cpp::NDC::push( info->initialLogNDC_ );
274 
275  if ( info->startCancelable_ == false ) {
276  int oldState = PTHREAD_CANCEL_DISABLE;
277 
278  if ( ::pthread_setcancelstate( PTHREAD_CANCEL_DISABLE,
279  &oldState ) != 0 )
280  throw std::runtime_error( "::pthread_setcancelstate failed" );
281  }
282 
283  const ScopedThreadQuitRegisterSelf quitReg;
284 
285  typename I::EpType ep = info->ep_;
286  typename I::ArgCopyType argCopy = info->argTransfer_;
287 
288  {
290  lock( info->clientCanContinueGuard_ );
291 
292  info->clientCanContinue_ = true;
293  info->epReached_ = true;
294 
295  // Notice that I signal the cond while still holding the mutex
296  // My hope is that this will keep us from having the info block
297  // get destructed out from under us while we are still in the
298  // middle of either the pthread_cond_signal call or the
299  // pthread_mutex_unlock call.
300  info->clientCanContinueCond_.Signal();
301  }
302 
303  clientCanContinueSignalled = true;
304 
305  info = 0;
306 
307  ep( argCopy );
308  } catch ( ... ) {
309  if ( clientCanContinueSignalled == false ) {
310  try {
312  lock( info->clientCanContinueGuard_ );
313 
314  info->clientCanContinue_ = true;
315  info->epReached_ = false;
316 
317  // Notice that I signal the cond while still holding the mutex
318  // My hope is that this will keep us from having the info block
319  // get destructed out from under us while we are still in the
320  // middle of either the pthread_cond_signal call or the
321  // pthread_mutex_unlock call.
322  info->clientCanContinueCond_.Signal();
323  } catch ( ... ) {
324  // Just stifle the exception
325  }
326  }
327 
328  MarkCaughtExceptionOkayToDestructIfThreadQuitRequestedError();
329  }
330 
331  return 0;
332 }
333 
334 
335 template < typename A, typename AT, typename AC >
336 ::pthread_t
338  void (*ep)( A ),
339  AT argTransfer,
340  const ::std::string & initialLogNDC,
341  const ::pthread_attr_t * const attr,
342  const bool startCancelable )
343 {
344  const ScopedPthreadCancelDisable cancelDisable;
345  const ScopedThreadQuitDeferSelf quitDefer;
346 
347  typedef BoilerPlateInfo< A, AT, AC > InfoType;
348 
349  InfoType info( ep, argTransfer, initialLogNDC, startCancelable );
350 
351  ::pthread_t thread;
352 
353  if ( ::pthread_create( &thread,
354  attr,
355  BoilerPlate< InfoType >,
356  &info ) != 0 )
357  throw std::runtime_error( "::pthread_create failed" );
358 
359  {
360  const ScopedLock< PthreadMutex > lock( info.clientCanContinueGuard_ );
361 
362  while ( info.clientCanContinue_ == false )
363  info.clientCanContinueCond_.Wait( info.clientCanContinueGuard_ );
364 
365  if ( info.epReached_ == false )
366  throw std::runtime_error( "thread died before entry point call" );
367  }
368 
369  return thread;
370 }
371 
372 
373 template < typename ArgType >
374 ::pthread_t
376  void (*ep)( ArgType & a ),
377  const ArgType & arg,
378  const ::std::string & initialLogNDC,
379  const ::pthread_attr_t * const attr,
380  const bool startCancelable )
381 {
382  return
384  < ArgType &,
385  const ArgType &,
386  ArgType >
387  ( ep,
388  arg,
389  initialLogNDC,
390  attr,
391  startCancelable );
392 }
393 
394 
395 template < typename ArgType >
396 ::pthread_t
398  void (*ep)( ArgType & a ),
399  const ArgType & arg,
400  const ::std::string & initialLogNDC,
401  const PthreadAttr & attr,
402  const bool startCancelable )
403 {
404  return
406  < ArgType &,
407  const ArgType &,
408  ArgType >
409  ( ep,
410  arg,
411  initialLogNDC,
412  &(attr.InternalPthreadAttr()),
413  startCancelable );
414 }
415 
416 
417 template < typename ArgType >
418 ::pthread_t
420  void (*ep)( const ArgType & a ),
421  const ArgType & arg,
422  const ::std::string & initialLogNDC,
423  const ::pthread_attr_t * const attr,
424  const bool startCancelable )
425 {
426  return
428  < const ArgType &,
429  const ArgType &,
430  const ArgType >
431  ( ep,
432  arg,
433  initialLogNDC,
434  attr,
435  startCancelable );
436 }
437 
438 
439 template < typename ArgType >
440 ::pthread_t
442  void (*ep)( const ArgType & a ),
443  const ArgType & arg,
444  const ::std::string & initialLogNDC,
445  const PthreadAttr & attr,
446  const bool startCancelable )
447 {
448  return
450  < const ArgType &,
451  const ArgType &,
452  const ArgType >
453  ( ep,
454  arg,
455  initialLogNDC,
456  &(attr.InternalPthreadAttr()),
457  startCancelable );
458 }
459 
460 
461 template < typename ArgType >
462 ::pthread_t
464  void (*ep)( const ArgType * & a ),
465  ArgType * const & arg,
466  const ::std::string & initialLogNDC,
467  const ::pthread_attr_t * const attr,
468  const bool startCancelable )
469 {
470  // This is a particularly gruesome case of mixing
471  // const-ness of pointer and references.
472 
473  return
475  < const ArgType * &,
476  ArgType * const &,
477  const ArgType * >
478  ( ep,
479  arg,
480  initialLogNDC,
481  attr,
482  startCancelable );
483 }
484 
485 
486 template < typename ArgType >
487 ::pthread_t
489  void (*ep)( const ArgType * & a ),
490  ArgType * const & arg,
491  const ::std::string & initialLogNDC,
492  const PthreadAttr & attr,
493  const bool startCancelable )
494 {
495  // This is a particularly gruesome case of mixing
496  // const-ness of pointer and references.
497 
498  return
500  < const ArgType * &,
501  ArgType * const &,
502  const ArgType * >
503  ( ep,
504  arg,
505  initialLogNDC,
506  &(attr.InternalPthreadAttr()),
507  startCancelable );
508 }
509 
510 
511 template < typename ArgType >
512 ::pthread_t
514  void (*ep)( ArgType & a ),
515  ArgType & arg,
516  const ::std::string & initialLogNDC,
517  const ::pthread_attr_t * const attr,
518  const bool startCancelable )
519 {
520  return
522  < ArgType &,
523  ArgType &,
524  ArgType & >
525  ( ep,
526  arg,
527  initialLogNDC,
528  attr,
529  startCancelable );
530 }
531 
532 
533 template < typename ArgType >
534 ::pthread_t
536  void (*ep)( ArgType & a ),
537  ArgType & arg,
538  const ::std::string & initialLogNDC,
539  const PthreadAttr & attr,
540  const bool startCancelable )
541 {
542  return
544  < ArgType &,
545  ArgType &,
546  ArgType & >
547  ( ep,
548  arg,
549  initialLogNDC,
550  &(attr.InternalPthreadAttr()),
551  startCancelable );
552 }
553 
554 
555 template < typename ArgType >
556 ::pthread_t
558  void (*ep)( const ArgType & a ),
559  const ArgType & arg,
560  const ::std::string & initialLogNDC,
561  const ::pthread_attr_t * const attr,
562  const bool startCancelable )
563 {
564  return
566  < const ArgType &,
567  const ArgType &,
568  const ArgType & >
569  ( ep,
570  arg,
571  initialLogNDC,
572  attr,
573  startCancelable );
574 }
575 
576 
577 template < typename ArgType >
578 ::pthread_t
580  void (*ep)( const ArgType & a ),
581  const ArgType & arg,
582  const ::std::string & initialLogNDC,
583  const PthreadAttr & attr,
584  const bool startCancelable )
585 {
586  return
588  < const ArgType &,
589  const ArgType &,
590  const ArgType & >
591  ( ep,
592  arg,
593  initialLogNDC,
594  &(attr.InternalPthreadAttr()),
595  startCancelable );
596 }
597 
598 
599 template < typename ArgType >
600 ::pthread_t
602  void (*ep)( const ArgType & a ),
603  ArgType & arg,
604  const ::std::string & initialLogNDC,
605  const ::pthread_attr_t * const attr,
606  const bool startCancelable )
607 {
608  return
610  < const ArgType &,
611  const ArgType &,
612  const ArgType & >
613  ( ep,
614  arg,
615  initialLogNDC,
616  attr,
617  startCancelable );
618 }
619 
620 
621 template < typename ArgType >
622 ::pthread_t
624  void (*ep)( const ArgType & a ),
625  ArgType & arg,
626  const ::std::string & initialLogNDC,
627  const PthreadAttr & attr,
628  const bool startCancelable )
629 {
630  return
632  < const ArgType &,
633  const ArgType &,
634  const ArgType & >
635  ( ep,
636  arg,
637  initialLogNDC,
638  &(attr.InternalPthreadAttr()),
639  startCancelable );
640 }
641 
642 
643 #endif
::pthread_t StartPthreadCommon(void(*ep)(A), AT argTransfer, const ::std::string &initialLogNDC, const ::pthread_attr_t *attr, bool startCancelable)
::pthread_t StartPthreadWithRef(void(*ep)(ArgType &a), ArgType &arg, const ::std::string &initialLogNDC=::std::string(), const ::pthread_attr_t *attr=0, bool startCancelable=false)
Starts up a new pthread.
A simple wrapper class that makes use of ::pthread_cond_t easier in a C++ world.
Definition: PthreadCond.h:43
::pthread_t StartPthreadWithCopy(void(*ep)(ArgType &a), const ArgType &arg, const ::std::string &initialLogNDC=::std::string(), const ::pthread_attr_t *attr=0, bool startCancelable=false)
Starts up a new pthread.
A templated scope class (i.e.
Definition: ScopedLock.h:46
void * BoilerPlate(void *bpInfoArg)
Definition: StartPthread.h:265
A simple wrapper class that makes use of ::pthread_mutex_t easier in a C++ world. ...
Definition: PthreadMutex.h:41