Tizen 2.0 Release
[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 {
44 class Thread
45     : private Noncopyable,
46       public WaitableHandleWatchSupport
47 {
48 public:
49     class Exception
50     {
51     public:
52         DECLARE_EXCEPTION_TYPE(DPL::Exception, Base)
53         DECLARE_EXCEPTION_TYPE(Base, CreateFailed)
54         DECLARE_EXCEPTION_TYPE(Base, DestroyFailed)
55         DECLARE_EXCEPTION_TYPE(Base, RunFailed)
56         DECLARE_EXCEPTION_TYPE(Base, QuitFailed)
57         DECLARE_EXCEPTION_TYPE(Base, UnmanagedThread)
58     };
59
60     typedef void (*EventDeleteProc)(void *event, void *userParam);
61     typedef void (*EventDispatchProc)(void *event, void *userParam);
62
63 protected:
64     /**
65      * Main thread entry
66      * The method is intended to be overloaded with custom code.
67      * Default implementation just executes Exec method to process
68      * all thread exents
69      */
70     virtual int ThreadEntry();
71
72     /**
73      * Start processing of thread events
74      */
75     int Exec();
76
77 private:
78     struct InternalEvent
79     {
80         void *event;
81         void *userParam;
82         EventDispatchProc eventDispatchProc;
83         EventDeleteProc eventDeleteProc;
84
85         InternalEvent(void *eventArg,
86                       void *userParamArg,
87                       EventDispatchProc eventDispatchProcArg,
88                       EventDeleteProc eventDeleteProcArg)
89             : event(eventArg),
90               userParam(userParamArg),
91               eventDispatchProc(eventDispatchProcArg),
92               eventDeleteProc(eventDeleteProcArg)
93         {
94         }
95     };
96
97     struct InternalTimedEvent
98         : InternalEvent
99     {
100         unsigned long dueTimeMiliseconds;
101         unsigned long registerTimeMiliseconds;
102
103         InternalTimedEvent(void *eventArg,
104                            void *userParamArg,
105                            unsigned long dueTimeMilisecondsArg,
106                            unsigned long registerTimeMilisecondsArg,
107                            EventDispatchProc eventDispatchProcArg,
108                            EventDeleteProc eventDeleteProcArg)
109             : InternalEvent(eventArg,
110                             userParamArg,
111                             eventDispatchProcArg,
112                             eventDeleteProcArg),
113               dueTimeMiliseconds(dueTimeMilisecondsArg),
114               registerTimeMiliseconds(registerTimeMilisecondsArg)
115         {
116         }
117
118         bool operator<(const InternalTimedEvent &other)
119         {
120             return registerTimeMiliseconds + dueTimeMiliseconds > other.registerTimeMiliseconds + other.dueTimeMiliseconds;
121         }
122     };
123
124     // Internal event list
125     typedef std::list<InternalEvent> InternalEventList;
126
127     // Internal timed event list
128     typedef std::vector<InternalTimedEvent> InternalTimedEventVector;
129
130     // State managment
131     pthread_t m_thread;
132     volatile bool m_abandon;
133     volatile bool m_running;
134     Mutex m_stateMutex;
135     WaitableEvent m_quitEvent;
136
137     // Event processing
138     Mutex m_eventMutex;
139     InternalEventList m_eventList;
140     WaitableEvent m_eventInvoker;
141
142     // Timed events processing
143     Mutex m_timedEventMutex;
144     InternalTimedEventVector m_timedEventVector;
145     WaitableEvent m_timedEventInvoker;
146
147     // WaitableHandleWatchSupport
148     virtual Thread *GetInvokerThread();
149     virtual void HandleDirectInvoker();
150     bool m_directInvoke;
151
152     // Internals
153     unsigned long GetCurrentTimeMiliseconds() const;
154     void ProcessEvents();
155     void ProcessTimedEvents();
156
157     static void *StaticThreadEntry(void *param);
158
159 public:
160     explicit Thread();
161     virtual ~Thread();
162
163     /**
164      * Run thread. Does nothing if thread is already running
165      */
166     void Run();
167
168     /**
169      * Send quit message to thread and wait for its end
170      * Does nothing is thread is not running
171      */
172     void Quit();
173
174     /**
175      * Checks if current thread is main one
176      * Returns true if it is main program thread, false otherwise
177      */
178     static bool IsMainThread();
179
180     /**
181      * Current thread retrieval
182      * Returns DPL thread handle or NULL if it is main program thread
183      */
184     static Thread *GetCurrentThread();
185
186     /**
187      * Low-level event push, usually used only by EventSupport
188      */
189     void PushEvent(void *event, EventDispatchProc eventDispatchProc, EventDeleteProc eventDeleteProc, void *userParam);
190
191     /**
192      * Low-level timed event push, usually used only by EventSupport
193      */
194     void PushTimedEvent(void *event, double dueTimeSeconds, EventDispatchProc eventDispatchProc, EventDeleteProc eventDeleteProc, void *userParam);
195
196     /**
197      * Sleep for a number of seconds
198      */
199     static void Sleep(uint64_t seconds);
200
201     /**
202      * Sleep for a number of miliseconds
203      */
204     static void MiliSleep(uint64_t miliseconds);
205
206     /**
207      * Sleep for a number of microseconds
208      */
209     static void MicroSleep(uint64_t microseconds);
210
211     /**
212      * Sleep for a number of nanoseconds
213      */
214     static void NanoSleep(uint64_t nanoseconds);
215 };
216
217 extern bool g_TLSforMainCreated;
218
219 // In case of using TLV in main thread, pthread_exit(NULL) has to be called in
220 // this thread explicitly.
221 // On the other hand, possibly, because of the kernel bug, there exist
222 // a problem, if any other thread than main exist during pthread_exit call
223 // (process can become non-responsive)
224 // TODO further investigation is required.
225 template<typename Type>
226 class ThreadLocalVariable
227     : public Noncopyable
228 {
229 public:
230     typedef Type ValueType;
231
232     class Exception
233     {
234     public:
235         DECLARE_EXCEPTION_TYPE(DPL::Exception, Base)
236         DECLARE_EXCEPTION_TYPE(Base, NullReference)
237         DECLARE_EXCEPTION_TYPE(Base, KeyCreateFailed)
238     };
239
240 private:
241     pthread_key_t m_key;
242
243     struct ManagedValue
244     {
245         ValueType value;
246         Optional<pthread_key_t> guardKey;
247     };
248
249     static void MainThreadExitClean()
250     {
251         // There is a possible bug in kernel. If this function is called
252         // before ALL threads are closed, process will hang!
253         // Because of that, by default this function has to be called in well
254         // known "threads state".
255
256         // pthread_exit(NULL);
257     }
258
259     static void InternalDestroy(void *specific)
260     {
261         // Destroy underlying type
262         ManagedValue *instance = static_cast<ManagedValue *>(specific);
263         if(instance->guardKey.IsNull())
264         {
265             delete instance;
266         }
267         else
268         {
269             int result = pthread_setspecific(*(instance->guardKey), instance);
270
271             Assert(result == 0 &&
272                    "Failed to set thread local variable");
273         }
274     }
275
276     Type &Reference(bool allowInstantiate = false)
277     {
278         ManagedValue *instance =
279             static_cast<ManagedValue *>(pthread_getspecific(m_key));
280
281         if (!instance)
282         {
283             // Check if it is allowed to instantiate
284             if (!allowInstantiate)
285                 Throw(typename Exception::NullReference);
286
287             // checking, if specific data is created for Main thread
288             // If yes, pthread_exit(NULL) is required
289             if (!g_TLSforMainCreated)
290             {
291                 if (Thread::IsMainThread())
292                 {
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         // TODO Should be an assert? is it developers fault to Reset Guarded
371         // value?
372         specific->guardKey = Optional<pthread_key_t>::Null;
373
374         InternalDestroy(specific);
375
376         int result = pthread_setspecific(m_key, NULL);
377
378         Assert(result == 0 &&
379                "Failed to reset thread local variable");
380     }
381
382     // GuardValue(true) allows to defer destroy (by pthread internal
383     // functionality) thread specific value until GuardValue(false) will be
384     // called.
385     void GuardValue(bool guard)
386     {
387         ManagedValue *instance =
388             static_cast<ManagedValue *>(pthread_getspecific(m_key));
389
390         Assert(instance && "Failed to get the value");
391
392         instance->guardKey = guard ? m_key : Optional<pthread_key_t>::Null;
393     }
394 };
395 } // namespace DPL
396
397 #endif // DPL_THREAD_H