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 public WaitableHandleWatchSupport
51 DECLARE_EXCEPTION_TYPE(DPL::Exception, Base)
52 DECLARE_EXCEPTION_TYPE(Base, CreateFailed)
53 DECLARE_EXCEPTION_TYPE(Base, DestroyFailed)
54 DECLARE_EXCEPTION_TYPE(Base, RunFailed)
55 DECLARE_EXCEPTION_TYPE(Base, QuitFailed)
56 DECLARE_EXCEPTION_TYPE(Base, UnmanagedThread)
59 typedef void (*EventDeleteProc)(void *event, void *userParam);
60 typedef void (*EventDispatchProc)(void *event, void *userParam);
65 * The method is intended to be overloaded with custom code.
66 * Default implementation just executes Exec method to process
69 virtual int ThreadEntry();
72 * Start processing of thread events
81 EventDispatchProc eventDispatchProc;
82 EventDeleteProc eventDeleteProc;
84 InternalEvent(void *eventArg,
86 EventDispatchProc eventDispatchProcArg,
87 EventDeleteProc eventDeleteProcArg) :
89 userParam(userParamArg),
90 eventDispatchProc(eventDispatchProcArg),
91 eventDeleteProc(eventDeleteProcArg)
95 struct InternalTimedEvent :
98 unsigned long dueTimeMiliseconds;
99 unsigned long registerTimeMiliseconds;
101 InternalTimedEvent(void *eventArg,
103 unsigned long dueTimeMilisecondsArg,
104 unsigned long registerTimeMilisecondsArg,
105 EventDispatchProc eventDispatchProcArg,
106 EventDeleteProc eventDeleteProcArg) :
107 InternalEvent(eventArg,
109 eventDispatchProcArg,
111 dueTimeMiliseconds(dueTimeMilisecondsArg),
112 registerTimeMiliseconds(registerTimeMilisecondsArg)
115 bool operator<(const InternalTimedEvent &other)
117 return registerTimeMiliseconds + dueTimeMiliseconds >
118 other.registerTimeMiliseconds + other.dueTimeMiliseconds;
122 // Internal event list
123 typedef std::list<InternalEvent> InternalEventList;
125 // Internal timed event list
126 typedef std::vector<InternalTimedEvent> InternalTimedEventVector;
130 volatile bool m_abandon;
131 volatile bool m_running;
133 WaitableEvent m_quitEvent;
137 InternalEventList m_eventList;
138 WaitableEvent m_eventInvoker;
140 // Timed events processing
141 Mutex m_timedEventMutex;
142 InternalTimedEventVector m_timedEventVector;
143 WaitableEvent m_timedEventInvoker;
145 // WaitableHandleWatchSupport
146 virtual Thread *GetInvokerThread();
147 virtual void HandleDirectInvoker();
151 unsigned long GetCurrentTimeMiliseconds() const;
152 void ProcessEvents();
153 void ProcessTimedEvents();
155 static void *StaticThreadEntry(void *param);
162 * Run thread. Does nothing if thread is already running
167 * Send quit message to thread and wait for its end
168 * Does nothing is thread is not running
173 * Checks if current thread is main one
174 * Returns true if it is main program thread, false otherwise
176 static bool IsMainThread();
179 * Current thread retrieval
180 * Returns DPL thread handle or NULL if it is main program thread
182 static Thread *GetCurrentThread();
185 * Low-level event push, usually used only by EventSupport
187 void PushEvent(void *event,
188 EventDispatchProc eventDispatchProc,
189 EventDeleteProc eventDeleteProc,
193 * Low-level timed event push, usually used only by EventSupport
195 void PushTimedEvent(void *event,
196 double dueTimeSeconds,
197 EventDispatchProc eventDispatchProc,
198 EventDeleteProc eventDeleteProc,
202 * Sleep for a number of seconds
204 static void Sleep(uint64_t seconds);
207 * Sleep for a number of miliseconds
209 static void MiliSleep(uint64_t miliseconds);
212 * Sleep for a number of microseconds
214 static void MicroSleep(uint64_t microseconds);
217 * Sleep for a number of nanoseconds
219 static void NanoSleep(uint64_t nanoseconds);
222 extern bool g_TLSforMainCreated;
224 // In case of using TLV in main thread, pthread_exit(NULL) has to be called in
225 // this thread explicitly.
226 // On the other hand, possibly, because of the kernel bug, there exist
227 // a problem, if any other thread than main exist during pthread_exit call
228 // (process can become non-responsive)
229 // TODO further investigation is required.
230 template<typename Type>
231 class ThreadLocalVariable :
235 typedef Type ValueType;
240 DECLARE_EXCEPTION_TYPE(DPL::Exception, Base)
241 DECLARE_EXCEPTION_TYPE(Base, NullReference)
242 DECLARE_EXCEPTION_TYPE(Base, KeyCreateFailed)
251 Optional<pthread_key_t> guardKey;
254 static void MainThreadExitClean()
256 // There is a possible bug in kernel. If this function is called
257 // before ALL threads are closed, process will hang!
258 // Because of that, by default this function has to be called in well
259 // known "threads state".
261 // pthread_exit(NULL);
264 static void InternalDestroy(void *specific)
266 // Destroy underlying type
267 ManagedValue *instance = static_cast<ManagedValue *>(specific);
268 if (instance->guardKey.IsNull()) {
271 int result = pthread_setspecific(*(instance->guardKey), instance);
273 Assert(result == 0 &&
274 "Failed to set thread local variable");
278 Type &Reference(bool allowInstantiate = false)
280 ManagedValue *instance =
281 static_cast<ManagedValue *>(pthread_getspecific(m_key));
284 // Check if it is allowed to instantiate
285 if (!allowInstantiate) {
286 Throw(typename Exception::NullReference);
289 // checking, if specific data is created for Main thread
290 // If yes, pthread_exit(NULL) is required
291 if (!g_TLSforMainCreated) {
292 if (Thread::IsMainThread()) {
293 g_TLSforMainCreated = true;
294 atexit(&MainThreadExitClean);
298 // Need to instantiate underlying type
299 instance = new ManagedValue();
301 int result = pthread_setspecific(m_key, instance);
303 Assert(result == 0 &&
304 "Failed to set thread local variable");
307 return instance->value;
311 ThreadLocalVariable()
313 int result = pthread_key_create(&m_key, &InternalDestroy);
315 ThrowMsg(typename Exception::KeyCreateFailed,
316 "Failed to allocate thread local variable: " << result);
320 ~ThreadLocalVariable()
322 pthread_key_delete(m_key);
325 Type &operator=(const Type &other)
327 Type &reference = Reference(true);
334 return pthread_getspecific(m_key) == NULL;
342 const Type& operator*() const
347 const Type* operator->() const
357 bool operator!() const
364 ManagedValue *specific =
365 static_cast<ManagedValue *>(pthread_getspecific(m_key));
371 // TODO Should be an assert? is it developers fault to Reset Guarded
373 specific->guardKey = Optional<pthread_key_t>::Null;
375 InternalDestroy(specific);
377 int result = pthread_setspecific(m_key, NULL);
379 Assert(result == 0 &&
380 "Failed to reset thread local variable");
383 // GuardValue(true) allows to defer destroy (by pthread internal
384 // functionality) thread specific value until GuardValue(false) will be
386 void GuardValue(bool guard)
388 ManagedValue *instance =
389 static_cast<ManagedValue *>(pthread_getspecific(m_key));
391 Assert(instance && "Failed to get the value");
393 instance->guardKey = guard ? m_key : Optional<pthread_key_t>::Null;
398 #endif // DPL_THREAD_H