threadSupport.h

Go to the documentation of this file.
00001 /* Thread support for ROSE */
00002 #ifndef ROSE_threadSupport_H
00003 #define ROSE_threadSupport_H
00004 
00005 /* Design rules:
00006  *   1. All public symbols in this file should use the "RTS_" prefix (ROSE Thread Support).
00007  *
00008  *   2. All constructs that have a user-supplied compound statement as a "body", have a matching "_END" macro.  For instance,
00009  *      RTS_MUTEX starts a mutual exclusion for a critical section, which ends with an RTS_MUTEX_END macro.  The END macros
00010  *      generally take no arguments.
00011  *
00012  *   3. Locally scoped symbols defined by the macros have names beginning with "RTS_". This is generally followed by the first
00013  *      letter of the rest of the macro name, a letter "s" or "p" for "shared" or "private", and an underscore.  For example,
00014  *      within the RTS_MUTEX macros, a private (non-shared) variable might be named "RTS_Mp_mutex".
00015  *
00016  *   4. Constructs that allow a user-supplied compound statement as a "body" should allow the body to "break" or "throw". Both
00017  *      forms of premature exit should behave as if the body executed to completion (except throw will throw the exception
00018  *      again automatically).
00019  *
00020  *   5. New functionality shall have types, constants, and functions reminiscent of the POSIX threads interface, but whose
00021  *      names begin with "RTS_" rather than "pthread_".
00022  */
00023 
00024 /* Needed for ROSE_HAVE_PTHREAD_H definition */
00025 #include "rosePublicConfig.h"
00026 
00027 #include <assert.h>
00028 #include <stdint.h>
00029 #include <stdio.h>
00030 #include <stdlib.h>
00031 
00032 #include <string>
00033 
00034 /* Figure out whether ROSE can support multi-threading and what kind of support library is available. */
00035 #ifdef ROSE_HAVE_PTHREAD_H
00036 #  define ROSE_THREADS_ENABLED
00037 #  define ROSE_THREADS_POSIX
00038 #  include <pthread.h>
00039 #else
00040 #  undef  ROSE_THREADS_ENABLED
00041 #endif
00042 
00043 /* This warning is in a public header file so that end users will see it when they compile against a version of ROSE that
00044  * doesn't have multi-thread support.  It would be imprudent to move this to one of the library's *.C files because then
00045  * an end user might spend substantial time trying to figure out why his multi-threaded program fails nondeterministically when
00046  * the ROSE documentation advertises that certain functions are thread safe.
00047  *
00048  * Unfortunately, due to the way ROSE's header files are organized, threadSupport.h will be included by pretty much every
00049  * ROSE library source file because every file includes _all_ the Sage node definitions (instead of only the ones it needs),
00050  * and a few of those nodes (e.g., SgFile) depend on something defined by the Disassembler class. The Disassembler supports
00051  * multi threading and therefore includes this header. Therefore every ROSE library source file will spit out this warning. */
00052 #ifndef ROSE_THREADS_ENABLED
00053 #  ifdef _MSC_VER
00054 #    pragma message("Multi-thread support is not enabled. ROSE will not be thread safe even for functions that advertise safety.")
00055 #  else
00056 #    warning "Multi-thread support is not enabled. ROSE will not be thread safe even for functions that advertise safety."
00057 #  endif
00058 #endif
00059 
00060 
00061 /******************************************************************************************************************************
00062  *                                      Layered Synchronization Primitives
00063  ******************************************************************************************************************************/
00064 
00087 enum RTS_Layer {
00088     RTS_LAYER_DONTCARE = 0,
00089 
00090     /* ROSE library layers, 100-199 */
00091     RTS_LAYER_ROSE_CALLBACKS_LIST_OBJ   = 100,          
00092     RTS_LAYER_RTS_MESSAGE_CLASS         = 105,          
00093     RTS_LAYER_DISASSEMBLER_CLASS        = 110,          
00095     /* Simulator layers (see projects/simulator), 200-220
00096      *
00097      * Constraints:
00098      *     RSIM_PROCESS_OBJ        < RSIM_PROCESS_CLONE_OBJ
00099      *     RSIM_SIGNALHANDLING_OBJ < RSIM_PROCESS_OBJ
00100      */
00101     RTS_LAYER_RSIM_SIGNALHANDLING_OBJ   = 200,          
00102     RTS_LAYER_RSIM_PROCESS_OBJ          = 201,          
00103     RTS_LAYER_RSIM_PROCESS_CLONE_OBJ    = 202,          
00104     RTS_LAYER_RSIM_THREAD_OBJ           = 203,          
00105     RTS_LAYER_RSIM_THREAD_CLASS         = 204,          
00106     RTS_LAYER_RSIM_SYSCALLDISABLER_OBJ  = 205,          
00107     RTS_LAYER_RSIM_TRACEIO_OBJ          = 206,          
00108     RTS_LAYER_RSIM_SIMULATOR_CLASS      = 207,          
00109     RTS_LAYER_RSIM_SIMULATOR_OBJ        = 208,          
00111     /* User layers.  These are for people that might want to use the ROSE Thread Support outside ROSE, such as in ROSE
00112      * projects.   We leave it up to them to organize how they'll use the available layers. */
00113     RTS_LAYER_USER_MIN                  = 250,          
00114     RTS_LAYER_USER_MAX                  = 299,          
00116     /* Max number of layers (i.e., 0 through N-1) */
00117     RTS_LAYER_NLAYERS                   = 300
00118 };
00119 
00126 bool RTS_acquiring(RTS_Layer);
00127 
00130 void RTS_releasing(RTS_Layer);
00131 
00132 /******************************************************************************************************************************
00133  *                                      Paired macros for using mutual exclusion locks
00134  ******************************************************************************************************************************/
00135 
00155 #ifdef ROSE_THREADS_ENABLED
00156 #  define RTS_MUTEX(MUTEX)                                                                                                     \
00157     do {        /* standard CPP macro protection */                                                                            \
00158         RTS_mutex_t *RTS_Mp_mutex = &(MUTEX); /* saved for when we need to unlock it */                                        \
00159         int RTS_Mp_err = RTS_mutex_lock(RTS_Mp_mutex);                                                                         \
00160         assert(0==RTS_Mp_err);                                                                                                 \
00161         do {    /* so we can catch "break" statements */                                                                       \
00162             try {
00163 
00165 #  define RTS_MUTEX_END                                                                                                        \
00166             } catch (...) {                                                                                                    \
00167                 RTS_Mp_err = RTS_mutex_unlock(RTS_Mp_mutex);                                                                   \
00168                 assert(0==RTS_Mp_err);                                                                                         \
00169                 throw;                                                                                                         \
00170             }                                                                                                                  \
00171         } while (0);                                                                                                           \
00172         RTS_Mp_err = RTS_mutex_unlock(RTS_Mp_mutex);                                                                           \
00173         assert(0==RTS_Mp_err);                                                                                                 \
00174     } while (0)
00175 #else
00176 #  define RTS_MUTEX(MUTEX)                                                                                                     \
00177     do {
00178 #  define RTS_MUTEX_END                                                                                                        \
00179     } while (0)
00180 #endif
00181 
00182 /******************************************************************************************************************************
00183  *                                      Types and functions for mutexes
00184  ******************************************************************************************************************************/
00185 
00186 #define RTS_MUTEX_MAGIC 0x1a95a713
00187 
00188 #ifdef ROSE_THREADS_ENABLED
00189 
00194 struct RTS_mutex_t {
00195     unsigned magic;
00196     RTS_Layer layer;
00197     pthread_mutex_t mutex;
00198 };
00199 
00200 #define RTS_MUTEX_INITIALIZER(LAYER) { RTS_MUTEX_MAGIC, (LAYER), PTHREAD_MUTEX_INITIALIZER }
00201 
00203 int RTS_mutex_init(RTS_mutex_t*, RTS_Layer, pthread_mutexattr_t*);
00204 
00205 #else
00206 
00207 struct RTS_mutex_t {
00208     int dummy;
00209 };
00210 
00211 #define RTS_MUTEX_INITIALIZER(LAYER) { 0 }
00212 
00213 int RTS_mutex_init(RTS_mutex_t*, RTS_Layer, void*);
00214 
00215 #endif
00216 
00218 int RTS_mutex_lock(RTS_mutex_t*);
00219 
00221 int RTS_mutex_unlock(RTS_mutex_t*);
00222 
00223 
00224 
00225 
00226 /*******************************************************************************************************************************
00227  *                                      Paired macros for using RTS_rwlock_t
00228  *******************************************************************************************************************************/
00229 
00313 #ifdef ROSE_THREADS_ENABLED
00314 #  define RTS_RWLOCK(RWLOCK, HOW)                                                                                              \
00315     do {        /* standard CPP macro protection */                                                                            \
00316         RTS_rwlock_t *RTS_Wp_rwlock = &(RWLOCK); /* saved for when we need to unlock it */                                     \
00317         int RTS_Wp_err = RTS_rwlock_##HOW(RTS_Wp_rwlock);                                                                      \
00318         assert(0==RTS_Wp_err);                                                                                                 \
00319         do {    /* so we can catch "break" statements */                                                                       \
00320             try {
00321                 
00322 #  define RTS_RWLOCK_END                                                                                                       \
00323             } catch (...) {                                                                                                    \
00324                 RTS_Wp_err = RTS_rwlock_unlock(RTS_Wp_rwlock);                                                                 \
00325                 assert(0==RTS_Wp_err);                                                                                         \
00326                 throw;                                                                                                         \
00327             }                                                                                                                  \
00328         } while (0);                                                                                                           \
00329         RTS_Wp_err = RTS_rwlock_unlock(RTS_Wp_rwlock);                                                                         \
00330         assert(0==RTS_Wp_err);                                                                                                 \
00331     } while (0)
00332 
00333 #else
00334 #  define RTS_RWLOCK(RWLOCK, HOW)                                                                                              \
00335     do {
00336 #  define RTS_RWLOCK_END                                                                                                       \
00337     } while (0)
00338 #endif
00339 
00340 #define RTS_READ(RWLOCK)        RTS_RWLOCK(RWLOCK, rdlock)                      
00341 #define RTS_READ_END            RTS_RWLOCK_END                                  
00342 #define RTS_WRITE(RWLOCK)       RTS_RWLOCK(RWLOCK, wrlock)                      
00343 #define RTS_WRITE_END           RTS_RWLOCK_END                                  
00345 /*******************************************************************************************************************************
00346  *                                      Types and functions for RTS_rwlock_t
00347  *
00348  * Programmers should generally use the RTS_READ and RTS_WRITE macros in their source code. The symbols defined here are
00349  * similar to pthread_rwlock* symbols and are mostly to support RTS_READ and RTS_WRITE macros (like how the RTS_mutex*
00350  * symbols support the RTS_MUTEX macro).
00351  *******************************************************************************************************************************/
00352 
00356 #ifdef ROSE_THREADS_ENABLED
00357 struct RTS_rwlock_t {
00358     unsigned magic;                             /* always RTS_RWLOCK_MAGIC after initialization */
00359     RTS_Layer layer;                            /* software layer to which this lock belongs, or zero */
00360     pthread_rwlock_t rwlock;                    /* the main read-write lock */
00361     RTS_mutex_t mutex;                          /* mutex to protect the following data members */
00362     size_t nlocks;                              /* number of write locks held */
00363     pthread_t owner;                            /* thread that currently holds the write lock */
00364 };
00365 #else
00366 struct RTS_rwlock_t {
00367     int dummy;
00368 };
00369 #endif
00370 
00371 #define RTS_RWLOCK_MAGIC 0x20e7f3f4
00372 
00374 #ifdef ROSE_THREADS_ENABLED
00375 #  define RTS_RWLOCK_INITIALIZER(LAYER) { RTS_RWLOCK_MAGIC,                                                                    \
00376                                           (LAYER),                                                                             \
00377                                           PTHREAD_RWLOCK_INITIALIZER,                                                          \
00378                                           RTS_MUTEX_INITIALIZER(RTS_LAYER_DONTCARE),                                           \
00379                                           0/*...*/                                                                             \
00380                                          }
00381 #else
00382 #  define RTS_RWLOCK_INITIALIZER(LAYER) { 0 }
00383 #endif
00384 
00385 #ifdef ROSE_THREADS_ENABLED
00386 
00387 int RTS_rwlock_init(RTS_rwlock_t *rwlock, RTS_Layer, pthread_rwlockattr_t *wrlock_attrs);
00388 #else
00389 int RTS_rwlock_init(RTS_rwlock_t *rwlock, RTS_Layer, void                 *wrlock_attrs);
00390 #endif
00391               
00405 int RTS_rwlock_rdlock(RTS_rwlock_t *rwlock);
00406 
00423 int RTS_rwlock_wrlock(RTS_rwlock_t *rwlock);
00424 
00436 int RTS_rwlock_unlock(RTS_rwlock_t *rwlock);
00437 
00438 
00439 
00440 /*******************************************************************************************************************************
00441  *                                      Paired macros for initialization functions
00442  *******************************************************************************************************************************/
00443 
00444 
00480 #ifdef ROSE_THREADS_ENABLED
00481 #  define RTS_INIT(MUTEX, ALLOW_RECURSION)                                                                                     \
00482     do {                                                                                                                       \
00483         static bool RTS_Is_initialized=false, RTS_Is_initializing=false;        /* "s"==shared; "p"=private */                 \
00484         static pthread_t RTS_Is_initializer;                                                                                   \
00485         static pthread_cond_t RTS_Is_condition=PTHREAD_COND_INITIALIZER;                                                       \
00486         RTS_mutex_t *RTS_Ip_mutex = &(MUTEX);                                                                                  \
00487         bool RTS_Ip_initialized, RTS_Ip_initializing;                                                                          \
00488         bool RTS_Ip_allow_recursion = (ALLOW_RECURSION);                                                                       \
00489                                                                                                                                \
00490         /* First critical section is only to obtain the initialization status and update it to "initializing" if necessary. We \
00491          * must release the lock before the RTS_I_LOCK body is executed in case we need to handle recursive calls to the       \
00492          * RTS_I_LOCK construct. */                                                                                            \
00493         RTS_MUTEX(MUTEX) {                                                                                                     \
00494             if (!(RTS_Ip_initialized=RTS_Is_initialized) && !(RTS_Ip_initializing=RTS_Is_initializing)) {                      \
00495                 RTS_Is_initializing = true; /* but leave private copy false so we can detect changed state */                  \
00496                 RTS_Is_initializer = pthread_self();                                                                           \
00497             }                                                                                                                  \
00498         } RTS_MUTEX_END;                                                                                                       \
00499                                                                                                                                \
00500         if (!RTS_Ip_initialized) {                                                                                             \
00501             if (!RTS_Ip_initializing) {                                                                                        \
00502                 do { /* so we catch "break" statements in user-supplied code. */                                               \
00503                     try {
00504 
00505 
00507 #  define RTS_INIT_END                                                                                                         \
00508                     } catch (...) {                                                                                            \
00509                         /* If the user supplied body throws an exception, consider the body to have completed. */              \
00510                         RTS_MUTEX(*RTS_Ip_mutex) {                                                                             \
00511                             RTS_Is_initialized = true;                                                                         \
00512                             RTS_Is_initializing = false;                                                                       \
00513                             pthread_cond_broadcast(&RTS_Is_condition);                                                         \
00514                         } RTS_MUTEX_END;                                                                                       \
00515                         throw;                                                                                                 \
00516                     }                                                                                                          \
00517                 } while (0);                                                                                                   \
00518                 RTS_MUTEX(*RTS_Ip_mutex) {                                                                                     \
00519                     RTS_Is_initialized = true;                                                                                 \
00520                     RTS_Is_initializing = false;                                                                               \
00521                     pthread_cond_broadcast(&RTS_Is_condition);                                                                 \
00522                 } RTS_MUTEX_END;                                                                                               \
00523             } else if (pthread_equal(pthread_self(), RTS_Is_initializer)) {                                                    \
00524                 /* This was a recursive call resulting from the user-supplied RTS_I body and we must allow it to continue      \
00525                  * unimpeded to prevent deadlock. We don't need to be holding the MUTEX lock to access RTS_Is_initializer      \
00526                  * because it's initialized only the first time through the critical section above--and the only way to reach  \
00527                  * this point is by this or some other thread having already initialized RTS_Is_initializer. */                \
00528                 if (!RTS_Ip_allow_recursion) {                                                                                 \
00529                     fprintf(stderr, "RTS_I_LOCK body made a recursive call. Aborting...\n");                                   \
00530                     abort();                                                                                                   \
00531                 }                                                                                                              \
00532             } else {                                                                                                           \
00533                 /* This is some other thread which is not in charge of initializing the class, bug which arrived to the        \
00534                  * RTS_I_LOCK before the first thread completed the initialization. */                                         \
00535                 RTS_MUTEX(*RTS_Ip_mutex) {                                                                                     \
00536                     while (!RTS_Is_initialized)                                                                                \
00537                         pthread_cond_wait(&RTS_Is_condition, &(RTS_Ip_mutex->mutex));                                          \
00538                 } RTS_MUTEX_END;                                                                                               \
00539             }                                                                                                                  \
00540         }                                                                                                                      \
00541     } while (0)
00542 #else
00543 #  define RTS_INIT(MUTEX, ALLOW_RECURSION)                                                                                     \
00544     do {                                                                                                                       \
00545         static bool RTS_Is_initialized=false;                                                                                  \
00546         if (!RTS_Is_initialized) {                                                                                             \
00547             RTS_Is_initialized = true;                                                                                         \
00548             do {
00549 #  define RTS_INIT_END                                                                                                         \
00550             } while (0);                                                                                                       \
00551         }                                                                                                                      \
00552     } while (0)
00553 #endif
00554 
00555 #define RTS_INIT_RECURSIVE(MUTEX)       RTS_INIT(MUTEX, true)                   
00556 #define RTS_INIT_NONRECURSIVE(MUTEX)    RTS_INIT(MUTEX, false)                  
00559 /******************************************************************************************************************************
00560  *                                      Support for messages
00561  ******************************************************************************************************************************/
00562 
00573 class RTS_Message {
00574 public:
00578     class Prefix {
00579     public:
00580         virtual ~Prefix() {};
00581         virtual void operator()(FILE*) {}
00582     };
00583 
00594     RTS_Message(FILE *f, Prefix *p)
00595         : f(f), p(p), buffer(NULL), bufsz(0), interrupted(false) {
00596         ctor();
00597     }
00598 
00599     ~RTS_Message() {
00600         dtor();
00601     }
00602 
00604     void set_file(FILE *f) {
00605         this->f = f;
00606     }
00607 
00609     FILE *get_file() const {
00610         return f;
00611     }
00612 
00633     RTS_Message& multipart(const std::string &name, const char *fmt, ...) __attribute__((format(printf, 3, 4)));
00634 
00647     RTS_Message& more(const char *fmt, ...) __attribute__((format(printf, 2, 3)));
00648 
00652     void multipart_end();
00653 
00667     RTS_Message& mesg(const char *fmt, ...) __attribute__((format(printf, 2, 3)));
00668 
00683     RTS_Message& brief(const char *fmt, ...) __attribute__((format(printf, 2, 3)));
00684 
00688     void brief_begin(const char *fmt, ...) __attribute__((format(printf, 2, 3)));
00689 
00691     void brief_end(const char *fmt, ...) __attribute__((format(printf, 2, 3)));
00692 
00703     int lock();
00704 
00710     int unlock(bool sol=true);
00711 
00712 private:
00713     RTS_Message() {abort();}
00714     RTS_Message& operator=(RTS_Message&) { abort(); return *this; } // return is to silence Klocwork
00715     void ctor();                                        
00716     void dtor();                                        
00717     void terminate();                                   
00718     void prefix();                                      
00719     void output_lines(const char *s);                   
00720     void format(const char *fmt, va_list, va_list);    
00722     static RTS_rwlock_t rwlock;                         
00723     static RTS_Message *in_multi;                       
00724     static bool sol;                                    
00726     FILE *f;                                            
00727     Prefix *p;                                          
00728     char *buffer;                                       
00729     size_t bufsz;                                       
00730     std::string name;                                   
00731     bool interrupted;                                   
00732 };
00733 
00734 /******************************************************************************************************************************
00735  *                                      Paired macros for messages
00736  ******************************************************************************************************************************/
00737 
00771 #ifdef ROSE_THREADS_ENABLED
00772 #  define RTS_MESSAGE(MESG)                                                                                                    \
00773     do {                                                                                                                       \
00774         RTS_Message *RTS_Mp_mesg = &(MESG);                                                                                    \
00775         int RTS_Mp_err = RTS_Mp_mesg->lock();                                                                                  \
00776         assert(0==RTS_Mp_err);                                                                                                 \
00777         do {                                                                                                                   \
00778             try {
00779 
00780 #  define RTS_MESSAGE_END(SOL)                                                                                                 \
00781             } catch (...) {                                                                                                    \
00782                 RTS_Mp_err = RTS_Mp_mesg->unlock((SOL));                                                                       \
00783                 assert(0==RTS_Mp_err);                                                                                         \
00784                 throw;                                                                                                         \
00785             }                                                                                                                  \
00786         } while (0);                                                                                                           \
00787         RTS_Mp_err = RTS_Mp_mesg->unlock((SOL));                                                                               \
00788         assert(0==RTS_Mp_err);                                                                                                 \
00789     } while (0)
00790 #else
00791 #  define RTS_MESSAGE(MESG)                                                                                                    \
00792     do {
00793 #  define RTS_MESSAGE_END(SOL)                                                                                                 \
00794     } while (0)
00795 #endif
00796 
00800 #endif /* !ROSE_threadSupport_H !*/

Generated on Sat May 19 00:53:07 2012 for ROSE by  doxygen 1.4.7