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 bool Thread::IsMainThread()
94 return (pthread_equal(pthread_self(), g_mainThread));
97 Thread *Thread::GetCurrentThread()
99 if (pthread_equal(pthread_self(), g_mainThread))
102 void *threadSpecific = pthread_getspecific(g_threadSpecific.threadSpecific);
104 // Is this a managed thread ?
105 if (threadSpecific == NULL)
106 Throw(Exception::UnmanagedThread);
108 return static_cast<Thread *>(threadSpecific);
111 void *Thread::StaticThreadEntry(void *param)
113 LogPedantic("Entered static thread entry");
116 Thread *This = static_cast<Thread *>(param);
117 Assert(This != NULL);
119 // Set thread specific
120 pthread_setspecific(g_threadSpecific.threadSpecific, This);
123 // Do not allow exceptions to hit pthread core
124 UNHANDLED_EXCEPTION_HANDLER_BEGIN
128 UNHANDLED_EXCEPTION_HANDLER_END
132 // Leave running state
133 Mutex::ScopedLock lock(&This->m_stateMutex);
135 This->m_running = false;
140 LogPedantic("Thread was abandoned");
141 pthread_detach(This->m_thread);
145 LogPedantic("Thread is joinable");
152 int Thread::ThreadEntry()
154 LogPedantic("Entered default thread entry");
158 void Thread::ProcessEvents()
160 LogPedantic("Processing events");
162 // Steal current event list
163 InternalEventList stolenEvents;
165 // Enter event list critical section
167 Mutex::ScopedLock lock(&m_eventMutex);
168 m_eventList.swap(stolenEvents);
169 m_eventInvoker.Reset();
172 // Process event list
173 LogPedantic("Stolen " << stolenEvents.size() << " internal events");
175 for (InternalEventList::iterator iterator = stolenEvents.begin(); iterator != stolenEvents.end(); ++iterator)
177 // Dispatch immediate event
178 iterator->eventDispatchProc(iterator->event, iterator->userParam);
181 iterator->eventDeleteProc(iterator->event, iterator->userParam);
185 void Thread::ProcessTimedEvents()
187 // Critical section on timed events mutex
189 Mutex::ScopedLock lock(&m_timedEventMutex);
192 unsigned long currentTimeMiliseconds = GetCurrentTimeMiliseconds();
195 LogPedantic("Processing timed events. Time now: " << currentTimeMiliseconds << " ms");
197 // All timed events are sorted chronologically
198 // Emit timed out events
199 while (!m_timedEventVector.empty() &&
200 currentTimeMiliseconds >= m_timedEventVector.begin()->registerTimeMiliseconds + m_timedEventVector.begin()->dueTimeMiliseconds)
203 LogPedantic("Transforming timed event into immediate event. Absolute due time: " <<
204 (m_timedEventVector.begin()->registerTimeMiliseconds + m_timedEventVector.begin()->dueTimeMiliseconds) << " ms");
206 // Emit immediate event
207 PushEvent(m_timedEventVector.begin()->event,
208 m_timedEventVector.begin()->eventDispatchProc,
209 m_timedEventVector.begin()->eventDeleteProc,
210 m_timedEventVector.begin()->userParam);
212 // Remove timed eventand fix heap
213 std::pop_heap(m_timedEventVector.begin(), m_timedEventVector.end());
214 m_timedEventVector.pop_back();
219 unsigned long Thread::GetCurrentTimeMiliseconds() const
222 gettimeofday(&tv, NULL);
223 return static_cast<unsigned long>(tv.tv_sec) * 1000 + static_cast<unsigned long>(tv.tv_usec) / 1000;
228 LogPedantic("Executing thread event processing");
230 const std::size_t MIN_HANDLE_LIST_SIZE = 4;
232 // Start processing of events
233 WaitableHandleListEx handleList;
235 // index 0: Quit waitable event handle
236 handleList.push_back(std::make_pair(m_quitEvent.GetHandle(), WaitMode::Read));
238 // index 1: Event occurred event handle
239 handleList.push_back(std::make_pair(m_eventInvoker.GetHandle(), WaitMode::Read));
241 // index 2: Timed event occurred event handle
242 handleList.push_back(std::make_pair(m_timedEventInvoker.GetHandle(), WaitMode::Read));
244 // index 3: Waitable handle watch support invoker
245 handleList.push_back(std::make_pair(WaitableHandleWatchSupport::WaitableInvokerHandle(), WaitMode::Read));
248 // Watch list might have been initialized before threaded started
249 // Need to fill waitable event watch list in this case
252 WaitableHandleListEx waitableHandleWatchHandles = WaitableHandleWatchSupport::WaitableWatcherHandles();
253 std::copy(waitableHandleWatchHandles.begin(), waitableHandleWatchHandles.end(), std::back_inserter(handleList));
261 // Retrieve minimum wait time, according to timed events list
262 unsigned long minimumWaitTime;
264 // Critical section on timed events mutex
266 Mutex::ScopedLock lock(&m_timedEventMutex);
268 if (!m_timedEventVector.empty())
270 unsigned long currentTimeMiliseconds = GetCurrentTimeMiliseconds();
271 unsigned long destinationTimeMiliseconds = m_timedEventVector.begin()->registerTimeMiliseconds + m_timedEventVector.begin()->dueTimeMiliseconds;
273 // Are we already late with timed event ?
274 if (currentTimeMiliseconds > destinationTimeMiliseconds)
277 minimumWaitTime = destinationTimeMiliseconds - currentTimeMiliseconds;
280 minimumWaitTime = 0xFFFFFFFF; // Infinity
284 LogPedantic("Thread loop minimum wait time: " << minimumWaitTime << " ms");
287 WaitableHandleIndexList waitableHandleIndexList = WaitForMultipleHandles(handleList, minimumWaitTime);
289 if (waitableHandleIndexList.empty())
291 // Timeout occurred. Process timed events.
292 LogPedantic("Timed event list elapsed invoker");
293 ProcessTimedEvents();
297 // Go through each index
298 for (WaitableHandleIndexList::const_iterator waitableHandleIndexIterator = waitableHandleIndexList.begin();
299 waitableHandleIndexIterator != waitableHandleIndexList.end();
300 ++waitableHandleIndexIterator)
302 size_t index = *waitableHandleIndexIterator;
304 LogPedantic("Event loop triggered with index: " << index);
309 // Quit waitable event handle
314 // Event occurred event handle
317 // Handle direct invoker
320 m_directInvoke = false;
322 LogPedantic("Handling direct invoker");
325 while (handleList.size() > MIN_HANDLE_LIST_SIZE)
326 handleList.pop_back();
328 // Insert current waitable event handles instead
330 WaitableHandleListEx waitableHandleWatchHandles = WaitableHandleWatchSupport::WaitableWatcherHandles();
331 std::copy(waitableHandleWatchHandles.begin(), waitableHandleWatchHandles.end(), std::back_inserter(handleList));
339 // Timed event list changed
340 LogPedantic("Timed event list changed invoker");
341 ProcessTimedEvents();
343 // Reset timed event invoker
344 m_timedEventInvoker.Reset();
350 // Waitable handle watch support invoker
351 LogPedantic("Waitable handle watch invoker event occurred");
353 // First, remove all previous handles
354 while (handleList.size() > MIN_HANDLE_LIST_SIZE)
355 handleList.pop_back();
357 // Insert current waitable event handles instead
359 WaitableHandleListEx waitableHandleWatchHandles = WaitableHandleWatchSupport::WaitableWatcherHandles();
360 std::copy(waitableHandleWatchHandles.begin(), waitableHandleWatchHandles.end(), std::back_inserter(handleList));
363 // Handle invoker in waitable watch support
364 WaitableHandleWatchSupport::InvokerFinished();
366 LogPedantic("Waitable handle watch invoker event handled");
372 // Waitable event watch list
373 LogPedantic("Waitable handle watch event occurred");
375 // Handle event in waitable handle watch
377 std::pair<WaitableHandle, WaitMode::Type> handle = handleList[index];
378 WaitableHandleWatchSupport::HandleWatcher(handle.first, handle.second);
383 m_directInvoke = false;
385 LogPedantic("Handling direct invoker");
388 while (handleList.size() > MIN_HANDLE_LIST_SIZE)
389 handleList.pop_back();
391 // Insert current waitable event handles instead
393 WaitableHandleListEx waitableHandleWatchHandles =
394 WaitableHandleWatchSupport::
395 WaitableWatcherHandles();
396 std::copy(waitableHandleWatchHandles.begin(),
397 waitableHandleWatchHandles.end(),
398 std::back_inserter(handleList));
402 LogPedantic("Waitable handle watch event handled");
410 LogPedantic("Leaving thread event processing");
416 LogPedantic("Running thread");
420 Mutex::ScopedLock lock(&m_stateMutex);
425 // Try to create new thread
426 if (pthread_create(&m_thread, NULL, &StaticThreadEntry, this) != 0)
427 Throw(Exception::RunFailed);
429 // At default, we abandon thread
432 // Enter running state
436 LogPedantic("Thread run");
441 pthread_t joinableThread;
445 Mutex::ScopedLock lock(&m_stateMutex);
447 // Is thread running ?
451 LogPedantic("Quitting thread...");
453 // Do not abandon thread, we will join
456 // Singal quit waitable event
457 m_quitEvent.Signal();
459 // Copy joinable thread identifier, because
460 // we are leaving critical section
461 joinableThread = m_thread;
464 // Wait for joinable thread
467 if (pthread_join(joinableThread, &result) != 0)
468 Throw(Exception::QuitFailed);
470 LogPedantic("Thread quit");
473 void Thread::PushEvent(void *event, EventDispatchProc eventDispatchProc, EventDeleteProc eventDeleteProc, void *userParam)
475 // Enter event list critical section
476 Mutex::ScopedLock lock(&m_eventMutex);
479 m_eventList.push_back(InternalEvent(event, userParam, eventDispatchProc, eventDeleteProc));
482 m_eventInvoker.Signal();
484 LogPedantic("Event pushed and invoker signaled");
487 void Thread::PushTimedEvent(void *event, double dueTimeSeconds, EventDispatchProc eventDispatchProc, EventDeleteProc eventDeleteProc, void *userParam)
489 // Check for developer errors
490 Assert(dueTimeSeconds >= 0.0);
492 // Enter timed event list critical section
493 Mutex::ScopedLock lock(&m_timedEventMutex);
496 unsigned long currentTimeMiliseconds = GetCurrentTimeMiliseconds();
498 // Convert to miliseconds
499 unsigned long dueTimeMiliseconds = static_cast<unsigned long>(1000.0 * dueTimeSeconds);
501 // Push new timed event
502 m_timedEventVector.push_back(InternalTimedEvent(event, userParam, dueTimeMiliseconds, currentTimeMiliseconds, eventDispatchProc, eventDeleteProc));
504 // Heapify timed events
505 std::make_heap(m_timedEventVector.begin(), m_timedEventVector.end());
508 m_timedEventInvoker.Signal();
510 LogPedantic("Timed event pushed and invoker signaled: due time: " << dueTimeMiliseconds << " ms, absolute due time: " << currentTimeMiliseconds + dueTimeMiliseconds << " ms");
513 Thread *Thread::GetInvokerThread()
518 void Thread::HandleDirectInvoker()
520 // We must be in ProcessEvents call stack
521 // Mark that situation to handle direct invoker
522 m_directInvoke = true;
525 void Thread::Sleep(uint64_t seconds)
527 NanoSleep(seconds * NANOSECONDS_PER_SECOND);
530 void Thread::MiliSleep(uint64_t miliseconds)
532 NanoSleep(miliseconds * NANOSECONDS_PER_MILISECOND);
535 void Thread::MicroSleep(uint64_t microseconds)
537 NanoSleep(microseconds * NANOSECONDS_PER_MICROSECOND);
540 void Thread::NanoSleep(uint64_t nanoseconds)
542 timespec requestedTime =
545 nanoseconds / NANOSECONDS_PER_SECOND),
548 nanoseconds % NANOSECONDS_PER_SECOND)
551 timespec remainingTime;
555 if (nanosleep(&requestedTime, &remainingTime) == 0)
559 Assert(error == EINTR);
561 requestedTime = remainingTime;