tizen beta 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      * Current thread retrieval
176      * Returns DPL thread handle or NULL if it is main program thread
177      */
178     static Thread *GetCurrentThread();
179
180     /**
181      * Low-level event push, usually used only by EventSupport
182      */
183     void PushEvent(void *event, EventDispatchProc eventDispatchProc, EventDeleteProc eventDeleteProc, void *userParam);
184
185     /**
186      * Low-level timed event push, usually used only by EventSupport
187      */
188     void PushTimedEvent(void *event, double dueTimeSeconds, EventDispatchProc eventDispatchProc, EventDeleteProc eventDeleteProc, void *userParam);
189
190     /**
191      * Sleep for a number of seconds
192      */
193     static void Sleep(uint64_t seconds);
194
195     /**
196      * Sleep for a number of miliseconds
197      */
198     static void MiliSleep(uint64_t miliseconds);
199
200     /**
201      * Sleep for a number of microseconds
202      */
203     static void MicroSleep(uint64_t microseconds);
204
205     /**
206      * Sleep for a number of nanoseconds
207      */
208     static void NanoSleep(uint64_t nanoseconds);
209 };
210
211 extern bool g_TLSforMainCreated;
212
213 // In case of using TLV in main thread, pthread_exit(NULL) has to be called in
214 // this thread explicitly.
215 // On the other hand, possibly, because of the kernel bug, there exist
216 // a problem, if any other thread than main exist during pthread_exit call
217 // (process can become non-responsive)
218 // TODO further investigation is required.
219 template<typename Type>
220 class ThreadLocalVariable
221     : public Noncopyable
222 {
223 public:
224     typedef Type ValueType;
225
226     class Exception
227     {
228     public:
229         DECLARE_EXCEPTION_TYPE(DPL::Exception, Base)
230         DECLARE_EXCEPTION_TYPE(Base, NullReference)
231     };
232
233 private:
234     pthread_key_t m_key;
235
236     struct ManagedValue
237     {
238         ValueType value;
239         Optional<pthread_key_t> guardKey;
240     };
241
242     static void MainThreadExitClean()
243     {
244         // There is a possible bug in kernel. If this function is called
245         // before ALL threads are closed, process will hang!
246         // Because of that, by default this function has to be called in well
247         // known "threads state".
248
249         // pthread_exit(NULL);
250     }
251
252     static void InternalDestroy(void *specific)
253     {
254         // Destroy underlying type
255         ManagedValue *instance = static_cast<ManagedValue *>(specific);
256         if(instance->guardKey.IsNull())
257         {
258             delete instance;
259         }
260         else
261         {
262             int result = pthread_setspecific(*(instance->guardKey), instance);
263
264             Assert(result == 0 &&
265                    "Failed to set thread local variable");
266         }
267     }
268
269     Type &Reference(bool allowInstantiate = false)
270     {
271         ManagedValue *instance =
272             static_cast<ManagedValue *>(pthread_getspecific(m_key));
273
274         if (!instance)
275         {
276             // Check if it is allowed to instantiate
277             if (!allowInstantiate)
278                 Throw(typename Exception::NullReference);
279
280             // checking, if specific data is created for Main thread
281             // If yes, pthread_exit(NULL) is required
282             if (!g_TLSforMainCreated)
283             {
284                 if (Thread::GetCurrentThread() == NULL)
285                 {
286                     g_TLSforMainCreated = true;
287                     atexit(&MainThreadExitClean);
288                 }
289             }
290
291             // Need to instantiate underlying type
292             instance = new ManagedValue();
293
294             int result = pthread_setspecific(m_key, instance);
295
296             Assert(result == 0 &&
297                    "Failed to set thread local variable");
298         }
299
300         return instance->value;
301     }
302
303 public:
304     ThreadLocalVariable()
305     {
306         int result = pthread_key_create(&m_key, &InternalDestroy);
307
308         Assert(result == 0 &&
309                "Failed to allocate thread local variable");
310     }
311
312     ~ThreadLocalVariable()
313     {
314         pthread_key_delete(m_key);
315     }
316
317     Type &operator=(const Type &other)
318     {
319         Type &reference = Reference(true);
320         reference = other;
321         return reference;
322     }
323
324     bool IsNull() const
325     {
326         return pthread_getspecific(m_key) == NULL;
327     }
328
329     Type& operator*()
330     {
331         return Reference();
332     }
333
334     const Type& operator*() const
335     {
336         return Reference();
337     }
338
339     const Type* operator->() const
340     {
341         return &Reference();
342     }
343
344     Type* operator->()
345     {
346         return &Reference();
347     }
348
349     bool operator!() const
350     {
351         return IsNull();
352     }
353
354     void Reset()
355     {
356         ManagedValue *specific =
357             static_cast<ManagedValue *>(pthread_getspecific(m_key));
358
359         if (!specific)
360             return;
361
362         // TODO Should be an assert? is it developers fault to Reset Guarded
363         // value?
364         specific->guardKey = Optional<pthread_key_t>::Null;
365
366         InternalDestroy(specific);
367
368         int result = pthread_setspecific(m_key, NULL);
369
370         Assert(result == 0 &&
371                "Failed to reset thread local variable");
372     }
373
374     // GuardValue(true) allows to defer destroy (by pthread internal
375     // functionality) thread specific value until GuardValue(false) will be
376     // called.
377     void GuardValue(bool guard)
378     {
379         ManagedValue *instance =
380             static_cast<ManagedValue *>(pthread_getspecific(m_key));
381
382         Assert(instance && "Failed to get the value");
383
384         instance->guardKey = guard ? m_key : Optional<pthread_key_t>::Null;
385     }
386 };
387 } // namespace DPL
388
389 #endif // DPL_THREAD_H