Source code formating unification
[framework/web/wrt-commons.git] / modules / core / include / dpl / thread.h
1 /*
2  * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved
3  *
4  *    Licensed under the Apache License, Version 2.0 (the "License");
5  *    you may not use this file except in compliance with the License.
6  *    You may obtain a copy of the License at
7  *
8  *        http://www.apache.org/licenses/LICENSE-2.0
9  *
10  *    Unless required by applicable law or agreed to in writing, software
11  *    distributed under the License is distributed on an "AS IS" BASIS,
12  *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  *    See the License for the specific language governing permissions and
14  *    limitations under the License.
15  */
16 /*
17  * @file        thread.h
18  * @author      Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com)
19  * @version     1.0
20  * @brief       This file is the implementation file of thread
21  */
22 #ifndef DPL_THREAD_H
23 #define DPL_THREAD_H
24
25 #include <dpl/waitable_handle_watch_support.h>
26 //#include <dpl/waitable_event.h>
27 //#include <dpl/waitable_handle.h>
28 #include <dpl/noncopyable.h>
29 #include <dpl/exception.h>
30 #include <dpl/mutex.h>
31 #include <dpl/assert.h>
32 #include <dpl/optional.h>
33 #include <stdint.h>
34 #include <cstdlib>
35 #include <pthread.h>
36 #include <algorithm>
37 #include <utility>
38 #include <vector>
39 #include <list>
40 #include <map>
41
42 namespace DPL {
43 class Thread :
44     private Noncopyable,
45     public WaitableHandleWatchSupport
46 {
47   public:
48     class Exception
49     {
50       public:
51         DECLARE_EXCEPTION_TYPE(DPL::Exception, Base)
52         DECLARE_EXCEPTION_TYPE(Base, CreateFailed)
53         DECLARE_EXCEPTION_TYPE(Base, DestroyFailed)
54         DECLARE_EXCEPTION_TYPE(Base, RunFailed)
55         DECLARE_EXCEPTION_TYPE(Base, QuitFailed)
56         DECLARE_EXCEPTION_TYPE(Base, UnmanagedThread)
57     };
58
59     typedef void (*EventDeleteProc)(void *event, void *userParam);
60     typedef void (*EventDispatchProc)(void *event, void *userParam);
61
62   protected:
63     /**
64      * Main thread entry
65      * The method is intended to be overloaded with custom code.
66      * Default implementation just executes Exec method to process
67      * all thread exents
68      */
69     virtual int ThreadEntry();
70
71     /**
72      * Start processing of thread events
73      */
74     int Exec();
75
76   private:
77     struct InternalEvent
78     {
79         void *event;
80         void *userParam;
81         EventDispatchProc eventDispatchProc;
82         EventDeleteProc eventDeleteProc;
83
84         InternalEvent(void *eventArg,
85                       void *userParamArg,
86                       EventDispatchProc eventDispatchProcArg,
87                       EventDeleteProc eventDeleteProcArg) :
88             event(eventArg),
89             userParam(userParamArg),
90             eventDispatchProc(eventDispatchProcArg),
91             eventDeleteProc(eventDeleteProcArg)
92         {}
93     };
94
95     struct InternalTimedEvent :
96         InternalEvent
97     {
98         unsigned long dueTimeMiliseconds;
99         unsigned long registerTimeMiliseconds;
100
101         InternalTimedEvent(void *eventArg,
102                            void *userParamArg,
103                            unsigned long dueTimeMilisecondsArg,
104                            unsigned long registerTimeMilisecondsArg,
105                            EventDispatchProc eventDispatchProcArg,
106                            EventDeleteProc eventDeleteProcArg) :
107             InternalEvent(eventArg,
108                           userParamArg,
109                           eventDispatchProcArg,
110                           eventDeleteProcArg),
111             dueTimeMiliseconds(dueTimeMilisecondsArg),
112             registerTimeMiliseconds(registerTimeMilisecondsArg)
113         {}
114
115         bool operator<(const InternalTimedEvent &other)
116         {
117             return registerTimeMiliseconds + dueTimeMiliseconds >
118                    other.registerTimeMiliseconds + other.dueTimeMiliseconds;
119         }
120     };
121
122     // Internal event list
123     typedef std::list<InternalEvent> InternalEventList;
124
125     // Internal timed event list
126     typedef std::vector<InternalTimedEvent> InternalTimedEventVector;
127
128     // State managment
129     pthread_t m_thread;
130     volatile bool m_abandon;
131     volatile bool m_running;
132     Mutex m_stateMutex;
133     WaitableEvent m_quitEvent;
134
135     // Event processing
136     Mutex m_eventMutex;
137     InternalEventList m_eventList;
138     WaitableEvent m_eventInvoker;
139
140     // Timed events processing
141     Mutex m_timedEventMutex;
142     InternalTimedEventVector m_timedEventVector;
143     WaitableEvent m_timedEventInvoker;
144
145     // WaitableHandleWatchSupport
146     virtual Thread *GetInvokerThread();
147     virtual void HandleDirectInvoker();
148     bool m_directInvoke;
149
150     // Internals
151     unsigned long GetCurrentTimeMiliseconds() const;
152     void ProcessEvents();
153     void ProcessTimedEvents();
154
155     static void *StaticThreadEntry(void *param);
156
157   public:
158     explicit Thread();
159     virtual ~Thread();
160
161     /**
162      * Run thread. Does nothing if thread is already running
163      */
164     void Run();
165
166     /**
167      * Send quit message to thread and wait for its end
168      * Does nothing is thread is not running
169      */
170     void Quit();
171
172     /**
173      * Checks if current thread is main one
174      * Returns true if it is main program thread, false otherwise
175      */
176     static bool IsMainThread();
177
178     /**
179      * Current thread retrieval
180      * Returns DPL thread handle or NULL if it is main program thread
181      */
182     static Thread *GetCurrentThread();
183
184     /**
185      * Low-level event push, usually used only by EventSupport
186      */
187     void PushEvent(void *event,
188                    EventDispatchProc eventDispatchProc,
189                    EventDeleteProc eventDeleteProc,
190                    void *userParam);
191
192     /**
193      * Low-level timed event push, usually used only by EventSupport
194      */
195     void PushTimedEvent(void *event,
196                         double dueTimeSeconds,
197                         EventDispatchProc eventDispatchProc,
198                         EventDeleteProc eventDeleteProc,
199                         void *userParam);
200
201     /**
202      * Sleep for a number of seconds
203      */
204     static void Sleep(uint64_t seconds);
205
206     /**
207      * Sleep for a number of miliseconds
208      */
209     static void MiliSleep(uint64_t miliseconds);
210
211     /**
212      * Sleep for a number of microseconds
213      */
214     static void MicroSleep(uint64_t microseconds);
215
216     /**
217      * Sleep for a number of nanoseconds
218      */
219     static void NanoSleep(uint64_t nanoseconds);
220 };
221
222 extern bool g_TLSforMainCreated;
223
224 // In case of using TLV in main thread, pthread_exit(NULL) has to be called in
225 // this thread explicitly.
226 // On the other hand, possibly, because of the kernel bug, there exist
227 // a problem, if any other thread than main exist during pthread_exit call
228 // (process can become non-responsive)
229 // TODO further investigation is required.
230 template<typename Type>
231 class ThreadLocalVariable :
232     public Noncopyable
233 {
234   public:
235     typedef Type ValueType;
236
237     class Exception
238     {
239       public:
240         DECLARE_EXCEPTION_TYPE(DPL::Exception, Base)
241         DECLARE_EXCEPTION_TYPE(Base, NullReference)
242         DECLARE_EXCEPTION_TYPE(Base, KeyCreateFailed)
243     };
244
245   private:
246     pthread_key_t m_key;
247
248     struct ManagedValue
249     {
250         ValueType value;
251         Optional<pthread_key_t> guardKey;
252     };
253
254     static void MainThreadExitClean()
255     {
256         // There is a possible bug in kernel. If this function is called
257         // before ALL threads are closed, process will hang!
258         // Because of that, by default this function has to be called in well
259         // known "threads state".
260
261         // pthread_exit(NULL);
262     }
263
264     static void InternalDestroy(void *specific)
265     {
266         // Destroy underlying type
267         ManagedValue *instance = static_cast<ManagedValue *>(specific);
268         if (instance->guardKey.IsNull()) {
269             delete instance;
270         } else {
271             int result = pthread_setspecific(*(instance->guardKey), instance);
272
273             Assert(result == 0 &&
274                    "Failed to set thread local variable");
275         }
276     }
277
278     Type &Reference(bool allowInstantiate = false)
279     {
280         ManagedValue *instance =
281             static_cast<ManagedValue *>(pthread_getspecific(m_key));
282
283         if (!instance) {
284             // Check if it is allowed to instantiate
285             if (!allowInstantiate) {
286                 Throw(typename Exception::NullReference);
287             }
288
289             // checking, if specific data is created for Main thread
290             // If yes, pthread_exit(NULL) is required
291             if (!g_TLSforMainCreated) {
292                 if (Thread::IsMainThread()) {
293                     g_TLSforMainCreated = true;
294                     atexit(&MainThreadExitClean);
295                 }
296             }
297
298             // Need to instantiate underlying type
299             instance = new ManagedValue();
300
301             int result = pthread_setspecific(m_key, instance);
302
303             Assert(result == 0 &&
304                    "Failed to set thread local variable");
305         }
306
307         return instance->value;
308     }
309
310   public:
311     ThreadLocalVariable()
312     {
313         int result = pthread_key_create(&m_key, &InternalDestroy);
314         if (result != 0) {
315             ThrowMsg(typename Exception::KeyCreateFailed,
316                      "Failed to allocate thread local variable: " << result);
317         }
318     }
319
320     ~ThreadLocalVariable()
321     {
322         pthread_key_delete(m_key);
323     }
324
325     Type &operator=(const Type &other)
326     {
327         Type &reference = Reference(true);
328         reference = other;
329         return reference;
330     }
331
332     bool IsNull() const
333     {
334         return pthread_getspecific(m_key) == NULL;
335     }
336
337     Type& operator*()
338     {
339         return Reference();
340     }
341
342     const Type& operator*() const
343     {
344         return Reference();
345     }
346
347     const Type* operator->() const
348     {
349         return &Reference();
350     }
351
352     Type* operator->()
353     {
354         return &Reference();
355     }
356
357     bool operator!() const
358     {
359         return IsNull();
360     }
361
362     void Reset()
363     {
364         ManagedValue *specific =
365             static_cast<ManagedValue *>(pthread_getspecific(m_key));
366
367         if (!specific) {
368             return;
369         }
370
371         // TODO Should be an assert? is it developers fault to Reset Guarded
372         // value?
373         specific->guardKey = Optional<pthread_key_t>::Null;
374
375         InternalDestroy(specific);
376
377         int result = pthread_setspecific(m_key, NULL);
378
379         Assert(result == 0 &&
380                "Failed to reset thread local variable");
381     }
382
383     // GuardValue(true) allows to defer destroy (by pthread internal
384     // functionality) thread specific value until GuardValue(false) will be
385     // called.
386     void GuardValue(bool guard)
387     {
388         ManagedValue *instance =
389             static_cast<ManagedValue *>(pthread_getspecific(m_key));
390
391         Assert(instance && "Failed to get the value");
392
393         instance->guardKey = guard ? m_key : Optional<pthread_key_t>::Null;
394     }
395 };
396 } // namespace DPL
397
398 #endif // DPL_THREAD_H