2 * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
18 * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com)
20 * @brief This file is the implementation file of thread
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>
45 : private Noncopyable,
46 public WaitableHandleWatchSupport
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)
60 typedef void (*EventDeleteProc)(void *event, void *userParam);
61 typedef void (*EventDispatchProc)(void *event, void *userParam);
66 * The method is intended to be overloaded with custom code.
67 * Default implementation just executes Exec method to process
70 virtual int ThreadEntry();
73 * Start processing of thread events
82 EventDispatchProc eventDispatchProc;
83 EventDeleteProc eventDeleteProc;
85 InternalEvent(void *eventArg,
87 EventDispatchProc eventDispatchProcArg,
88 EventDeleteProc eventDeleteProcArg)
90 userParam(userParamArg),
91 eventDispatchProc(eventDispatchProcArg),
92 eventDeleteProc(eventDeleteProcArg)
97 struct InternalTimedEvent
100 unsigned long dueTimeMiliseconds;
101 unsigned long registerTimeMiliseconds;
103 InternalTimedEvent(void *eventArg,
105 unsigned long dueTimeMilisecondsArg,
106 unsigned long registerTimeMilisecondsArg,
107 EventDispatchProc eventDispatchProcArg,
108 EventDeleteProc eventDeleteProcArg)
109 : InternalEvent(eventArg,
111 eventDispatchProcArg,
113 dueTimeMiliseconds(dueTimeMilisecondsArg),
114 registerTimeMiliseconds(registerTimeMilisecondsArg)
118 bool operator<(const InternalTimedEvent &other)
120 return registerTimeMiliseconds + dueTimeMiliseconds > other.registerTimeMiliseconds + other.dueTimeMiliseconds;
124 // Internal event list
125 typedef std::list<InternalEvent> InternalEventList;
127 // Internal timed event list
128 typedef std::vector<InternalTimedEvent> InternalTimedEventVector;
132 volatile bool m_abandon;
133 volatile bool m_running;
135 WaitableEvent m_quitEvent;
139 InternalEventList m_eventList;
140 WaitableEvent m_eventInvoker;
142 // Timed events processing
143 Mutex m_timedEventMutex;
144 InternalTimedEventVector m_timedEventVector;
145 WaitableEvent m_timedEventInvoker;
147 // WaitableHandleWatchSupport
148 virtual Thread *GetInvokerThread();
149 virtual void HandleDirectInvoker();
153 unsigned long GetCurrentTimeMiliseconds() const;
154 void ProcessEvents();
155 void ProcessTimedEvents();
157 static void *StaticThreadEntry(void *param);
164 * Run thread. Does nothing if thread is already running
169 * Send quit message to thread and wait for its end
170 * Does nothing is thread is not running
175 * Current thread retrieval
176 * Returns DPL thread handle or NULL if it is main program thread
178 static Thread *GetCurrentThread();
181 * Low-level event push, usually used only by EventSupport
183 void PushEvent(void *event, EventDispatchProc eventDispatchProc, EventDeleteProc eventDeleteProc, void *userParam);
186 * Low-level timed event push, usually used only by EventSupport
188 void PushTimedEvent(void *event, double dueTimeSeconds, EventDispatchProc eventDispatchProc, EventDeleteProc eventDeleteProc, void *userParam);
191 * Sleep for a number of seconds
193 static void Sleep(uint64_t seconds);
196 * Sleep for a number of miliseconds
198 static void MiliSleep(uint64_t miliseconds);
201 * Sleep for a number of microseconds
203 static void MicroSleep(uint64_t microseconds);
206 * Sleep for a number of nanoseconds
208 static void NanoSleep(uint64_t nanoseconds);
211 extern bool g_TLSforMainCreated;
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
224 typedef Type ValueType;
229 DECLARE_EXCEPTION_TYPE(DPL::Exception, Base)
230 DECLARE_EXCEPTION_TYPE(Base, NullReference)
239 Optional<pthread_key_t> guardKey;
242 static void MainThreadExitClean()
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".
249 // pthread_exit(NULL);
252 static void InternalDestroy(void *specific)
254 // Destroy underlying type
255 ManagedValue *instance = static_cast<ManagedValue *>(specific);
256 if(instance->guardKey.IsNull())
262 int result = pthread_setspecific(*(instance->guardKey), instance);
264 Assert(result == 0 &&
265 "Failed to set thread local variable");
269 Type &Reference(bool allowInstantiate = false)
271 ManagedValue *instance =
272 static_cast<ManagedValue *>(pthread_getspecific(m_key));
276 // Check if it is allowed to instantiate
277 if (!allowInstantiate)
278 Throw(typename Exception::NullReference);
280 // checking, if specific data is created for Main thread
281 // If yes, pthread_exit(NULL) is required
282 if (!g_TLSforMainCreated)
284 if (Thread::GetCurrentThread() == NULL)
286 g_TLSforMainCreated = true;
287 atexit(&MainThreadExitClean);
291 // Need to instantiate underlying type
292 instance = new ManagedValue();
294 int result = pthread_setspecific(m_key, instance);
296 Assert(result == 0 &&
297 "Failed to set thread local variable");
300 return instance->value;
304 ThreadLocalVariable()
306 int result = pthread_key_create(&m_key, &InternalDestroy);
308 Assert(result == 0 &&
309 "Failed to allocate thread local variable");
312 ~ThreadLocalVariable()
314 pthread_key_delete(m_key);
317 Type &operator=(const Type &other)
319 Type &reference = Reference(true);
326 return pthread_getspecific(m_key) == NULL;
334 const Type& operator*() const
339 const Type* operator->() const
349 bool operator!() const
356 ManagedValue *specific =
357 static_cast<ManagedValue *>(pthread_getspecific(m_key));
362 // TODO Should be an assert? is it developers fault to Reset Guarded
364 specific->guardKey = Optional<pthread_key_t>::Null;
366 InternalDestroy(specific);
368 int result = pthread_setspecific(m_key, NULL);
370 Assert(result == 0 &&
371 "Failed to reset thread local variable");
374 // GuardValue(true) allows to defer destroy (by pthread internal
375 // functionality) thread specific value until GuardValue(false) will be
377 void GuardValue(bool guard)
379 ManagedValue *instance =
380 static_cast<ManagedValue *>(pthread_getspecific(m_key));
382 Assert(instance && "Failed to get the value");
384 instance->guardKey = guard ? m_key : Optional<pthread_key_t>::Null;
389 #endif // DPL_THREAD_H