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
23 #include <dpl/thread.h>
24 #include <dpl/log/wrt_log.h>
27 #include <dpl/assert.h>
32 namespace // anonymous
34 static const size_t NANOSECONDS_PER_SECOND =
35 static_cast<uint64_t>(1000 * 1000 * 1000);
37 static const size_t NANOSECONDS_PER_MILISECOND =
38 static_cast<uint64_t>(1000 * 1000);
40 static const size_t NANOSECONDS_PER_MICROSECOND =
41 static_cast<uint64_t>(1000);
43 static const std::thread::id g_mainThread = std::this_thread::get_id();
48 pthread_key_t threadSpecific;
54 pthread_key_create(&threadSpecific, NULL);
57 virtual ~ThreadSpecific()
59 pthread_key_delete(threadSpecific);
63 static ThreadSpecific g_threadSpecific;
64 } // namespace anonymous
67 bool g_TLSforMainCreated = false;
78 // Ensure that we quit thread
79 // Always wait thread by yourself; if thread is still running
80 // this may be sometimes very bad. When derived, some resources
81 // may leak or be doubly freed
84 // Remove any remainig events
85 // Thread proc is surely not running now
86 for (InternalEventList::iterator iterator = m_eventList.begin();
87 iterator != m_eventList.end();
90 iterator->eventDeleteProc(iterator->event, iterator->userParam);
96 bool Thread::IsMainThread()
98 return (std::this_thread::get_id() == g_mainThread);
101 Thread *Thread::GetCurrentThread()
103 if (std::this_thread::get_id() == g_mainThread) {
107 void *threadSpecific = pthread_getspecific(g_threadSpecific.threadSpecific);
109 // Is this a managed thread ?
110 if (threadSpecific == NULL) {
111 Throw(Exception::UnmanagedThread);
114 return static_cast<Thread *>(threadSpecific);
117 void *Thread::StaticThreadEntry(void *param)
120 char errbuf[512] = {0,};
121 WrtLogD("Entered static thread entry");
124 Thread *This = static_cast<Thread *>(param);
125 Assert(This != NULL);
127 // Set thread specific
128 int result = pthread_setspecific(g_threadSpecific.threadSpecific, This);
132 errstr = strerror_r(result, errbuf, sizeof(errbuf));
134 strerror_r(result, errbuf, sizeof(errbuf));
137 WrtLogE("Failed to set threadSpecific. Error: %s", errstr);
141 // Do not allow exceptions to hit pthread core
142 UNHANDLED_EXCEPTION_HANDLER_BEGIN
146 UNHANDLED_EXCEPTION_HANDLER_END
150 // Leave running state
151 std::lock_guard<std::mutex> lock(This->m_stateMutex);
153 This->m_running = false;
156 if (This->m_abandon) {
157 WrtLogD("Thread was abandoned");
158 This->m_thread.detach();
160 WrtLogD("Thread is joinable");
167 int Thread::ThreadEntry()
169 WrtLogD("Entered default thread entry");
173 void Thread::ProcessEvents()
175 WrtLogD("Processing events");
177 // Steal current event list
178 InternalEventList stolenEvents;
180 // Enter event list critical section
182 std::lock_guard<std::mutex> lock(m_eventMutex);
183 m_eventList.swap(stolenEvents);
184 m_eventInvoker.Reset();
187 // Process event list
188 WrtLogD("Stolen %u internal events", stolenEvents.size());
190 for (InternalEventList::iterator iterator = stolenEvents.begin();
191 iterator != stolenEvents.end();
194 // Dispatch immediate event
195 iterator->eventDispatchProc(iterator->event, iterator->userParam);
198 iterator->eventDeleteProc(iterator->event, iterator->userParam);
202 void Thread::ProcessTimedEvents()
204 // Critical section on timed events mutex
206 std::lock_guard<std::mutex> lock(m_timedEventMutex);
209 unsigned long currentTimeMiliseconds = GetCurrentTimeMiliseconds();
212 WrtLogD("Processing timed events. Time now: %lu ms", currentTimeMiliseconds);
214 // All timed events are sorted chronologically
215 // Emit timed out events
216 while (!m_timedEventVector.empty() &&
217 currentTimeMiliseconds >=
218 m_timedEventVector.begin()->registerTimeMiliseconds +
219 m_timedEventVector.begin()->dueTimeMiliseconds)
222 WrtLogD("Transforming timed event into immediate event. Absolute due time: %lu ms",
223 (m_timedEventVector.begin()->registerTimeMiliseconds +
224 m_timedEventVector.begin()->dueTimeMiliseconds));
226 // Emit immediate event
227 PushEvent(m_timedEventVector.begin()->event,
228 m_timedEventVector.begin()->eventDispatchProc,
229 m_timedEventVector.begin()->eventDeleteProc,
230 m_timedEventVector.begin()->userParam);
232 // Remove timed eventand fix heap
233 std::pop_heap(m_timedEventVector.begin(), m_timedEventVector.end());
234 m_timedEventVector.pop_back();
239 unsigned long Thread::GetCurrentTimeMiliseconds() const
242 gettimeofday(&tv, NULL);
243 return static_cast<unsigned long>(tv.tv_sec) * 1000 +
244 static_cast<unsigned long>(tv.tv_usec) / 1000;
249 WrtLogD("Executing thread event processing");
251 const std::size_t MIN_HANDLE_LIST_SIZE = 4;
253 // Start processing of events
254 WaitableHandleListEx handleList;
256 // index 0: Quit waitable event handle
257 handleList.push_back(std::make_pair(m_quitEvent.GetHandle(), WaitMode::Read));
259 // index 1: Event occurred event handle
260 handleList.push_back(std::make_pair(m_eventInvoker.GetHandle(),
263 // index 2: Timed event occurred event handle
264 handleList.push_back(std::make_pair(m_timedEventInvoker.GetHandle(),
267 // index 3: Waitable handle watch support invoker
268 handleList.push_back(std::make_pair(WaitableHandleWatchSupport::
269 WaitableInvokerHandle(),
273 // Watch list might have been initialized before threaded started
274 // Need to fill waitable event watch list in this case
277 WaitableHandleListEx waitableHandleWatchHandles =
278 WaitableHandleWatchSupport::WaitableWatcherHandles();
280 waitableHandleWatchHandles.begin(),
281 waitableHandleWatchHandles.end(), std::back_inserter(handleList));
288 // Retrieve minimum wait time, according to timed events list
289 unsigned long minimumWaitTime;
291 // Critical section on timed events mutex
293 std::lock_guard<std::mutex> lock(m_timedEventMutex);
295 if (!m_timedEventVector.empty()) {
296 unsigned long currentTimeMiliseconds =
297 GetCurrentTimeMiliseconds();
298 unsigned long destinationTimeMiliseconds =
299 m_timedEventVector.begin()->registerTimeMiliseconds +
300 m_timedEventVector.begin()->dueTimeMiliseconds;
302 // Are we already late with timed event ?
303 if (currentTimeMiliseconds > destinationTimeMiliseconds) {
306 minimumWaitTime = destinationTimeMiliseconds -
307 currentTimeMiliseconds;
310 minimumWaitTime = 0xFFFFFFFF; // Infinity
315 WrtLogD("Thread loop minimum wait time: %lu ms", minimumWaitTime);
318 WaitableHandleIndexList waitableHandleIndexList =
319 WaitForMultipleHandles(handleList, minimumWaitTime);
321 if (waitableHandleIndexList.empty()) {
322 // Timeout occurred. Process timed events.
323 WrtLogD("Timed event list elapsed invoker");
324 ProcessTimedEvents();
328 // Go through each index
329 for (WaitableHandleIndexList::const_iterator
330 waitableHandleIndexIterator = waitableHandleIndexList.begin();
331 waitableHandleIndexIterator != waitableHandleIndexList.end();
332 ++waitableHandleIndexIterator)
334 size_t index = *waitableHandleIndexIterator;
336 WrtLogD("Event loop triggered with index: %u", index);
340 // Quit waitable event handle
345 // Event occurred event handle
348 // Handle direct invoker
349 if (m_directInvoke) {
350 m_directInvoke = false;
352 WrtLogD("Handling direct invoker");
355 while (handleList.size() > MIN_HANDLE_LIST_SIZE) {
356 handleList.pop_back();
359 // Insert current waitable event handles instead
361 WaitableHandleListEx waitableHandleWatchHandles =
362 WaitableHandleWatchSupport::WaitableWatcherHandles();
364 waitableHandleWatchHandles.begin(),
365 waitableHandleWatchHandles.end(),
366 std::back_inserter(handleList));
374 // Timed event list changed
375 WrtLogD("Timed event list changed invoker");
376 ProcessTimedEvents();
378 // Reset timed event invoker
379 m_timedEventInvoker.Reset();
385 // Waitable handle watch support invoker
386 WrtLogD("Waitable handle watch invoker event occurred");
388 // First, remove all previous handles
389 while (handleList.size() > MIN_HANDLE_LIST_SIZE) {
390 handleList.pop_back();
393 // Insert current waitable event handles instead
395 WaitableHandleListEx waitableHandleWatchHandles =
396 WaitableHandleWatchSupport::WaitableWatcherHandles();
398 waitableHandleWatchHandles.begin(),
399 waitableHandleWatchHandles.end(),
400 std::back_inserter(handleList));
403 // Handle invoker in waitable watch support
404 WaitableHandleWatchSupport::InvokerFinished();
406 WrtLogD("Waitable handle watch invoker event handled");
412 // Waitable event watch list
413 WrtLogD("Waitable handle watch event occurred");
415 // Handle event in waitable handle watch
417 std::pair<WaitableHandle,
418 WaitMode::Type> handle = handleList[index];
419 WaitableHandleWatchSupport::HandleWatcher(handle.first,
423 if (m_directInvoke) {
424 m_directInvoke = false;
426 WrtLogD("Handling direct invoker");
429 while (handleList.size() > MIN_HANDLE_LIST_SIZE) {
430 handleList.pop_back();
433 // Insert current waitable event handles instead
435 WaitableHandleListEx waitableHandleWatchHandles =
436 WaitableHandleWatchSupport::
437 WaitableWatcherHandles();
438 std::copy(waitableHandleWatchHandles.begin(),
439 waitableHandleWatchHandles.end(),
440 std::back_inserter(handleList));
444 WrtLogD("Waitable handle watch event handled");
452 WrtLogD("Leaving thread event processing");
458 WrtLogD("Running thread");
462 std::lock_guard<std::mutex> lock(m_stateMutex);
469 m_thread = std::thread(StaticThreadEntry,this);
470 }catch(std::system_error e){
471 Throw(Exception::RunFailed);
474 // At default, we abandon thread
477 // Enter running state
481 WrtLogD("Thread run");
488 std::lock_guard<std::mutex> lock(m_stateMutex);
490 // Is thread running ?
495 WrtLogD("Quitting thread...");
497 // Do not abandon thread, we will join
500 // Singal quit waitable event
501 m_quitEvent.Signal();
506 }catch(std::system_error e){
507 Throw(Exception::QuitFailed);
510 WrtLogD("Thread quit");
513 void Thread::PushEvent(void *event,
514 EventDispatchProc eventDispatchProc,
515 EventDeleteProc eventDeleteProc,
518 // Enter event list critical section
519 std::lock_guard<std::mutex> lock(m_eventMutex);
522 m_eventList.push_back(InternalEvent(event, userParam, eventDispatchProc,
526 m_eventInvoker.Signal();
528 WrtLogD("Event pushed and invoker signaled");
531 void Thread::PushTimedEvent(void *event,
532 double dueTimeSeconds,
533 EventDispatchProc eventDispatchProc,
534 EventDeleteProc eventDeleteProc,
537 // Check for developer errors
538 Assert(dueTimeSeconds >= 0.0);
540 // Enter timed event list critical section
541 std::lock_guard<std::mutex> lock(m_timedEventMutex);
544 unsigned long currentTimeMiliseconds = GetCurrentTimeMiliseconds();
546 // Convert to miliseconds
547 unsigned long dueTimeMiliseconds =
548 static_cast<unsigned long>(1000.0 * dueTimeSeconds);
550 // Push new timed event
551 m_timedEventVector.push_back(InternalTimedEvent(event, userParam,
553 currentTimeMiliseconds,
557 // Heapify timed events
558 std::make_heap(m_timedEventVector.begin(), m_timedEventVector.end());
561 m_timedEventInvoker.Signal();
563 WrtLogD("Timed event pushed and invoker signaled: "
564 "due time: %lu ms, absolute due time: %lu ms",
565 dueTimeMiliseconds, currentTimeMiliseconds + dueTimeMiliseconds);
568 Thread *Thread::GetInvokerThread()
573 void Thread::HandleDirectInvoker()
575 // We must be in ProcessEvents call stack
576 // Mark that situation to handle direct invoker
577 m_directInvoke = true;
580 void Thread::Sleep(uint64_t seconds)
582 NanoSleep(seconds * NANOSECONDS_PER_SECOND);
585 void Thread::MiliSleep(uint64_t miliseconds)
587 NanoSleep(miliseconds * NANOSECONDS_PER_MILISECOND);
590 void Thread::MicroSleep(uint64_t microseconds)
592 NanoSleep(microseconds * NANOSECONDS_PER_MICROSECOND);
595 void Thread::NanoSleep(uint64_t nanoseconds)
597 timespec requestedTime = {
599 nanoseconds / NANOSECONDS_PER_SECOND),
602 nanoseconds % NANOSECONDS_PER_SECOND)
605 timespec remainingTime;
608 if (nanosleep(&requestedTime, &remainingTime) == 0) {
613 Assert(error == EINTR);
615 requestedTime = remainingTime;