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/noncopyable.h>
27 #include <dpl/exception.h>
28 #include <dpl/assert.h>
29 #include <boost/optional.hpp>
41 public WaitableHandleWatchSupport
47 DECLARE_EXCEPTION_TYPE(DPL::Exception, Base)
48 DECLARE_EXCEPTION_TYPE(Base, CreateFailed)
49 DECLARE_EXCEPTION_TYPE(Base, DestroyFailed)
50 DECLARE_EXCEPTION_TYPE(Base, RunFailed)
51 DECLARE_EXCEPTION_TYPE(Base, QuitFailed)
52 DECLARE_EXCEPTION_TYPE(Base, UnmanagedThread)
55 typedef void (*EventDeleteProc)(void *event, void *userParam);
56 typedef void (*EventDispatchProc)(void *event, void *userParam);
61 * The method is intended to be overloaded with custom code.
62 * Default implementation just executes Exec method to process
65 virtual int ThreadEntry();
68 * Start processing of thread events
77 EventDispatchProc eventDispatchProc;
78 EventDeleteProc eventDeleteProc;
80 InternalEvent(void *eventArg,
82 EventDispatchProc eventDispatchProcArg,
83 EventDeleteProc eventDeleteProcArg) :
85 userParam(userParamArg),
86 eventDispatchProc(eventDispatchProcArg),
87 eventDeleteProc(eventDeleteProcArg)
91 struct InternalTimedEvent :
94 unsigned long dueTimeMiliseconds;
95 unsigned long registerTimeMiliseconds;
97 InternalTimedEvent(void *eventArg,
99 unsigned long dueTimeMilisecondsArg,
100 unsigned long registerTimeMilisecondsArg,
101 EventDispatchProc eventDispatchProcArg,
102 EventDeleteProc eventDeleteProcArg) :
103 InternalEvent(eventArg,
105 eventDispatchProcArg,
107 dueTimeMiliseconds(dueTimeMilisecondsArg),
108 registerTimeMiliseconds(registerTimeMilisecondsArg)
111 bool operator<(const InternalTimedEvent &other)
113 return registerTimeMiliseconds + dueTimeMiliseconds >
114 other.registerTimeMiliseconds + other.dueTimeMiliseconds;
118 // Internal event list
119 typedef std::list<InternalEvent> InternalEventList;
121 // Internal timed event list
122 typedef std::vector<InternalTimedEvent> InternalTimedEventVector;
125 std::thread m_thread;
126 volatile bool m_abandon;
127 volatile bool m_running;
128 std::mutex m_stateMutex;
129 WaitableEvent m_quitEvent;
132 std::mutex m_eventMutex;
133 InternalEventList m_eventList;
134 WaitableEvent m_eventInvoker;
136 // Timed events processing
137 std::mutex m_timedEventMutex;
138 InternalTimedEventVector m_timedEventVector;
139 WaitableEvent m_timedEventInvoker;
141 // WaitableHandleWatchSupport
142 virtual Thread *GetInvokerThread();
143 virtual void HandleDirectInvoker();
147 unsigned long GetCurrentTimeMiliseconds() const;
148 void ProcessEvents();
149 void ProcessTimedEvents();
151 static void *StaticThreadEntry(void *param);
158 * Run thread. Does nothing if thread is already running
163 * Send quit message to thread and wait for its end
164 * Does nothing is thread is not running
169 * Checks if current thread is main one
170 * Returns true if it is main program thread, false otherwise
172 static bool IsMainThread();
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,
184 EventDispatchProc eventDispatchProc,
185 EventDeleteProc eventDeleteProc,
189 * Low-level timed event push, usually used only by EventSupport
191 void PushTimedEvent(void *event,
192 double dueTimeSeconds,
193 EventDispatchProc eventDispatchProc,
194 EventDeleteProc eventDeleteProc,
198 * Sleep for a number of seconds
200 static void Sleep(uint64_t seconds);
203 * Sleep for a number of miliseconds
205 static void MiliSleep(uint64_t miliseconds);
208 * Sleep for a number of microseconds
210 static void MicroSleep(uint64_t microseconds);
213 * Sleep for a number of nanoseconds
215 static void NanoSleep(uint64_t nanoseconds);
218 extern bool g_TLSforMainCreated;
220 // In case of using TLV in main thread, pthread_exit(NULL) has to be called in
221 // this thread explicitly.
222 // On the other hand, possibly, because of the kernel bug, there exist
223 // a problem, if any other thread than main exist during pthread_exit call
224 // (process can become non-responsive)
225 // TODO further investigation is required.
226 template<typename Type>
227 class ThreadLocalVariable :
231 typedef Type ValueType;
236 DECLARE_EXCEPTION_TYPE(DPL::Exception, Base)
237 DECLARE_EXCEPTION_TYPE(Base, NullReference)
238 DECLARE_EXCEPTION_TYPE(Base, KeyCreateFailed)
247 boost::optional<pthread_key_t> guardKey;
250 static void MainThreadExitClean()
252 // There is a possible bug in kernel. If this function is called
253 // before ALL threads are closed, process will hang!
254 // Because of that, by default this function has to be called in well
255 // known "threads state".
257 // pthread_exit(NULL);
260 static void InternalDestroy(void *specific)
262 // Destroy underlying type
263 ManagedValue *instance = static_cast<ManagedValue *>(specific);
264 if (!instance->guardKey) {
267 int result = pthread_setspecific(*(instance->guardKey), instance);
269 Assert(result == 0 &&
270 "Failed to set thread local variable");
274 Type &Reference(bool allowInstantiate = false)
276 ManagedValue *instance =
277 static_cast<ManagedValue *>(pthread_getspecific(m_key));
280 // Check if it is allowed to instantiate
281 if (!allowInstantiate) {
282 Throw(typename Exception::NullReference);
285 // checking, if specific data is created for Main thread
286 // If yes, pthread_exit(NULL) is required
287 if (!g_TLSforMainCreated) {
288 if (Thread::IsMainThread()) {
289 g_TLSforMainCreated = true;
290 atexit(&MainThreadExitClean);
294 // Need to instantiate underlying type
295 instance = new ManagedValue();
297 int result = pthread_setspecific(m_key, instance);
299 Assert(result == 0 &&
300 "Failed to set thread local variable");
303 return instance->value;
307 ThreadLocalVariable()
309 int result = pthread_key_create(&m_key, &InternalDestroy);
311 ThrowMsg(typename Exception::KeyCreateFailed,
312 "Failed to allocate thread local variable: " << result);
316 ~ThreadLocalVariable()
318 pthread_key_delete(m_key);
321 Type &operator=(const Type &other)
323 Type &reference = Reference(true);
330 return pthread_getspecific(m_key) == NULL;
338 const Type& operator*() const
343 const Type* operator->() const
353 bool operator!() const
360 ManagedValue *specific =
361 static_cast<ManagedValue *>(pthread_getspecific(m_key));
367 // TODO Should be an assert? is it developers fault to Reset Guarded
369 specific->guardKey = boost::optional<pthread_key_t>();
371 InternalDestroy(specific);
373 int result = pthread_setspecific(m_key, NULL);
375 Assert(result == 0 &&
376 "Failed to reset thread local variable");
379 // GuardValue(true) allows to defer destroy (by pthread internal
380 // functionality) thread specific value until GuardValue(false) will be
382 void GuardValue(bool guard)
384 ManagedValue *instance =
385 static_cast<ManagedValue *>(pthread_getspecific(m_key));
387 Assert(instance && "Failed to get the value");
389 instance->guardKey = guard ? m_key : boost::optional<pthread_key_t>();
394 #endif // DPL_THREAD_H