ROSE  0.9.6a
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
threadSupport.h
Go to the documentation of this file.
1 /* Thread support for ROSE */
2 #ifndef ROSE_threadSupport_H
3 #define ROSE_threadSupport_H
4 
5 /* Design rules:
6  * 1. All public symbols in this file should use the "RTS_" prefix (ROSE Thread Support).
7  *
8  * 2. All constructs that have a user-supplied compound statement as a "body", have a matching "_END" macro. For instance,
9  * RTS_MUTEX starts a mutual exclusion for a critical section, which ends with an RTS_MUTEX_END macro. The END macros
10  * generally take no arguments.
11  *
12  * 3. Locally scoped symbols defined by the macros have names beginning with "RTS_". This is generally followed by the first
13  * letter of the rest of the macro name, a letter "s" or "p" for "shared" or "private", and an underscore. For example,
14  * within the RTS_MUTEX macros, a private (non-shared) variable might be named "RTS_Mp_mutex".
15  *
16  * 4. Constructs that allow a user-supplied compound statement as a "body" should allow the body to "break" or "throw". Both
17  * forms of premature exit should behave as if the body executed to completion (except throw will throw the exception
18  * again automatically).
19  *
20  * 5. New functionality shall have types, constants, and functions reminiscent of the POSIX threads interface, but whose
21  * names begin with "RTS_" rather than "pthread_".
22  */
23 
24 /* Needed for ROSE_HAVE_PTHREAD_H definition */
25 #include "rosePublicConfig.h"
26 
27 #include <assert.h>
28 #include <stdint.h>
29 #include <stdio.h>
30 #include <stdlib.h>
31 
32 #include <string>
33 
34 /* Figure out whether ROSE can support multi-threading and what kind of support library is available. */
35 #ifdef ROSE_HAVE_PTHREAD_H
36 # define ROSE_THREADS_ENABLED
37 # define ROSE_THREADS_POSIX
38 # include <pthread.h>
39 #else
40 # undef ROSE_THREADS_ENABLED
41 #endif
42 
43 /* This warning is in a public header file so that end users will see it when they compile against a version of ROSE that
44  * doesn't have multi-thread support. It would be imprudent to move this to one of the library's *.C files because then
45  * an end user might spend substantial time trying to figure out why his multi-threaded program fails nondeterministically when
46  * the ROSE documentation advertises that certain functions are thread safe.
47  *
48  * Unfortunately, due to the way ROSE's header files are organized, threadSupport.h will be included by pretty much every
49  * ROSE library source file because every file includes _all_ the Sage node definitions (instead of only the ones it needs),
50  * and a few of those nodes (e.g., SgFile) depend on something defined by the Disassembler class. The Disassembler supports
51  * multi threading and therefore includes this header. Therefore every ROSE library source file will spit out this warning. */
52 #ifndef ROSE_THREADS_ENABLED
53 # ifdef _MSC_VER
54 # pragma message("Multi-thread support is not enabled. ROSE will not be thread safe even for functions that advertise safety.")
55 # else
56 # warning "Multi-thread support is not enabled. ROSE will not be thread safe even for functions that advertise safety."
57 # endif
58 #endif
59 
60 /* The __attribute__ mechanism is only supported by GNU compilers */
61 #ifndef __GNUC__
62 #define __attribute__(x) /*NOTHING*/
63 #define __attribute(x) /*NOTHING*/
64 #endif
65 
66 /******************************************************************************************************************************
67  * Layered Synchronization Primitives
68  ******************************************************************************************************************************/
69 
92 enum RTS_Layer {
94 
95  /* ROSE library layers, 100-199 */
101  /* Simulator layers (see projects/simulator), 200-220
102  *
103  * Constraints:
104  * RSIM_PROCESS_OBJ < RSIM_PROCESS_CLONE_OBJ
105  * RSIM_SIGNALHANDLING_OBJ < RSIM_PROCESS_OBJ
106  */
117  /* User layers. These are for people that might want to use the ROSE Thread Support outside ROSE, such as in ROSE
118  * projects. We leave it up to them to organize how they'll use the available layers. */
122  /* Max number of layers (i.e., 0 through N-1) */
124 };
125 
133 
137 
138 /******************************************************************************************************************************
139  * Paired macros for using mutual exclusion locks
140  ******************************************************************************************************************************/
141 
161 #ifdef ROSE_THREADS_ENABLED
162 # define RTS_MUTEX(MUTEX) \
163  do { /* standard CPP macro protection */ \
164  RTS_mutex_t *RTS_Mp_mutex = &(MUTEX); /* saved for when we need to unlock it */ \
165  int RTS_Mp_err = RTS_mutex_lock(RTS_Mp_mutex); \
166  assert(0==RTS_Mp_err); \
167  do { /* so we can catch "break" statements */ \
168  try {
169 
171 # define RTS_MUTEX_END \
172  } catch (...) { \
173  RTS_Mp_err = RTS_mutex_unlock(RTS_Mp_mutex); \
174  assert(0==RTS_Mp_err); \
175  throw; \
176  } \
177  } while (0); \
178  RTS_Mp_err = RTS_mutex_unlock(RTS_Mp_mutex); \
179  assert(0==RTS_Mp_err); \
180  } while (0)
181 #else
182 # define RTS_MUTEX(MUTEX) \
183  do {
184 # define RTS_MUTEX_END \
185  } while (0)
186 #endif
187 
188 /******************************************************************************************************************************
189  * Types and functions for mutexes
190  ******************************************************************************************************************************/
191 
192 #define RTS_MUTEX_MAGIC 0x1a95a713
193 
194 #ifdef ROSE_THREADS_ENABLED
195 
200 struct RTS_mutex_t {
201  unsigned magic;
203  pthread_mutex_t mutex;
204 };
205 
206 #define RTS_MUTEX_INITIALIZER(LAYER) { RTS_MUTEX_MAGIC, (LAYER), PTHREAD_MUTEX_INITIALIZER }
207 
209 int RTS_mutex_init(RTS_mutex_t*, RTS_Layer, pthread_mutexattr_t*);
210 
211 #else
212 
213 struct RTS_mutex_t {
214  int dummy;
215 };
216 
217 #define RTS_MUTEX_INITIALIZER(LAYER) { 0 }
218 
219 int RTS_mutex_init(RTS_mutex_t*, RTS_Layer, void*);
220 
221 #endif
222 
225 
228 
229 
230 
231 
232 /*******************************************************************************************************************************
233  * Paired macros for using RTS_rwlock_t
234  *******************************************************************************************************************************/
235 
319 #ifdef ROSE_THREADS_ENABLED
320 # define RTS_RWLOCK(RWLOCK, HOW) \
321  do { /* standard CPP macro protection */ \
322  RTS_rwlock_t *RTS_Wp_rwlock = &(RWLOCK); /* saved for when we need to unlock it */ \
323  int RTS_Wp_err = RTS_rwlock_##HOW(RTS_Wp_rwlock); \
324  assert(0==RTS_Wp_err); \
325  do { /* so we can catch "break" statements */ \
326  try {
327 
328 # define RTS_RWLOCK_END \
329  } catch (...) { \
330  RTS_Wp_err = RTS_rwlock_unlock(RTS_Wp_rwlock); \
331  assert(0==RTS_Wp_err); \
332  throw; \
333  } \
334  } while (0); \
335  RTS_Wp_err = RTS_rwlock_unlock(RTS_Wp_rwlock); \
336  assert(0==RTS_Wp_err); \
337  } while (0)
338 
339 #else
340 # define RTS_RWLOCK(RWLOCK, HOW) \
341  do {
342 # define RTS_RWLOCK_END \
343  } while (0)
344 #endif
345 
346 #define RTS_READ(RWLOCK) RTS_RWLOCK(RWLOCK, rdlock)
347 #define RTS_READ_END RTS_RWLOCK_END
348 #define RTS_WRITE(RWLOCK) RTS_RWLOCK(RWLOCK, wrlock)
349 #define RTS_WRITE_END RTS_RWLOCK_END
351 /*******************************************************************************************************************************
352  * Types and functions for RTS_rwlock_t
353  *
354  * Programmers should generally use the RTS_READ and RTS_WRITE macros in their source code. The symbols defined here are
355  * similar to pthread_rwlock* symbols and are mostly to support RTS_READ and RTS_WRITE macros (like how the RTS_mutex*
356  * symbols support the RTS_MUTEX macro).
357  *******************************************************************************************************************************/
358 
362 #ifdef ROSE_THREADS_ENABLED
363 struct RTS_rwlock_t {
364  unsigned magic; /* always RTS_RWLOCK_MAGIC after initialization */
365  RTS_Layer layer; /* software layer to which this lock belongs, or zero */
366  pthread_rwlock_t rwlock; /* the main read-write lock */
367  RTS_mutex_t mutex; /* mutex to protect the following data members */
368  size_t nlocks; /* number of write locks held */
369  pthread_t owner; /* thread that currently holds the write lock */
370 };
371 #else
372 struct RTS_rwlock_t {
373  int dummy;
374 };
375 #endif
376 
377 #define RTS_RWLOCK_MAGIC 0x20e7f3f4
378 
380 #ifdef ROSE_THREADS_ENABLED
381 # define RTS_RWLOCK_INITIALIZER(LAYER) { RTS_RWLOCK_MAGIC, \
382  (LAYER), \
383  PTHREAD_RWLOCK_INITIALIZER, \
384  RTS_MUTEX_INITIALIZER(RTS_LAYER_DONTCARE), \
385  0/*...*/ \
386  }
387 #else
388 # define RTS_RWLOCK_INITIALIZER(LAYER) { 0 }
389 #endif
390 
391 #ifdef ROSE_THREADS_ENABLED
392 
393 int RTS_rwlock_init(RTS_rwlock_t *rwlock, RTS_Layer, pthread_rwlockattr_t *wrlock_attrs);
394 #else
395 int RTS_rwlock_init(RTS_rwlock_t *rwlock, RTS_Layer, void *wrlock_attrs);
396 #endif
397 
411 int RTS_rwlock_rdlock(RTS_rwlock_t *rwlock);
412 
429 int RTS_rwlock_wrlock(RTS_rwlock_t *rwlock);
430 
442 int RTS_rwlock_unlock(RTS_rwlock_t *rwlock);
443 
444 
445 
446 /*******************************************************************************************************************************
447  * Paired macros for initialization functions
448  *******************************************************************************************************************************/
449 
450 
486 #ifdef ROSE_THREADS_ENABLED
487 # define RTS_INIT(MUTEX, ALLOW_RECURSION) \
488  do { \
489  static bool RTS_Is_initialized=false, RTS_Is_initializing=false; /* "s"==shared; "p"=private */ \
490  static pthread_t RTS_Is_initializer; \
491  static pthread_cond_t RTS_Is_condition=PTHREAD_COND_INITIALIZER; \
492  RTS_mutex_t *RTS_Ip_mutex = &(MUTEX); \
493  bool RTS_Ip_initialized, RTS_Ip_initializing; \
494  bool RTS_Ip_allow_recursion = (ALLOW_RECURSION); \
495  \
496  /* First critical section is only to obtain the initialization status and update it to "initializing" if necessary. We \
497  * must release the lock before the RTS_I_LOCK body is executed in case we need to handle recursive calls to the \
498  * RTS_I_LOCK construct. */ \
499  RTS_MUTEX(MUTEX) { \
500  if (!(RTS_Ip_initialized=RTS_Is_initialized) && !(RTS_Ip_initializing=RTS_Is_initializing)) { \
501  RTS_Is_initializing = true; /* but leave private copy false so we can detect changed state */ \
502  RTS_Is_initializer = pthread_self(); \
503  } \
504  } RTS_MUTEX_END; \
505  \
506  if (!RTS_Ip_initialized) { \
507  if (!RTS_Ip_initializing) { \
508  do { /* so we catch "break" statements in user-supplied code. */ \
509  try {
510 
511 
513 # define RTS_INIT_END \
514  } catch (...) { \
515  /* If the user supplied body throws an exception, consider the body to have completed. */ \
516  RTS_MUTEX(*RTS_Ip_mutex) { \
517  RTS_Is_initialized = true; \
518  RTS_Is_initializing = false; \
519  pthread_cond_broadcast(&RTS_Is_condition); \
520  } RTS_MUTEX_END; \
521  throw; \
522  } \
523  } while (0); \
524  RTS_MUTEX(*RTS_Ip_mutex) { \
525  RTS_Is_initialized = true; \
526  RTS_Is_initializing = false; \
527  pthread_cond_broadcast(&RTS_Is_condition); \
528  } RTS_MUTEX_END; \
529  } else if (pthread_equal(pthread_self(), RTS_Is_initializer)) { \
530  /* This was a recursive call resulting from the user-supplied RTS_I body and we must allow it to continue \
531  * unimpeded to prevent deadlock. We don't need to be holding the MUTEX lock to access RTS_Is_initializer \
532  * because it's initialized only the first time through the critical section above--and the only way to reach \
533  * this point is by this or some other thread having already initialized RTS_Is_initializer. */ \
534  if (!RTS_Ip_allow_recursion) { \
535  fprintf(stderr, "RTS_I_LOCK body made a recursive call. Aborting...\n"); \
536  abort(); \
537  } \
538  } else { \
539  /* This is some other thread which is not in charge of initializing the class, bug which arrived to the \
540  * RTS_I_LOCK before the first thread completed the initialization. */ \
541  RTS_MUTEX(*RTS_Ip_mutex) { \
542  while (!RTS_Is_initialized) \
543  pthread_cond_wait(&RTS_Is_condition, &(RTS_Ip_mutex->mutex)); \
544  } RTS_MUTEX_END; \
545  } \
546  } \
547  } while (0)
548 #else
549 # define RTS_INIT(MUTEX, ALLOW_RECURSION) \
550  do { \
551  static bool RTS_Is_initialized=false; \
552  if (!RTS_Is_initialized) { \
553  RTS_Is_initialized = true; \
554  do {
555 # define RTS_INIT_END \
556  } while (0); \
557  } \
558  } while (0)
559 #endif
560 
561 #define RTS_INIT_RECURSIVE(MUTEX) RTS_INIT(MUTEX, true)
562 #define RTS_INIT_NONRECURSIVE(MUTEX) RTS_INIT(MUTEX, false)
565 /******************************************************************************************************************************
566  * Support for messages
567  ******************************************************************************************************************************/
568 
579 class RTS_Message {
580 public:
584  class Prefix {
585  public:
586  virtual ~Prefix() {};
587  virtual void operator()(FILE*) {}
588  };
589 
601  : f(f), p(p), buffer(NULL), bufsz(0), interrupted(false) {
602  ctor();
603  }
604 
606  dtor();
607  }
608 
610  void set_file(FILE *f) {
611  this->f = f;
612  }
613 
615  FILE *get_file() const {
616  return f;
617  }
618 
639  RTS_Message& multipart(const std::string &name, const char *fmt, ...) __attribute__((format(printf, 3, 4)));
640 
653  RTS_Message& more(const char *fmt, ...) __attribute__((format(printf, 2, 3)));
654 
658  void multipart_end();
659 
673  RTS_Message& mesg(const char *fmt, ...) __attribute__((format(printf, 2, 3)));
674 
689  RTS_Message& brief(const char *fmt, ...) __attribute__((format(printf, 2, 3)));
690 
694  void brief_begin(const char *fmt, ...) __attribute__((format(printf, 2, 3)));
695 
697  void brief_end(const char *fmt, ...) __attribute__((format(printf, 2, 3)));
698 
709  int lock();
710 
716  int unlock(bool sol=true);
717 
718 private:
719  RTS_Message() {abort();}
720  RTS_Message& operator=(RTS_Message&) { abort(); return *this; } // return is to silence Klocwork
721  void ctor();
722  void dtor();
723  void terminate();
724  void prefix();
725  void output_lines(const char *s);
726  void format(const char *fmt, va_list, va_list);
730  static bool sol;
732  FILE *f;
734  char *buffer;
735  size_t bufsz;
736  std::string name;
737  bool interrupted;
738 };
739 
740 /******************************************************************************************************************************
741  * Paired macros for messages
742  ******************************************************************************************************************************/
743 
777 #ifdef ROSE_THREADS_ENABLED
778 # define RTS_MESSAGE(MESG) \
779  do { \
780  RTS_Message *RTS_Mp_mesg = &(MESG); \
781  int RTS_Mp_err = RTS_Mp_mesg->lock(); \
782  assert(0==RTS_Mp_err); \
783  do { \
784  try {
785 
786 # define RTS_MESSAGE_END(SOL) \
787  } catch (...) { \
788  RTS_Mp_err = RTS_Mp_mesg->unlock((SOL)); \
789  assert(0==RTS_Mp_err); \
790  throw; \
791  } \
792  } while (0); \
793  RTS_Mp_err = RTS_Mp_mesg->unlock((SOL)); \
794  assert(0==RTS_Mp_err); \
795  } while (0)
796 #else
797 # define RTS_MESSAGE(MESG) \
798  do {
799 # define RTS_MESSAGE_END(SOL) \
800  } while (0)
801 #endif
802 
806 #endif /* !ROSE_threadSupport_H !*/