summaryrefslogtreecommitdiff
path: root/SDL_Core/src/thirdPartyLibs/MessageBroker/include/system.h
blob: fac4f7926befdeab773643dc9210a8e49eba62fc (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
/**
 * \file system.h
 * \brief System utils.
 * \author Sebastien Vincent
 */

#ifndef SYSTEM_H
#define SYSTEM_H

#ifdef _WIN32

#include <windows.h>

#else

#include <pthread.h>

#endif

/**
 * \namespace System
 * \brief System related class (thread, ...).
 */
namespace System
{

  /**
   * \brief Sleep for x milliseconds
   * \param ms millisecond to sleep
   */
  void msleep(unsigned long ms);

  /**
   * \class ThreadArg
   * \brief Abstract class to represent thread argument.
   * \see ThreadArgImpl
   * \see Thread
   */
  class ThreadArg 
  {
    public:
      /**
       * \brief Destructor.
       */
      virtual ~ThreadArg();

      /**
       * \brief Call the method.
       * \note Have to be implemented by subclasses
       */
      virtual void* Call() = 0;
  };

  /**
   * \class ThreadArgImpl
   * \brief Template class that represent thread argument.
   *
   * This class is used to provide callback function within 
   * an object. The method which will be called during thread
   * execution must be of the form <code>void* MyMethod(void* arg)</code>. 
   * Inside this method you are free to called any method of the object.
   *
   * \warning As class keep pointer of object reference, you should take 
   * care at the lifetime of object you pass in ThreadArgImpl constructor,
   * else it could lead to crash your program.\n See Thread class documentation
   * for an example of how to use ThreadArgImpl class.
   * \see Thread
   */
  template<class T> class ThreadArgImpl : public ThreadArg
  {
    public:
      /**
       * \typedef Method
       * \brief T method signature.
       */
      typedef void* (T::*Method)(void*);

      /**
       * \brief Constructor.
       * \param obj object
       * \param method class method
       * \param arg argument to method
       */
      ThreadArgImpl(T& obj, Method method, void* arg)
      {
        m_obj = &obj;
        m_method = method;
        m_arg = arg;
      }

      /**
       * \brief Call the method.
       */
      virtual void* Call()
      {
        return (m_obj->*m_method)(m_arg);
      }

    private:
      /**
       * \brief Object pointer.
       */
      T* m_obj;

      /**
       * \brief Method of T class.
       */
      Method m_method;

      /**
       * \brief Argument of method.
       */
      void* m_arg;
  };

  /**
   * \class Thread
   * \brief Thread implementation.
   *
   * Preferred use of this class is to construct ThreadArgImpl inside
   * another class and pass <code>*this</code> as obj parameter:\n
   * \n
   * \code
   * class MyClass
   * {
   *    public:
   *      void MyMethod()
   *      {
   *        ThreadArg* arg = new ThreadArgImpl<MyClass>(*this, &MyClass::MethodForThread, NULL);
   *        Thread th(arg);
   *        th.Start();
   *      }
   *
   *      void* MethodForThread(void * arg)
   *      {
   *        // do stuff 
   *      }
   * };
   * \endcode
   *
   */
  class Thread
  {
    public:
      /**
       * \brief Constructor.
       * \param arg thread argument (MUST be dynamically allocated using new)
       * \note System::Thread object takes care of freeing method memory.\n
       * The way of calling constructor is:
       * <code>
       * Thread thread(new ThreadArgImpl<MyClass>(instanceOfMyClass, &MyClass::Method));
       * </code>
       * \warning You should take care of the object (instanceOfMyClass) lifetime pass 
       * into ThreadArgImpl constructor, else it could lead to a crash because ThreadArgImpl
       * keep pointer of the reference.
       * \warning The "arg" parameter MUST be dynamically allocated (using new).
       * \see ThreadArgImpl
       */
      Thread(ThreadArg* arg);

      /**
       * \brief Destructor.
       */
      virtual ~Thread();

      /**
       * \brief Start thread.
       * \param detach if set to true, the thread will be in detach state so 
       * you do not have to call join on this type of thread.
       * \return true if success, false otherwise
       * \warning Do NOT <code>Join</code> a detached thread.
       */
      bool Start(bool detach);

      /**
       * \brief Stop thread.
       * \return true if success, false otherwise
       * \warning Calling this method could lead callback object to an 
       * incoherent state. You should call it really in desperate situations when
       * you really want to stop thread and do not care about the rest.
       * \warning With POSIX thread implementation, calling Stop (one or more times)
       * will leak 28 bytes of memory.
       */
      bool Stop();

      /**
       * \brief Join thread.
       * \param ret pointer to return code of the joined thread
       * \return true if success, false otherwise
       * \warning Do NOT <code>Join</code> a detached thread.
       */
      bool Join(void** ret = NULL);

#ifdef _WIN32
      HANDLE
#else
      pthread_t
#endif
      GetId() const {
        return m_id;
      }

    private:
      /**
       * \brief Entry point of thread before calling specific 
       * callback.
       * \param arg thread argument
       * \return result of ThreadArg callback
       */
#ifdef _WIN32
      static DWORD WINAPI Call(LPVOID arg);
#else
      static void* Call(void* arg);
#endif
      /**
       * \brief Thread identifier.
       */
#ifdef _WIN32 /* Win32 thread */
      HANDLE m_id;
#else /* POSIX thread */
      pthread_t m_id;
#endif

      /**
       * \brief Thread argument.
       */
      ThreadArg* m_arg;
  };

  /**
   * \class Mutex
   * \brief Mutex implementation.
   */
  class Mutex
  {
    public:
      /**
       * \brief Constructor.
       */
      Mutex();

      /**
       * \brief Destructor.
       */
      ~Mutex();

      /**
       * \brief Lock the mutex.
       * \return true if mutex is locked, false if error
       */
      bool Lock();
      
      /**
       * \brief Unlock the mutex.
       * \return true if mutex is unlocked, false if error
       */
      bool Unlock();

    private:
      /**
       * \brief The mutex.
       */
#ifdef _WIN32
      HANDLE m_mutex;
#else
      pthread_mutex_t m_mutex;
#endif
  };

#ifdef _WIN32
#warning "BinarySemaphore is implemented for POSIX systems only"
#else
  /**
   * \class BinarySemaphore
   * \brief Binary semaphore implementation.
   */
  class BinarySemaphore {
  public:
    /**
      * \brief Constructor.
      */
    BinarySemaphore();

    /**
      * \brief Destructor.
      */
    ~BinarySemaphore();

    /**
      * \brief Wait until the semaphore is unlocked.
      */
    void Wait();

    /**
      * \brief Notify the semaphore.
      */
    void Notify();

  private:
    /**
      * \brief Mutex to prevent concurrent access to the flag.
      */
    pthread_mutex_t m_mutex;

    /**
      * \brief Conditional variable to block threads.
      */
    pthread_cond_t m_cond;

    /**
      * \brief Semaphore state: false = down, true = up.
      */
    bool m_isUp;
  };
#endif /* _WIN32 */

} /* namespace System */

#endif /* SYSTEM_H */