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/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 pthread_t g_mainThread = pthread_self();
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 (pthread_equal(pthread_self(), g_mainThread));
101 Thread *Thread::GetCurrentThread()
103 if (pthread_equal(pthread_self(), 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)
119 LogPedantic("Entered static thread entry");
122 Thread *This = static_cast<Thread *>(param);
123 Assert(This != NULL);
125 // Set thread specific
126 int result = pthread_setspecific(g_threadSpecific.threadSpecific, This);
129 LogError("Failed to set threadSpecific. Error: " << strerror(result));
133 // Do not allow exceptions to hit pthread core
134 UNHANDLED_EXCEPTION_HANDLER_BEGIN
138 UNHANDLED_EXCEPTION_HANDLER_END
142 // Leave running state
143 Mutex::ScopedLock lock(&This->m_stateMutex);
145 This->m_running = false;
148 if (This->m_abandon) {
149 LogPedantic("Thread was abandoned");
150 pthread_detach(This->m_thread);
152 LogPedantic("Thread is joinable");
159 int Thread::ThreadEntry()
161 LogPedantic("Entered default thread entry");
165 void Thread::ProcessEvents()
167 LogPedantic("Processing events");
169 // Steal current event list
170 InternalEventList stolenEvents;
172 // Enter event list critical section
174 Mutex::ScopedLock lock(&m_eventMutex);
175 m_eventList.swap(stolenEvents);
176 m_eventInvoker.Reset();
179 // Process event list
180 LogPedantic("Stolen " << stolenEvents.size() << " internal events");
182 for (InternalEventList::iterator iterator = stolenEvents.begin();
183 iterator != stolenEvents.end();
186 // Dispatch immediate event
187 iterator->eventDispatchProc(iterator->event, iterator->userParam);
190 iterator->eventDeleteProc(iterator->event, iterator->userParam);
194 void Thread::ProcessTimedEvents()
196 // Critical section on timed events mutex
198 Mutex::ScopedLock lock(&m_timedEventMutex);
201 unsigned long currentTimeMiliseconds = GetCurrentTimeMiliseconds();
205 "Processing timed events. Time now: " << currentTimeMiliseconds <<
208 // All timed events are sorted chronologically
209 // Emit timed out events
210 while (!m_timedEventVector.empty() &&
211 currentTimeMiliseconds >=
212 m_timedEventVector.begin()->registerTimeMiliseconds +
213 m_timedEventVector.begin()->dueTimeMiliseconds)
217 "Transforming timed event into immediate event. Absolute due time: "
219 (m_timedEventVector.begin()->registerTimeMiliseconds +
220 m_timedEventVector.begin()->dueTimeMiliseconds) <<
223 // Emit immediate event
224 PushEvent(m_timedEventVector.begin()->event,
225 m_timedEventVector.begin()->eventDispatchProc,
226 m_timedEventVector.begin()->eventDeleteProc,
227 m_timedEventVector.begin()->userParam);
229 // Remove timed eventand fix heap
230 std::pop_heap(m_timedEventVector.begin(), m_timedEventVector.end());
231 m_timedEventVector.pop_back();
236 unsigned long Thread::GetCurrentTimeMiliseconds() const
239 gettimeofday(&tv, NULL);
240 return static_cast<unsigned long>(tv.tv_sec) * 1000 +
241 static_cast<unsigned long>(tv.tv_usec) / 1000;
246 LogPedantic("Executing thread event processing");
248 const std::size_t MIN_HANDLE_LIST_SIZE = 4;
250 // Start processing of events
251 WaitableHandleListEx handleList;
253 // index 0: Quit waitable event handle
254 handleList.push_back(std::make_pair(m_quitEvent.GetHandle(), WaitMode::Read));
256 // index 1: Event occurred event handle
257 handleList.push_back(std::make_pair(m_eventInvoker.GetHandle(),
260 // index 2: Timed event occurred event handle
261 handleList.push_back(std::make_pair(m_timedEventInvoker.GetHandle(),
264 // index 3: Waitable handle watch support invoker
265 handleList.push_back(std::make_pair(WaitableHandleWatchSupport::
266 WaitableInvokerHandle(),
270 // Watch list might have been initialized before threaded started
271 // Need to fill waitable event watch list in this case
274 WaitableHandleListEx waitableHandleWatchHandles =
275 WaitableHandleWatchSupport::WaitableWatcherHandles();
277 waitableHandleWatchHandles.begin(),
278 waitableHandleWatchHandles.end(), std::back_inserter(handleList));
285 // Retrieve minimum wait time, according to timed events list
286 unsigned long minimumWaitTime;
288 // Critical section on timed events mutex
290 Mutex::ScopedLock lock(&m_timedEventMutex);
292 if (!m_timedEventVector.empty()) {
293 unsigned long currentTimeMiliseconds =
294 GetCurrentTimeMiliseconds();
295 unsigned long destinationTimeMiliseconds =
296 m_timedEventVector.begin()->registerTimeMiliseconds +
297 m_timedEventVector.begin()->dueTimeMiliseconds;
299 // Are we already late with timed event ?
300 if (currentTimeMiliseconds > destinationTimeMiliseconds) {
303 minimumWaitTime = destinationTimeMiliseconds -
304 currentTimeMiliseconds;
307 minimumWaitTime = 0xFFFFFFFF; // Infinity
313 "Thread loop minimum wait time: " << minimumWaitTime << " ms");
316 WaitableHandleIndexList waitableHandleIndexList =
317 WaitForMultipleHandles(handleList, minimumWaitTime);
319 if (waitableHandleIndexList.empty()) {
320 // Timeout occurred. Process timed events.
321 LogPedantic("Timed event list elapsed invoker");
322 ProcessTimedEvents();
326 // Go through each index
327 for (WaitableHandleIndexList::const_iterator
328 waitableHandleIndexIterator = waitableHandleIndexList.begin();
329 waitableHandleIndexIterator != waitableHandleIndexList.end();
330 ++waitableHandleIndexIterator)
332 size_t index = *waitableHandleIndexIterator;
334 LogPedantic("Event loop triggered with index: " << index);
338 // Quit waitable event handle
343 // Event occurred event handle
346 // Handle direct invoker
347 if (m_directInvoke) {
348 m_directInvoke = false;
350 LogPedantic("Handling direct invoker");
353 while (handleList.size() > MIN_HANDLE_LIST_SIZE) {
354 handleList.pop_back();
357 // Insert current waitable event handles instead
359 WaitableHandleListEx waitableHandleWatchHandles =
360 WaitableHandleWatchSupport::WaitableWatcherHandles();
362 waitableHandleWatchHandles.begin(),
363 waitableHandleWatchHandles.end(),
364 std::back_inserter(handleList));
372 // Timed event list changed
373 LogPedantic("Timed event list changed invoker");
374 ProcessTimedEvents();
376 // Reset timed event invoker
377 m_timedEventInvoker.Reset();
383 // Waitable handle watch support invoker
384 LogPedantic("Waitable handle watch invoker event occurred");
386 // First, remove all previous handles
387 while (handleList.size() > MIN_HANDLE_LIST_SIZE) {
388 handleList.pop_back();
391 // Insert current waitable event handles instead
393 WaitableHandleListEx waitableHandleWatchHandles =
394 WaitableHandleWatchSupport::WaitableWatcherHandles();
396 waitableHandleWatchHandles.begin(),
397 waitableHandleWatchHandles.end(),
398 std::back_inserter(handleList));
401 // Handle invoker in waitable watch support
402 WaitableHandleWatchSupport::InvokerFinished();
404 LogPedantic("Waitable handle watch invoker event handled");
410 // Waitable event watch list
411 LogPedantic("Waitable handle watch event occurred");
413 // Handle event in waitable handle watch
415 std::pair<WaitableHandle,
416 WaitMode::Type> handle = handleList[index];
417 WaitableHandleWatchSupport::HandleWatcher(handle.first,
421 if (m_directInvoke) {
422 m_directInvoke = false;
424 LogPedantic("Handling direct invoker");
427 while (handleList.size() > MIN_HANDLE_LIST_SIZE) {
428 handleList.pop_back();
431 // Insert current waitable event handles instead
433 WaitableHandleListEx waitableHandleWatchHandles =
434 WaitableHandleWatchSupport::
435 WaitableWatcherHandles();
436 std::copy(waitableHandleWatchHandles.begin(),
437 waitableHandleWatchHandles.end(),
438 std::back_inserter(handleList));
442 LogPedantic("Waitable handle watch event handled");
450 LogPedantic("Leaving thread event processing");
456 LogPedantic("Running thread");
460 Mutex::ScopedLock lock(&m_stateMutex);
466 // Try to create new thread
467 if (pthread_create(&m_thread, NULL, &StaticThreadEntry, this) != 0) {
468 Throw(Exception::RunFailed);
471 // At default, we abandon thread
474 // Enter running state
478 LogPedantic("Thread run");
483 pthread_t joinableThread;
487 Mutex::ScopedLock lock(&m_stateMutex);
489 // Is thread running ?
494 LogPedantic("Quitting thread...");
496 // Do not abandon thread, we will join
499 // Singal quit waitable event
500 m_quitEvent.Signal();
502 // Copy joinable thread identifier, because
503 // we are leaving critical section
504 joinableThread = m_thread;
507 // Wait for joinable thread
510 if (pthread_join(joinableThread, &result) != 0) {
511 Throw(Exception::QuitFailed);
514 LogPedantic("Thread quit");
517 void Thread::PushEvent(void *event,
518 EventDispatchProc eventDispatchProc,
519 EventDeleteProc eventDeleteProc,
522 // Enter event list critical section
523 Mutex::ScopedLock lock(&m_eventMutex);
526 m_eventList.push_back(InternalEvent(event, userParam, eventDispatchProc,
530 m_eventInvoker.Signal();
532 LogPedantic("Event pushed and invoker signaled");
535 void Thread::PushTimedEvent(void *event,
536 double dueTimeSeconds,
537 EventDispatchProc eventDispatchProc,
538 EventDeleteProc eventDeleteProc,
541 // Check for developer errors
542 Assert(dueTimeSeconds >= 0.0);
544 // Enter timed event list critical section
545 Mutex::ScopedLock lock(&m_timedEventMutex);
548 unsigned long currentTimeMiliseconds = GetCurrentTimeMiliseconds();
550 // Convert to miliseconds
551 unsigned long dueTimeMiliseconds =
552 static_cast<unsigned long>(1000.0 * dueTimeSeconds);
554 // Push new timed event
555 m_timedEventVector.push_back(InternalTimedEvent(event, userParam,
557 currentTimeMiliseconds,
561 // Heapify timed events
562 std::make_heap(m_timedEventVector.begin(), m_timedEventVector.end());
565 m_timedEventInvoker.Signal();
568 "Timed event pushed and invoker signaled: due time: " <<
569 dueTimeMiliseconds << " ms, absolute due time: " <<
570 currentTimeMiliseconds + dueTimeMiliseconds << " ms");
573 Thread *Thread::GetInvokerThread()
578 void Thread::HandleDirectInvoker()
580 // We must be in ProcessEvents call stack
581 // Mark that situation to handle direct invoker
582 m_directInvoke = true;
585 void Thread::Sleep(uint64_t seconds)
587 NanoSleep(seconds * NANOSECONDS_PER_SECOND);
590 void Thread::MiliSleep(uint64_t miliseconds)
592 NanoSleep(miliseconds * NANOSECONDS_PER_MILISECOND);
595 void Thread::MicroSleep(uint64_t microseconds)
597 NanoSleep(microseconds * NANOSECONDS_PER_MICROSECOND);
600 void Thread::NanoSleep(uint64_t nanoseconds)
602 timespec requestedTime = {
604 nanoseconds / NANOSECONDS_PER_SECOND),
607 nanoseconds % NANOSECONDS_PER_SECOND)
610 timespec remainingTime;
613 if (nanosleep(&requestedTime, &remainingTime) == 0) {
618 Assert(error == EINTR);
620 requestedTime = remainingTime;