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 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)
119 LogDebug("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.");
132 // Do not allow exceptions to hit pthread core
133 UNHANDLED_EXCEPTION_HANDLER_BEGIN
137 UNHANDLED_EXCEPTION_HANDLER_END
141 // Leave running state
142 std::lock_guard<std::mutex> lock(This->m_stateMutex);
144 This->m_running = false;
147 if (This->m_abandon) {
148 LogDebug("Thread was abandoned");
149 This->m_thread.detach();
151 LogDebug("Thread is joinable");
158 int Thread::ThreadEntry()
160 LogDebug("Entered default thread entry");
164 void Thread::ProcessEvents()
166 LogDebug("Processing events");
168 // Steal current event list
169 InternalEventList stolenEvents;
171 // Enter event list critical section
173 std::lock_guard<std::mutex> lock(m_eventMutex);
174 m_eventList.swap(stolenEvents);
175 m_eventInvoker.Reset();
178 // Process event list
179 LogDebug("Stolen " << stolenEvents.size() << " internal events");
181 for (InternalEventList::iterator iterator = stolenEvents.begin();
182 iterator != stolenEvents.end();
185 // Dispatch immediate event
186 iterator->eventDispatchProc(iterator->event, iterator->userParam);
189 iterator->eventDeleteProc(iterator->event, iterator->userParam);
193 void Thread::ProcessTimedEvents()
195 // Critical section on timed events mutex
197 std::lock_guard<std::mutex> lock(m_timedEventMutex);
200 unsigned long currentTimeMiliseconds = GetCurrentTimeMiliseconds();
203 LogDebug("Processing timed events. Time now: " << currentTimeMiliseconds << " ms");
205 // All timed events are sorted chronologically
206 // Emit timed out events
207 while (!m_timedEventVector.empty() &&
208 currentTimeMiliseconds >=
209 m_timedEventVector.begin()->registerTimeMiliseconds +
210 m_timedEventVector.begin()->dueTimeMiliseconds)
213 LogDebug("Transforming timed event into immediate event. Absolute due time: " <<
214 (m_timedEventVector.begin()->registerTimeMiliseconds +
215 m_timedEventVector.begin()->dueTimeMiliseconds) << " ms");
217 // Emit immediate event
218 PushEvent(m_timedEventVector.begin()->event,
219 m_timedEventVector.begin()->eventDispatchProc,
220 m_timedEventVector.begin()->eventDeleteProc,
221 m_timedEventVector.begin()->userParam);
223 // Remove timed eventand fix heap
224 std::pop_heap(m_timedEventVector.begin(), m_timedEventVector.end());
225 m_timedEventVector.pop_back();
230 unsigned long Thread::GetCurrentTimeMiliseconds() const
233 gettimeofday(&tv, NULL);
234 return static_cast<unsigned long>(tv.tv_sec) * 1000 +
235 static_cast<unsigned long>(tv.tv_usec) / 1000;
240 LogDebug("Executing thread event processing");
242 const std::size_t MIN_HANDLE_LIST_SIZE = 4;
244 // Start processing of events
245 WaitableHandleListEx handleList;
247 // index 0: Quit waitable event handle
248 handleList.push_back(std::make_pair(m_quitEvent.GetHandle(), WaitMode::Read));
250 // index 1: Event occurred event handle
251 handleList.push_back(std::make_pair(m_eventInvoker.GetHandle(),
254 // index 2: Timed event occurred event handle
255 handleList.push_back(std::make_pair(m_timedEventInvoker.GetHandle(),
258 // index 3: Waitable handle watch support invoker
259 handleList.push_back(std::make_pair(WaitableHandleWatchSupport::
260 WaitableInvokerHandle(),
264 // Watch list might have been initialized before threaded started
265 // Need to fill waitable event watch list in this case
268 WaitableHandleListEx waitableHandleWatchHandles =
269 WaitableHandleWatchSupport::WaitableWatcherHandles();
271 waitableHandleWatchHandles.begin(),
272 waitableHandleWatchHandles.end(), std::back_inserter(handleList));
279 // Retrieve minimum wait time, according to timed events list
280 unsigned long minimumWaitTime;
282 // Critical section on timed events mutex
284 std::lock_guard<std::mutex> lock(m_timedEventMutex);
286 if (!m_timedEventVector.empty()) {
287 unsigned long currentTimeMiliseconds =
288 GetCurrentTimeMiliseconds();
289 unsigned long destinationTimeMiliseconds =
290 m_timedEventVector.begin()->registerTimeMiliseconds +
291 m_timedEventVector.begin()->dueTimeMiliseconds;
293 // Are we already late with timed event ?
294 if (currentTimeMiliseconds > destinationTimeMiliseconds) {
297 minimumWaitTime = destinationTimeMiliseconds -
298 currentTimeMiliseconds;
301 minimumWaitTime = 0xFFFFFFFF; // Infinity
306 LogDebug("Thread loop minimum wait time: " << minimumWaitTime << " ms");
309 WaitableHandleIndexList waitableHandleIndexList =
310 WaitForMultipleHandles(handleList, minimumWaitTime);
312 if (waitableHandleIndexList.empty()) {
313 // Timeout occurred. Process timed events.
314 LogDebug("Timed event list elapsed invoker");
315 ProcessTimedEvents();
319 // Go through each index
320 for (WaitableHandleIndexList::const_iterator
321 waitableHandleIndexIterator = waitableHandleIndexList.begin();
322 waitableHandleIndexIterator != waitableHandleIndexList.end();
323 ++waitableHandleIndexIterator)
325 size_t index = *waitableHandleIndexIterator;
327 LogDebug("Event loop triggered with index: " << index);
331 // Quit waitable event handle
336 // Event occurred event handle
339 // Handle direct invoker
340 if (m_directInvoke) {
341 m_directInvoke = false;
343 LogDebug("Handling direct invoker");
346 while (handleList.size() > MIN_HANDLE_LIST_SIZE) {
347 handleList.pop_back();
350 // Insert current waitable event handles instead
352 WaitableHandleListEx waitableHandleWatchHandles =
353 WaitableHandleWatchSupport::WaitableWatcherHandles();
355 waitableHandleWatchHandles.begin(),
356 waitableHandleWatchHandles.end(),
357 std::back_inserter(handleList));
365 // Timed event list changed
366 LogDebug("Timed event list changed invoker");
367 ProcessTimedEvents();
369 // Reset timed event invoker
370 m_timedEventInvoker.Reset();
376 // Waitable handle watch support invoker
377 LogDebug("Waitable handle watch invoker event occurred");
379 // First, remove all previous handles
380 while (handleList.size() > MIN_HANDLE_LIST_SIZE) {
381 handleList.pop_back();
384 // Insert current waitable event handles instead
386 WaitableHandleListEx waitableHandleWatchHandles =
387 WaitableHandleWatchSupport::WaitableWatcherHandles();
389 waitableHandleWatchHandles.begin(),
390 waitableHandleWatchHandles.end(),
391 std::back_inserter(handleList));
394 // Handle invoker in waitable watch support
395 WaitableHandleWatchSupport::InvokerFinished();
397 LogDebug("Waitable handle watch invoker event handled");
403 // Waitable event watch list
404 LogDebug("Waitable handle watch event occurred");
406 // Handle event in waitable handle watch
408 std::pair<WaitableHandle,
409 WaitMode::Type> handle = handleList[index];
410 WaitableHandleWatchSupport::HandleWatcher(handle.first,
414 if (m_directInvoke) {
415 m_directInvoke = false;
417 LogDebug("Handling direct invoker");
420 while (handleList.size() > MIN_HANDLE_LIST_SIZE) {
421 handleList.pop_back();
424 // Insert current waitable event handles instead
426 WaitableHandleListEx waitableHandleWatchHandles =
427 WaitableHandleWatchSupport::
428 WaitableWatcherHandles();
429 std::copy(waitableHandleWatchHandles.begin(),
430 waitableHandleWatchHandles.end(),
431 std::back_inserter(handleList));
435 LogDebug("Waitable handle watch event handled");
443 LogDebug("Leaving thread event processing");
449 LogDebug("Running thread");
453 std::lock_guard<std::mutex> lock(m_stateMutex);
460 m_thread = std::thread(StaticThreadEntry,this);
461 }catch(std::system_error e){
462 Throw(Exception::RunFailed);
465 // At default, we abandon thread
468 // Enter running state
472 LogDebug("Thread run");
479 std::lock_guard<std::mutex> lock(m_stateMutex);
481 // Is thread running ?
486 LogDebug("Quitting thread...");
488 // Do not abandon thread, we will join
491 // Singal quit waitable event
492 m_quitEvent.Signal();
497 }catch(std::system_error e){
498 Throw(Exception::QuitFailed);
501 LogDebug("Thread quit");
504 void Thread::PushEvent(void *event,
505 EventDispatchProc eventDispatchProc,
506 EventDeleteProc eventDeleteProc,
509 // Enter event list critical section
510 std::lock_guard<std::mutex> lock(m_eventMutex);
513 m_eventList.push_back(InternalEvent(event, userParam, eventDispatchProc,
517 m_eventInvoker.Signal();
519 LogDebug("Event pushed and invoker signaled");
522 void Thread::PushTimedEvent(void *event,
523 double dueTimeSeconds,
524 EventDispatchProc eventDispatchProc,
525 EventDeleteProc eventDeleteProc,
528 // Check for developer errors
529 Assert(dueTimeSeconds >= 0.0);
531 // Enter timed event list critical section
532 std::lock_guard<std::mutex> lock(m_timedEventMutex);
535 unsigned long currentTimeMiliseconds = GetCurrentTimeMiliseconds();
537 // Convert to miliseconds
538 unsigned long dueTimeMiliseconds =
539 static_cast<unsigned long>(1000.0 * dueTimeSeconds);
541 // Push new timed event
542 m_timedEventVector.push_back(InternalTimedEvent(event, userParam,
544 currentTimeMiliseconds,
548 // Heapify timed events
549 std::make_heap(m_timedEventVector.begin(), m_timedEventVector.end());
552 m_timedEventInvoker.Signal();
554 LogDebug("Timed event pushed and invoker signaled: "
555 "due time: " << dueTimeMiliseconds << " ms, absolute due time: " <<
556 (currentTimeMiliseconds + dueTimeMiliseconds) << " ms");
559 Thread *Thread::GetInvokerThread()
564 void Thread::HandleDirectInvoker()
566 // We must be in ProcessEvents call stack
567 // Mark that situation to handle direct invoker
568 m_directInvoke = true;
571 void Thread::Sleep(uint64_t seconds)
573 NanoSleep(seconds * NANOSECONDS_PER_SECOND);
576 void Thread::MiliSleep(uint64_t miliseconds)
578 NanoSleep(miliseconds * NANOSECONDS_PER_MILISECOND);
581 void Thread::MicroSleep(uint64_t microseconds)
583 NanoSleep(microseconds * NANOSECONDS_PER_MICROSECOND);
586 void Thread::NanoSleep(uint64_t nanoseconds)
588 timespec requestedTime = {
590 nanoseconds / NANOSECONDS_PER_SECOND),
593 nanoseconds % NANOSECONDS_PER_SECOND)
596 timespec remainingTime;
599 if (nanosleep(&requestedTime, &remainingTime) == 0) {
604 Assert(error == EINTR);
606 requestedTime = remainingTime;
609 } // namespace VcoreDPL