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