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
68 bool g_TLSforMainCreated = false;
80 // Ensure that we quit thread
81 // Always wait thread by yourself; if thread is still running
82 // this may be sometimes very bad. When derived, some resources
83 // may leak or be doubly freed
86 // Remove any remainig events
87 // Thread proc is surely not running now
88 for (InternalEventList::iterator iterator = m_eventList.begin(); iterator != m_eventList.end(); ++iterator)
89 iterator->eventDeleteProc(iterator->event, iterator->userParam);
94 bool Thread::IsMainThread()
96 return (pthread_equal(pthread_self(), g_mainThread));
99 Thread *Thread::GetCurrentThread()
101 if (pthread_equal(pthread_self(), g_mainThread))
104 void *threadSpecific = pthread_getspecific(g_threadSpecific.threadSpecific);
106 // Is this a managed thread ?
107 if (threadSpecific == NULL)
108 Throw(Exception::UnmanagedThread);
110 return static_cast<Thread *>(threadSpecific);
113 void *Thread::StaticThreadEntry(void *param)
115 LogPedantic("Entered static thread entry");
118 Thread *This = static_cast<Thread *>(param);
119 Assert(This != NULL);
121 // Set thread specific
122 int result = pthread_setspecific(g_threadSpecific.threadSpecific, This);
126 LogError("Failed to set threadSpecific. Error: " << strerror(result));
130 // Do not allow exceptions to hit pthread core
131 UNHANDLED_EXCEPTION_HANDLER_BEGIN
135 UNHANDLED_EXCEPTION_HANDLER_END
139 // Leave running state
140 Mutex::ScopedLock lock(&This->m_stateMutex);
142 This->m_running = false;
147 LogPedantic("Thread was abandoned");
148 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(); iterator != stolenEvents.end(); ++iterator)
184 // Dispatch immediate event
185 iterator->eventDispatchProc(iterator->event, iterator->userParam);
188 iterator->eventDeleteProc(iterator->event, iterator->userParam);
192 void Thread::ProcessTimedEvents()
194 // Critical section on timed events mutex
196 Mutex::ScopedLock lock(&m_timedEventMutex);
199 unsigned long currentTimeMiliseconds = GetCurrentTimeMiliseconds();
202 LogPedantic("Processing timed events. Time now: " << currentTimeMiliseconds << " ms");
204 // All timed events are sorted chronologically
205 // Emit timed out events
206 while (!m_timedEventVector.empty() &&
207 currentTimeMiliseconds >= m_timedEventVector.begin()->registerTimeMiliseconds + m_timedEventVector.begin()->dueTimeMiliseconds)
210 LogPedantic("Transforming timed event into immediate event. Absolute due time: " <<
211 (m_timedEventVector.begin()->registerTimeMiliseconds + m_timedEventVector.begin()->dueTimeMiliseconds) << " ms");
213 // Emit immediate event
214 PushEvent(m_timedEventVector.begin()->event,
215 m_timedEventVector.begin()->eventDispatchProc,
216 m_timedEventVector.begin()->eventDeleteProc,
217 m_timedEventVector.begin()->userParam);
219 // Remove timed eventand fix heap
220 std::pop_heap(m_timedEventVector.begin(), m_timedEventVector.end());
221 m_timedEventVector.pop_back();
226 unsigned long Thread::GetCurrentTimeMiliseconds() const
229 gettimeofday(&tv, NULL);
230 return static_cast<unsigned long>(tv.tv_sec) * 1000 + static_cast<unsigned long>(tv.tv_usec) / 1000;
235 LogPedantic("Executing thread event processing");
237 const std::size_t MIN_HANDLE_LIST_SIZE = 4;
239 // Start processing of events
240 WaitableHandleListEx handleList;
242 // index 0: Quit waitable event handle
243 handleList.push_back(std::make_pair(m_quitEvent.GetHandle(), WaitMode::Read));
245 // index 1: Event occurred event handle
246 handleList.push_back(std::make_pair(m_eventInvoker.GetHandle(), WaitMode::Read));
248 // index 2: Timed event occurred event handle
249 handleList.push_back(std::make_pair(m_timedEventInvoker.GetHandle(), WaitMode::Read));
251 // index 3: Waitable handle watch support invoker
252 handleList.push_back(std::make_pair(WaitableHandleWatchSupport::WaitableInvokerHandle(), WaitMode::Read));
255 // Watch list might have been initialized before threaded started
256 // Need to fill waitable event watch list in this case
259 WaitableHandleListEx waitableHandleWatchHandles = WaitableHandleWatchSupport::WaitableWatcherHandles();
260 std::copy(waitableHandleWatchHandles.begin(), waitableHandleWatchHandles.end(), std::back_inserter(handleList));
268 // Retrieve minimum wait time, according to timed events list
269 unsigned long minimumWaitTime;
271 // Critical section on timed events mutex
273 Mutex::ScopedLock lock(&m_timedEventMutex);
275 if (!m_timedEventVector.empty())
277 unsigned long currentTimeMiliseconds = GetCurrentTimeMiliseconds();
278 unsigned long destinationTimeMiliseconds = m_timedEventVector.begin()->registerTimeMiliseconds + m_timedEventVector.begin()->dueTimeMiliseconds;
280 // Are we already late with timed event ?
281 if (currentTimeMiliseconds > destinationTimeMiliseconds)
284 minimumWaitTime = destinationTimeMiliseconds - currentTimeMiliseconds;
287 minimumWaitTime = 0xFFFFFFFF; // Infinity
291 LogPedantic("Thread loop minimum wait time: " << minimumWaitTime << " ms");
294 WaitableHandleIndexList waitableHandleIndexList = WaitForMultipleHandles(handleList, minimumWaitTime);
296 if (waitableHandleIndexList.empty())
298 // Timeout occurred. Process timed events.
299 LogPedantic("Timed event list elapsed invoker");
300 ProcessTimedEvents();
304 // Go through each index
305 for (WaitableHandleIndexList::const_iterator waitableHandleIndexIterator = waitableHandleIndexList.begin();
306 waitableHandleIndexIterator != waitableHandleIndexList.end();
307 ++waitableHandleIndexIterator)
309 size_t index = *waitableHandleIndexIterator;
311 LogPedantic("Event loop triggered with index: " << index);
316 // Quit waitable event handle
321 // Event occurred event handle
324 // Handle direct invoker
327 m_directInvoke = false;
329 LogPedantic("Handling direct invoker");
332 while (handleList.size() > MIN_HANDLE_LIST_SIZE)
333 handleList.pop_back();
335 // Insert current waitable event handles instead
337 WaitableHandleListEx waitableHandleWatchHandles = WaitableHandleWatchSupport::WaitableWatcherHandles();
338 std::copy(waitableHandleWatchHandles.begin(), waitableHandleWatchHandles.end(), std::back_inserter(handleList));
346 // Timed event list changed
347 LogPedantic("Timed event list changed invoker");
348 ProcessTimedEvents();
350 // Reset timed event invoker
351 m_timedEventInvoker.Reset();
357 // Waitable handle watch support invoker
358 LogPedantic("Waitable handle watch invoker event occurred");
360 // First, remove all previous handles
361 while (handleList.size() > MIN_HANDLE_LIST_SIZE)
362 handleList.pop_back();
364 // Insert current waitable event handles instead
366 WaitableHandleListEx waitableHandleWatchHandles = WaitableHandleWatchSupport::WaitableWatcherHandles();
367 std::copy(waitableHandleWatchHandles.begin(), waitableHandleWatchHandles.end(), std::back_inserter(handleList));
370 // Handle invoker in waitable watch support
371 WaitableHandleWatchSupport::InvokerFinished();
373 LogPedantic("Waitable handle watch invoker event handled");
379 // Waitable event watch list
380 LogPedantic("Waitable handle watch event occurred");
382 // Handle event in waitable handle watch
384 std::pair<WaitableHandle, WaitMode::Type> handle = handleList[index];
385 WaitableHandleWatchSupport::HandleWatcher(handle.first, handle.second);
390 m_directInvoke = false;
392 LogPedantic("Handling direct invoker");
395 while (handleList.size() > MIN_HANDLE_LIST_SIZE)
396 handleList.pop_back();
398 // Insert current waitable event handles instead
400 WaitableHandleListEx waitableHandleWatchHandles =
401 WaitableHandleWatchSupport::
402 WaitableWatcherHandles();
403 std::copy(waitableHandleWatchHandles.begin(),
404 waitableHandleWatchHandles.end(),
405 std::back_inserter(handleList));
409 LogPedantic("Waitable handle watch event handled");
417 LogPedantic("Leaving thread event processing");
423 LogPedantic("Running thread");
427 Mutex::ScopedLock lock(&m_stateMutex);
432 // Try to create new thread
433 if (pthread_create(&m_thread, NULL, &StaticThreadEntry, this) != 0)
434 Throw(Exception::RunFailed);
436 // At default, we abandon thread
439 // Enter running state
443 LogPedantic("Thread run");
448 pthread_t joinableThread;
452 Mutex::ScopedLock lock(&m_stateMutex);
454 // Is thread running ?
458 LogPedantic("Quitting thread...");
460 // Do not abandon thread, we will join
463 // Singal quit waitable event
464 m_quitEvent.Signal();
466 // Copy joinable thread identifier, because
467 // we are leaving critical section
468 joinableThread = m_thread;
471 // Wait for joinable thread
474 if (pthread_join(joinableThread, &result) != 0)
475 Throw(Exception::QuitFailed);
477 LogPedantic("Thread quit");
480 void Thread::PushEvent(void *event, EventDispatchProc eventDispatchProc, EventDeleteProc eventDeleteProc, void *userParam)
482 // Enter event list critical section
483 Mutex::ScopedLock lock(&m_eventMutex);
486 m_eventList.push_back(InternalEvent(event, userParam, eventDispatchProc, eventDeleteProc));
489 m_eventInvoker.Signal();
491 LogPedantic("Event pushed and invoker signaled");
494 void Thread::PushTimedEvent(void *event, double dueTimeSeconds, EventDispatchProc eventDispatchProc, EventDeleteProc eventDeleteProc, void *userParam)
496 // Check for developer errors
497 Assert(dueTimeSeconds >= 0.0);
499 // Enter timed event list critical section
500 Mutex::ScopedLock lock(&m_timedEventMutex);
503 unsigned long currentTimeMiliseconds = GetCurrentTimeMiliseconds();
505 // Convert to miliseconds
506 unsigned long dueTimeMiliseconds = static_cast<unsigned long>(1000.0 * dueTimeSeconds);
508 // Push new timed event
509 m_timedEventVector.push_back(InternalTimedEvent(event, userParam, dueTimeMiliseconds, currentTimeMiliseconds, eventDispatchProc, eventDeleteProc));
511 // Heapify timed events
512 std::make_heap(m_timedEventVector.begin(), m_timedEventVector.end());
515 m_timedEventInvoker.Signal();
517 LogPedantic("Timed event pushed and invoker signaled: due time: " << dueTimeMiliseconds << " ms, absolute due time: " << currentTimeMiliseconds + dueTimeMiliseconds << " ms");
520 Thread *Thread::GetInvokerThread()
525 void Thread::HandleDirectInvoker()
527 // We must be in ProcessEvents call stack
528 // Mark that situation to handle direct invoker
529 m_directInvoke = true;
532 void Thread::Sleep(uint64_t seconds)
534 NanoSleep(seconds * NANOSECONDS_PER_SECOND);
537 void Thread::MiliSleep(uint64_t miliseconds)
539 NanoSleep(miliseconds * NANOSECONDS_PER_MILISECOND);
542 void Thread::MicroSleep(uint64_t microseconds)
544 NanoSleep(microseconds * NANOSECONDS_PER_MICROSECOND);
547 void Thread::NanoSleep(uint64_t nanoseconds)
549 timespec requestedTime =
552 nanoseconds / NANOSECONDS_PER_SECOND),
555 nanoseconds % NANOSECONDS_PER_SECOND)
558 timespec remainingTime;
562 if (nanosleep(&requestedTime, &remainingTime) == 0)
566 Assert(error == EINTR);
568 requestedTime = remainingTime;