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
27U_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
51class U_COMMON_API Mutex : public UMemory {
52public:
53  inline Mutex(UMTX *mutex = NULL);
54  inline ~Mutex();
55
56private:
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
63inline Mutex::Mutex(UMTX *mutex)
64  : fMutex(mutex)
65{
66  umtx_lock(fMutex);
67}
68
69inline 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 */
82typedef 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 */
92struct 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 */
120template<typename T>
121class SimpleSingletonWrapper {
122public:
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    }
135private:
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 */
145struct 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 */
177template<typename T>
178class TriStateSingletonWrapper {
179public:
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    }
192private:
193    TriStateSingleton &singleton;
194};
195
196U_NAMESPACE_END
197
198#endif //_MUTEX_
199//eof
200