Update wrt-commons_0.2.53
[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     };
238
239 private:
240     pthread_key_t m_key;
241
242     struct ManagedValue
243     {
244         ValueType value;
245         Optional<pthread_key_t> guardKey;
246     };
247
248     static void MainThreadExitClean()
249     {
250         // There is a possible bug in kernel. If this function is called
251         // before ALL threads are closed, process will hang!
252         // Because of that, by default this function has to be called in well
253         // known "threads state".
254
255         // pthread_exit(NULL);
256     }
257
258     static void InternalDestroy(void *specific)
259     {
260         // Destroy underlying type
261         ManagedValue *instance = static_cast<ManagedValue *>(specific);
262         if(instance->guardKey.IsNull())
263         {
264             delete instance;
265         }
266         else
267         {
268             int result = pthread_setspecific(*(instance->guardKey), instance);
269
270             Assert(result == 0 &&
271                    "Failed to set thread local variable");
272         }
273     }
274
275     Type &Reference(bool allowInstantiate = false)
276     {
277         ManagedValue *instance =
278             static_cast<ManagedValue *>(pthread_getspecific(m_key));
279
280         if (!instance)
281         {
282             // Check if it is allowed to instantiate
283             if (!allowInstantiate)
284                 Throw(typename Exception::NullReference);
285
286             // checking, if specific data is created for Main thread
287             // If yes, pthread_exit(NULL) is required
288             if (!g_TLSforMainCreated)
289             {
290                 if (Thread::IsMainThread())
291                 {
292                     g_TLSforMainCreated = true;
293                     atexit(&MainThreadExitClean);
294                 }
295             }
296
297             // Need to instantiate underlying type
298             instance = new ManagedValue();
299
300             int result = pthread_setspecific(m_key, instance);
301
302             Assert(result == 0 &&
303                    "Failed to set thread local variable");
304         }
305
306         return instance->value;
307     }
308
309 public:
310     ThreadLocalVariable()
311     {
312         int result = pthread_key_create(&m_key, &InternalDestroy);
313
314         Assert(result == 0 &&
315                "Failed to allocate thread local variable");
316     }
317
318     ~ThreadLocalVariable()
319     {
320         pthread_key_delete(m_key);
321     }
322
323     Type &operator=(const Type &other)
324     {
325         Type &reference = Reference(true);
326         reference = other;
327         return reference;
328     }
329
330     bool IsNull() const
331     {
332         return pthread_getspecific(m_key) == NULL;
333     }
334
335     Type& operator*()
336     {
337         return Reference();
338     }
339
340     const Type& operator*() const
341     {
342         return Reference();
343     }
344
345     const Type* operator->() const
346     {
347         return &Reference();
348     }
349
350     Type* operator->()
351     {
352         return &Reference();
353     }
354
355     bool operator!() const
356     {
357         return IsNull();
358     }
359
360     void Reset()
361     {
362         ManagedValue *specific =
363             static_cast<ManagedValue *>(pthread_getspecific(m_key));
364
365         if (!specific)
366             return;
367
368         // TODO Should be an assert? is it developers fault to Reset Guarded
369         // value?
370         specific->guardKey = Optional<pthread_key_t>::Null;
371
372         InternalDestroy(specific);
373
374         int result = pthread_setspecific(m_key, NULL);
375
376         Assert(result == 0 &&
377                "Failed to reset thread local variable");
378     }
379
380     // GuardValue(true) allows to defer destroy (by pthread internal
381     // functionality) thread specific value until GuardValue(false) will be
382     // called.
383     void GuardValue(bool guard)
384     {
385         ManagedValue *instance =
386             static_cast<ManagedValue *>(pthread_getspecific(m_key));
387
388         Assert(instance && "Failed to get the value");
389
390         instance->guardKey = guard ? m_key : Optional<pthread_key_t>::Null;
391     }
392 };
393 } // namespace DPL
394
395 #endif // DPL_THREAD_H