Home | History | Annotate | Download | only in common
      1 /*
      2 ******************************************************************************
      3 *
      4 *   Copyright (C) 1997-2010, International Business Machines
      5 *   Corporation and others.  All Rights Reserved.
      6 *
      7 ******************************************************************************
      8 */
      9 //----------------------------------------------------------------------------
     10 // File:     mutex.h
     11 //
     12 // Lightweight C++ wrapper for umtx_ C mutex functions
     13 //
     14 // Author:   Alan Liu  1/31/97
     15 // History:
     16 // 06/04/97   helena         Updated setImplementation as per feedback from 5/21 drop.
     17 // 04/07/1999  srl               refocused as a thin wrapper
     18 //
     19 //----------------------------------------------------------------------------
     20 #ifndef MUTEX_H
     21 #define MUTEX_H
     22 
     23 #include "unicode/utypes.h"
     24 #include "unicode/uobject.h"
     25 #include "umutex.h"
     26 
     27 U_NAMESPACE_BEGIN
     28 
     29 //----------------------------------------------------------------------------
     30 // Code within that accesses shared static or global data should
     31 // should instantiate a Mutex object while doing so. You should make your own
     32 // private mutex where possible.
     33 
     34 // For example:
     35 //
     36 // UMTX myMutex;
     37 //
     38 // void Function(int arg1, int arg2)
     39 // {
     40 //    static Object* foo;     // Shared read-write object
     41 //    Mutex mutex(&myMutex);  // or no args for the global lock
     42 //    foo->Method();
     43 //    // When 'mutex' goes out of scope and gets destroyed here, the lock is released
     44 // }
     45 //
     46 // Note:  Do NOT use the form 'Mutex mutex();' as that merely forward-declares a function
     47 //        returning a Mutex. This is a common mistake which silently slips through the
     48 //        compiler!!
     49 //
     50 
     51 class U_COMMON_API Mutex : public UMemory {
     52 public:
     53   inline Mutex(UMTX *mutex = NULL);
     54   inline ~Mutex();
     55 
     56 private:
     57   UMTX   *fMutex;
     58 
     59   Mutex(const Mutex &other); // forbid copying of this class
     60   Mutex &operator=(const Mutex &other); // forbid copying of this class
     61 };
     62 
     63 inline Mutex::Mutex(UMTX *mutex)
     64   : fMutex(mutex)
     65 {
     66   umtx_lock(fMutex);
     67 }
     68 
     69 inline Mutex::~Mutex()
     70 {
     71   umtx_unlock(fMutex);
     72 }
     73 
     74 // common code for singletons ---------------------------------------------- ***
     75 
     76 /**
     77  * Function pointer for the instantiator parameter of
     78  * SimpleSingleton::getInstance() and TriStateSingleton::getInstance().
     79  * The function creates some object, optionally using the context parameter.
     80  * The function need not check for U_FAILURE(errorCode).
     81  */
     82 typedef void *InstantiatorFn(const void *context, UErrorCode &errorCode);
     83 
     84 /**
     85  * Singleton struct with shared instantiation/mutexing code.
     86  * Simple: Does not remember if a previous instantiation failed.
     87  * Best used if the instantiation can really only fail with an out-of-memory error,
     88  * otherwise use a TriStateSingleton.
     89  * Best used via SimpleSingletonWrapper or similar.
     90  * Define a static SimpleSingleton instance via the STATIC_SIMPLE_SINGLETON macro.
     91  */
     92 struct SimpleSingleton {
     93     void *fInstance;
     94 
     95     /**
     96      * Returns the singleton instance, or NULL if it could not be created.
     97      * Calls the instantiator with the context if the instance has not been
     98      * created yet. In a race condition, the duplicate may not be NULL.
     99      * The caller must delete the duplicate.
    100      * The caller need not initialize the duplicate before the call.
    101      */
    102     void *getInstance(InstantiatorFn *instantiator, const void *context,
    103                       void *&duplicate,
    104                       UErrorCode &errorCode);
    105     /**
    106      * Resets the fields. The caller must have deleted the singleton instance.
    107      * Not mutexed.
    108      * Call this from a cleanup function.
    109      */
    110     void reset() { fInstance=NULL; }
    111 };
    112 
    113 #define STATIC_SIMPLE_SINGLETON(name) static SimpleSingleton name={ NULL }
    114 
    115 /**
    116  * Handy wrapper for an SimpleSingleton.
    117  * Intended for temporary use on the stack, to make the SimpleSingleton easier to deal with.
    118  * Takes care of the duplicate deletion and type casting.
    119  */
    120 template<typename T>
    121 class SimpleSingletonWrapper {
    122 public:
    123     SimpleSingletonWrapper(SimpleSingleton &s) : singleton(s) {}
    124     void deleteInstance() {
    125         delete (T *)singleton.fInstance;
    126         singleton.reset();
    127     }
    128     T *getInstance(InstantiatorFn *instantiator, const void *context,
    129                    UErrorCode &errorCode) {
    130         void *duplicate;
    131         T *instance=(T *)singleton.getInstance(instantiator, context, duplicate, errorCode);
    132         delete (T *)duplicate;
    133         return instance;
    134     }
    135 private:
    136     SimpleSingleton &singleton;
    137 };
    138 
    139 /**
    140  * Singleton struct with shared instantiation/mutexing code.
    141  * Tri-state: Instantiation succeeded/failed/not attempted yet.
    142  * Best used via TriStateSingletonWrapper or similar.
    143  * Define a static TriStateSingleton instance via the STATIC_TRI_STATE_SINGLETON macro.
    144  */
    145 struct TriStateSingleton {
    146     void *fInstance;
    147     UErrorCode fErrorCode;
    148     int8_t fHaveInstance;
    149 
    150     /**
    151      * Returns the singleton instance, or NULL if it could not be created.
    152      * Calls the instantiator with the context if the instance has not been
    153      * created yet. In a race condition, the duplicate may not be NULL.
    154      * The caller must delete the duplicate.
    155      * The caller need not initialize the duplicate before the call.
    156      * The singleton creation is only attempted once. If it fails,
    157      * the singleton will then always return NULL.
    158      */
    159     void *getInstance(InstantiatorFn *instantiator, const void *context,
    160                       void *&duplicate,
    161                       UErrorCode &errorCode);
    162     /**
    163      * Resets the fields. The caller must have deleted the singleton instance.
    164      * Not mutexed.
    165      * Call this from a cleanup function.
    166      */
    167     void reset();
    168 };
    169 
    170 #define STATIC_TRI_STATE_SINGLETON(name) static TriStateSingleton name={ NULL, U_ZERO_ERROR, 0 }
    171 
    172 /**
    173  * Handy wrapper for an TriStateSingleton.
    174  * Intended for temporary use on the stack, to make the TriStateSingleton easier to deal with.
    175  * Takes care of the duplicate deletion and type casting.
    176  */
    177 template<typename T>
    178 class TriStateSingletonWrapper {
    179 public:
    180     TriStateSingletonWrapper(TriStateSingleton &s) : singleton(s) {}
    181     void deleteInstance() {
    182         delete (T *)singleton.fInstance;
    183         singleton.reset();
    184     }
    185     T *getInstance(InstantiatorFn *instantiator, const void *context,
    186                    UErrorCode &errorCode) {
    187         void *duplicate;
    188         T *instance=(T *)singleton.getInstance(instantiator, context, duplicate, errorCode);
    189         delete (T *)duplicate;
    190         return instance;
    191     }
    192 private:
    193     TriStateSingleton &singleton;
    194 };
    195 
    196 U_NAMESPACE_END
    197 
    198 #endif //_MUTEX_
    199 //eof
    200