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 * Checks if current thread is main one
176 * Returns true if it is main program thread, false otherwise
178 static bool IsMainThread();
181 * Current thread retrieval
182 * Returns DPL thread handle or NULL if it is main program thread
184 static Thread *GetCurrentThread();
187 * Low-level event push, usually used only by EventSupport
189 void PushEvent(void *event, EventDispatchProc eventDispatchProc, EventDeleteProc eventDeleteProc, void *userParam);
192 * Low-level timed event push, usually used only by EventSupport
194 void PushTimedEvent(void *event, double dueTimeSeconds, EventDispatchProc eventDispatchProc, EventDeleteProc eventDeleteProc, void *userParam);
197 * Sleep for a number of seconds
199 static void Sleep(uint64_t seconds);
202 * Sleep for a number of miliseconds
204 static void MiliSleep(uint64_t miliseconds);
207 * Sleep for a number of microseconds
209 static void MicroSleep(uint64_t microseconds);
212 * Sleep for a number of nanoseconds
214 static void NanoSleep(uint64_t nanoseconds);
217 extern bool g_TLSforMainCreated;
219 // In case of using TLV in main thread, pthread_exit(NULL) has to be called in
220 // this thread explicitly.
221 // On the other hand, possibly, because of the kernel bug, there exist
222 // a problem, if any other thread than main exist during pthread_exit call
223 // (process can become non-responsive)
224 // TODO further investigation is required.
225 template<typename Type>
226 class ThreadLocalVariable
230 typedef Type ValueType;
235 DECLARE_EXCEPTION_TYPE(DPL::Exception, Base)
236 DECLARE_EXCEPTION_TYPE(Base, NullReference)
245 Optional<pthread_key_t> guardKey;
248 static void MainThreadExitClean()
250 // There is a possible bug in kernel. If this function is called
251 // before ALL threads are closed, process will hang!
252 // Because of that, by default this function has to be called in well
253 // known "threads state".
255 // pthread_exit(NULL);
258 static void InternalDestroy(void *specific)
260 // Destroy underlying type
261 ManagedValue *instance = static_cast<ManagedValue *>(specific);
262 if(instance->guardKey.IsNull())
268 int result = pthread_setspecific(*(instance->guardKey), instance);
270 Assert(result == 0 &&
271 "Failed to set thread local variable");
275 Type &Reference(bool allowInstantiate = false)
277 ManagedValue *instance =
278 static_cast<ManagedValue *>(pthread_getspecific(m_key));
282 // Check if it is allowed to instantiate
283 if (!allowInstantiate)
284 Throw(typename Exception::NullReference);
286 // checking, if specific data is created for Main thread
287 // If yes, pthread_exit(NULL) is required
288 if (!g_TLSforMainCreated)
290 if (Thread::IsMainThread())
292 g_TLSforMainCreated = true;
293 atexit(&MainThreadExitClean);
297 // Need to instantiate underlying type
298 instance = new ManagedValue();
300 int result = pthread_setspecific(m_key, instance);
302 Assert(result == 0 &&
303 "Failed to set thread local variable");
306 return instance->value;
310 ThreadLocalVariable()
312 int result = pthread_key_create(&m_key, &InternalDestroy);
314 Assert(result == 0 &&
315 "Failed to allocate thread local variable");
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));
368 // TODO Should be an assert? is it developers fault to Reset Guarded
370 specific->guardKey = Optional<pthread_key_t>::Null;
372 InternalDestroy(specific);
374 int result = pthread_setspecific(m_key, NULL);
376 Assert(result == 0 &&
377 "Failed to reset thread local variable");
380 // GuardValue(true) allows to defer destroy (by pthread internal
381 // functionality) thread specific value until GuardValue(false) will be
383 void GuardValue(bool guard)
385 ManagedValue *instance =
386 static_cast<ManagedValue *>(pthread_getspecific(m_key));
388 Assert(instance && "Failed to get the value");
390 instance->guardKey = guard ? m_key : Optional<pthread_key_t>::Null;
395 #endif // DPL_THREAD_H