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
22 #include <dpl/thread.h>
23 #include <dpl/log/log.h>
26 #include <dpl/assert.h>
30 namespace // anonymous
32 static const size_t NANOSECONDS_PER_SECOND =
33 static_cast<uint64_t>(1000 * 1000 * 1000);
35 static const size_t NANOSECONDS_PER_MILISECOND =
36 static_cast<uint64_t>(1000 * 1000);
38 static const size_t NANOSECONDS_PER_MICROSECOND =
39 static_cast<uint64_t>(1000);
41 static const pthread_t g_mainThread = pthread_self();
46 pthread_key_t threadSpecific;
52 pthread_key_create(&threadSpecific, NULL);
55 virtual ~ThreadSpecific()
57 pthread_key_delete(threadSpecific);
61 static ThreadSpecific g_threadSpecific;
62 } // namespace anonymous
66 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(); iterator != m_eventList.end(); ++iterator)
87 iterator->eventDeleteProc(iterator->event, iterator->userParam);
92 Thread *Thread::GetCurrentThread()
94 if (pthread_equal(pthread_self(), g_mainThread))
97 void *threadSpecific = pthread_getspecific(g_threadSpecific.threadSpecific);
99 // Is this a managed thread ?
100 if (threadSpecific == NULL)
101 Throw(Exception::UnmanagedThread);
103 return static_cast<Thread *>(threadSpecific);
106 void *Thread::StaticThreadEntry(void *param)
108 LogPedantic("Entered static thread entry");
111 Thread *This = static_cast<Thread *>(param);
112 Assert(This != NULL);
114 // Set thread specific
115 pthread_setspecific(g_threadSpecific.threadSpecific, This);
118 // Do not allow exceptions to hit pthread core
119 UNHANDLED_EXCEPTION_HANDLER_BEGIN
123 UNHANDLED_EXCEPTION_HANDLER_END
127 // Leave running state
128 Mutex::ScopedLock lock(&This->m_stateMutex);
130 This->m_running = false;
135 LogPedantic("Thread was abandoned");
136 pthread_detach(This->m_thread);
140 LogPedantic("Thread is joinable");
147 int Thread::ThreadEntry()
149 LogPedantic("Entered default thread entry");
153 void Thread::ProcessEvents()
155 LogPedantic("Processing events");
157 // Steal current event list
158 InternalEventList stolenEvents;
160 // Enter event list critical section
162 Mutex::ScopedLock lock(&m_eventMutex);
163 m_eventList.swap(stolenEvents);
164 m_eventInvoker.Reset();
167 // Process event list
168 LogPedantic("Stolen " << stolenEvents.size() << " internal events");
170 for (InternalEventList::iterator iterator = stolenEvents.begin(); iterator != stolenEvents.end(); ++iterator)
172 // Dispatch immediate event
173 iterator->eventDispatchProc(iterator->event, iterator->userParam);
176 iterator->eventDeleteProc(iterator->event, iterator->userParam);
180 void Thread::ProcessTimedEvents()
182 // Critical section on timed events mutex
184 Mutex::ScopedLock lock(&m_timedEventMutex);
187 unsigned long currentTimeMiliseconds = GetCurrentTimeMiliseconds();
190 LogPedantic("Processing timed events. Time now: " << currentTimeMiliseconds << " ms");
192 // All timed events are sorted chronologically
193 // Emit timed out events
194 while (!m_timedEventVector.empty() &&
195 currentTimeMiliseconds >= m_timedEventVector.begin()->registerTimeMiliseconds + m_timedEventVector.begin()->dueTimeMiliseconds)
198 LogPedantic("Transforming timed event into immediate event. Absolute due time: " <<
199 (m_timedEventVector.begin()->registerTimeMiliseconds + m_timedEventVector.begin()->dueTimeMiliseconds) << " ms");
201 // Emit immediate event
202 PushEvent(m_timedEventVector.begin()->event,
203 m_timedEventVector.begin()->eventDispatchProc,
204 m_timedEventVector.begin()->eventDeleteProc,
205 m_timedEventVector.begin()->userParam);
207 // Remove timed eventand fix heap
208 std::pop_heap(m_timedEventVector.begin(), m_timedEventVector.end());
209 m_timedEventVector.pop_back();
214 unsigned long Thread::GetCurrentTimeMiliseconds() const
217 gettimeofday(&tv, NULL);
218 return static_cast<unsigned long>(tv.tv_sec) * 1000 + static_cast<unsigned long>(tv.tv_usec) / 1000;
223 LogPedantic("Executing thread event processing");
225 const std::size_t MIN_HANDLE_LIST_SIZE = 4;
227 // Start processing of events
228 WaitableHandleListEx handleList;
230 // index 0: Quit waitable event handle
231 handleList.push_back(std::make_pair(m_quitEvent.GetHandle(), WaitMode::Read));
233 // index 1: Event occurred event handle
234 handleList.push_back(std::make_pair(m_eventInvoker.GetHandle(), WaitMode::Read));
236 // index 2: Timed event occurred event handle
237 handleList.push_back(std::make_pair(m_timedEventInvoker.GetHandle(), WaitMode::Read));
239 // index 3: Waitable handle watch support invoker
240 handleList.push_back(std::make_pair(WaitableHandleWatchSupport::WaitableInvokerHandle(), WaitMode::Read));
243 // Watch list might have been initialized before threaded started
244 // Need to fill waitable event watch list in this case
247 WaitableHandleListEx waitableHandleWatchHandles = WaitableHandleWatchSupport::WaitableWatcherHandles();
248 std::copy(waitableHandleWatchHandles.begin(), waitableHandleWatchHandles.end(), std::back_inserter(handleList));
256 // Retrieve minimum wait time, according to timed events list
257 unsigned long minimumWaitTime;
259 // Critical section on timed events mutex
261 Mutex::ScopedLock lock(&m_timedEventMutex);
263 if (!m_timedEventVector.empty())
265 unsigned long currentTimeMiliseconds = GetCurrentTimeMiliseconds();
266 unsigned long destinationTimeMiliseconds = m_timedEventVector.begin()->registerTimeMiliseconds + m_timedEventVector.begin()->dueTimeMiliseconds;
268 // Are we already late with timed event ?
269 if (currentTimeMiliseconds > destinationTimeMiliseconds)
272 minimumWaitTime = destinationTimeMiliseconds - currentTimeMiliseconds;
275 minimumWaitTime = 0xFFFFFFFF; // Infinity
279 LogPedantic("Thread loop minimum wait time: " << minimumWaitTime << " ms");
282 WaitableHandleIndexList waitableHandleIndexList = WaitForMultipleHandles(handleList, minimumWaitTime);
284 if (waitableHandleIndexList.empty())
286 // Timeout occurred. Process timed events.
287 LogPedantic("Timed event list elapsed invoker");
288 ProcessTimedEvents();
292 // Go through each index
293 for (WaitableHandleIndexList::const_iterator waitableHandleIndexIterator = waitableHandleIndexList.begin();
294 waitableHandleIndexIterator != waitableHandleIndexList.end();
295 ++waitableHandleIndexIterator)
297 size_t index = *waitableHandleIndexIterator;
299 LogPedantic("Event loop triggered with index: " << index);
304 // Quit waitable event handle
309 // Event occurred event handle
312 // Handle direct invoker
315 m_directInvoke = false;
317 LogPedantic("Handling direct invoker");
320 while (handleList.size() > MIN_HANDLE_LIST_SIZE)
321 handleList.pop_back();
323 // Insert current waitable event handles instead
325 WaitableHandleListEx waitableHandleWatchHandles = WaitableHandleWatchSupport::WaitableWatcherHandles();
326 std::copy(waitableHandleWatchHandles.begin(), waitableHandleWatchHandles.end(), std::back_inserter(handleList));
334 // Timed event list changed
335 LogPedantic("Timed event list changed invoker");
336 ProcessTimedEvents();
338 // Reset timed event invoker
339 m_timedEventInvoker.Reset();
345 // Waitable handle watch support invoker
346 LogPedantic("Waitable handle watch invoker event occurred");
348 // First, remove all previous handles
349 while (handleList.size() > MIN_HANDLE_LIST_SIZE)
350 handleList.pop_back();
352 // Insert current waitable event handles instead
354 WaitableHandleListEx waitableHandleWatchHandles = WaitableHandleWatchSupport::WaitableWatcherHandles();
355 std::copy(waitableHandleWatchHandles.begin(), waitableHandleWatchHandles.end(), std::back_inserter(handleList));
358 // Handle invoker in waitable watch support
359 WaitableHandleWatchSupport::InvokerFinished();
361 LogPedantic("Waitable handle watch invoker event handled");
367 // Waitable event watch list
368 LogPedantic("Waitable handle watch event occurred");
370 // Handle event in waitable handle watch
372 std::pair<WaitableHandle, WaitMode::Type> handle = handleList[index];
373 WaitableHandleWatchSupport::HandleWatcher(handle.first, handle.second);
378 m_directInvoke = false;
380 LogPedantic("Handling direct invoker");
383 while (handleList.size() > MIN_HANDLE_LIST_SIZE)
384 handleList.pop_back();
386 // Insert current waitable event handles instead
388 WaitableHandleListEx waitableHandleWatchHandles =
389 WaitableHandleWatchSupport::
390 WaitableWatcherHandles();
391 std::copy(waitableHandleWatchHandles.begin(),
392 waitableHandleWatchHandles.end(),
393 std::back_inserter(handleList));
397 LogPedantic("Waitable handle watch event handled");
405 LogPedantic("Leaving thread event processing");
411 LogPedantic("Running thread");
415 Mutex::ScopedLock lock(&m_stateMutex);
420 // Try to create new thread
421 if (pthread_create(&m_thread, NULL, &StaticThreadEntry, this) != 0)
422 Throw(Exception::RunFailed);
424 // At default, we abandon thread
427 // Enter running state
431 LogPedantic("Thread run");
436 pthread_t joinableThread;
440 Mutex::ScopedLock lock(&m_stateMutex);
442 // Is thread running ?
446 LogPedantic("Quitting thread...");
448 // Do not abandon thread, we will join
451 // Singal quit waitable event
452 m_quitEvent.Signal();
454 // Copy joinable thread identifier, because
455 // we are leaving critical section
456 joinableThread = m_thread;
459 // Wait for joinable thread
462 if (pthread_join(joinableThread, &result) != 0)
463 Throw(Exception::QuitFailed);
465 LogPedantic("Thread quit");
468 void Thread::PushEvent(void *event, EventDispatchProc eventDispatchProc, EventDeleteProc eventDeleteProc, void *userParam)
470 // Enter event list critical section
471 Mutex::ScopedLock lock(&m_eventMutex);
474 m_eventList.push_back(InternalEvent(event, userParam, eventDispatchProc, eventDeleteProc));
477 m_eventInvoker.Signal();
479 LogPedantic("Event pushed and invoker signaled");
482 void Thread::PushTimedEvent(void *event, double dueTimeSeconds, EventDispatchProc eventDispatchProc, EventDeleteProc eventDeleteProc, void *userParam)
484 // Check for developer errors
485 Assert(dueTimeSeconds >= 0.0);
487 // Enter timed event list critical section
488 Mutex::ScopedLock lock(&m_timedEventMutex);
491 unsigned long currentTimeMiliseconds = GetCurrentTimeMiliseconds();
493 // Convert to miliseconds
494 unsigned long dueTimeMiliseconds = static_cast<unsigned long>(1000.0 * dueTimeSeconds);
496 // Push new timed event
497 m_timedEventVector.push_back(InternalTimedEvent(event, userParam, dueTimeMiliseconds, currentTimeMiliseconds, eventDispatchProc, eventDeleteProc));
499 // Heapify timed events
500 std::make_heap(m_timedEventVector.begin(), m_timedEventVector.end());
503 m_timedEventInvoker.Signal();
505 LogPedantic("Timed event pushed and invoker signaled: due time: " << dueTimeMiliseconds << " ms, absolute due time: " << currentTimeMiliseconds + dueTimeMiliseconds << " ms");
508 Thread *Thread::GetInvokerThread()
513 void Thread::HandleDirectInvoker()
515 // We must be in ProcessEvents call stack
516 // Mark that situation to handle direct invoker
517 m_directInvoke = true;
520 void Thread::Sleep(uint64_t seconds)
522 NanoSleep(seconds * NANOSECONDS_PER_SECOND);
525 void Thread::MiliSleep(uint64_t miliseconds)
527 NanoSleep(miliseconds * NANOSECONDS_PER_MILISECOND);
530 void Thread::MicroSleep(uint64_t microseconds)
532 NanoSleep(microseconds * NANOSECONDS_PER_MICROSECOND);
535 void Thread::NanoSleep(uint64_t nanoseconds)
537 timespec requestedTime =
540 nanoseconds / NANOSECONDS_PER_SECOND),
543 nanoseconds % NANOSECONDS_PER_SECOND)
546 timespec remainingTime;
550 if (nanosleep(&requestedTime, &remainingTime) == 0)
554 Assert(error == EINTR);
556 requestedTime = remainingTime;