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/assert.h>
31 #include <boost/optional.hpp>
43 public WaitableHandleWatchSupport
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)
57 typedef void (*EventDeleteProc)(void *event, void *userParam);
58 typedef void (*EventDispatchProc)(void *event, void *userParam);
63 * The method is intended to be overloaded with custom code.
64 * Default implementation just executes Exec method to process
67 virtual int ThreadEntry();
70 * Start processing of thread events
79 EventDispatchProc eventDispatchProc;
80 EventDeleteProc eventDeleteProc;
82 InternalEvent(void *eventArg,
84 EventDispatchProc eventDispatchProcArg,
85 EventDeleteProc eventDeleteProcArg) :
87 userParam(userParamArg),
88 eventDispatchProc(eventDispatchProcArg),
89 eventDeleteProc(eventDeleteProcArg)
93 struct InternalTimedEvent :
96 unsigned long dueTimeMiliseconds;
97 unsigned long registerTimeMiliseconds;
99 InternalTimedEvent(void *eventArg,
101 unsigned long dueTimeMilisecondsArg,
102 unsigned long registerTimeMilisecondsArg,
103 EventDispatchProc eventDispatchProcArg,
104 EventDeleteProc eventDeleteProcArg) :
105 InternalEvent(eventArg,
107 eventDispatchProcArg,
109 dueTimeMiliseconds(dueTimeMilisecondsArg),
110 registerTimeMiliseconds(registerTimeMilisecondsArg)
113 bool operator<(const InternalTimedEvent &other)
115 return registerTimeMiliseconds + dueTimeMiliseconds >
116 other.registerTimeMiliseconds + other.dueTimeMiliseconds;
120 // Internal event list
121 typedef std::list<InternalEvent> InternalEventList;
123 // Internal timed event list
124 typedef std::vector<InternalTimedEvent> InternalTimedEventVector;
127 std::thread m_thread;
128 volatile bool m_abandon;
129 volatile bool m_running;
130 std::mutex m_stateMutex;
131 WaitableEvent m_quitEvent;
134 std::mutex m_eventMutex;
135 InternalEventList m_eventList;
136 WaitableEvent m_eventInvoker;
138 // Timed events processing
139 std::mutex m_timedEventMutex;
140 InternalTimedEventVector m_timedEventVector;
141 WaitableEvent m_timedEventInvoker;
143 // WaitableHandleWatchSupport
144 virtual Thread *GetInvokerThread();
145 virtual void HandleDirectInvoker();
149 unsigned long GetCurrentTimeMiliseconds() const;
150 void ProcessEvents();
151 void ProcessTimedEvents();
153 static void *StaticThreadEntry(void *param);
160 * Run thread. Does nothing if thread is already running
165 * Send quit message to thread and wait for its end
166 * Does nothing is thread is not running
171 * Checks if current thread is main one
172 * Returns true if it is main program thread, false otherwise
174 static bool IsMainThread();
177 * Current thread retrieval
178 * Returns DPL thread handle or NULL if it is main program thread
180 static Thread *GetCurrentThread();
183 * Low-level event push, usually used only by EventSupport
185 void PushEvent(void *event,
186 EventDispatchProc eventDispatchProc,
187 EventDeleteProc eventDeleteProc,
191 * Low-level timed event push, usually used only by EventSupport
193 void PushTimedEvent(void *event,
194 double dueTimeSeconds,
195 EventDispatchProc eventDispatchProc,
196 EventDeleteProc eventDeleteProc,
200 * Sleep for a number of seconds
202 static void Sleep(uint64_t seconds);
205 * Sleep for a number of miliseconds
207 static void MiliSleep(uint64_t miliseconds);
210 * Sleep for a number of microseconds
212 static void MicroSleep(uint64_t microseconds);
215 * Sleep for a number of nanoseconds
217 static void NanoSleep(uint64_t nanoseconds);
220 extern bool g_TLSforMainCreated;
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 :
233 typedef Type ValueType;
238 DECLARE_EXCEPTION_TYPE(DPL::Exception, Base)
239 DECLARE_EXCEPTION_TYPE(Base, NullReference)
240 DECLARE_EXCEPTION_TYPE(Base, KeyCreateFailed)
249 boost::optional<pthread_key_t> guardKey;
252 static void MainThreadExitClean()
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".
259 // pthread_exit(NULL);
262 static void InternalDestroy(void *specific)
264 // Destroy underlying type
265 ManagedValue *instance = static_cast<ManagedValue *>(specific);
266 if (!instance->guardKey) {
269 int result = pthread_setspecific(*(instance->guardKey), instance);
271 Assert(result == 0 &&
272 "Failed to set thread local variable");
276 Type &Reference(bool allowInstantiate = false)
278 ManagedValue *instance =
279 static_cast<ManagedValue *>(pthread_getspecific(m_key));
282 // Check if it is allowed to instantiate
283 if (!allowInstantiate) {
284 Throw(typename Exception::NullReference);
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);
296 // Need to instantiate underlying type
297 instance = new ManagedValue();
299 int result = pthread_setspecific(m_key, instance);
301 Assert(result == 0 &&
302 "Failed to set thread local variable");
305 return instance->value;
309 ThreadLocalVariable()
311 int result = pthread_key_create(&m_key, &InternalDestroy);
313 ThrowMsg(typename Exception::KeyCreateFailed,
314 "Failed to allocate thread local variable: " << result);
318 ~ThreadLocalVariable()
320 pthread_key_delete(m_key);
323 Type &operator=(const Type &other)
325 Type &reference = Reference(true);
332 return pthread_getspecific(m_key) == NULL;
340 const Type& operator*() const
345 const Type* operator->() const
355 bool operator!() const
362 ManagedValue *specific =
363 static_cast<ManagedValue *>(pthread_getspecific(m_key));
369 // TODO Should be an assert? is it developers fault to Reset Guarded
371 specific->guardKey = boost::optional<pthread_key_t>();
373 InternalDestroy(specific);
375 int result = pthread_setspecific(m_key, NULL);
377 Assert(result == 0 &&
378 "Failed to reset thread local variable");
381 // GuardValue(true) allows to defer destroy (by pthread internal
382 // functionality) thread specific value until GuardValue(false) will be
384 void GuardValue(bool guard)
386 ManagedValue *instance =
387 static_cast<ManagedValue *>(pthread_getspecific(m_key));
389 Assert(instance && "Failed to get the value");
391 instance->guardKey = guard ? m_key : boost::optional<pthread_key_t>();
396 #endif // DPL_THREAD_H