Initialize Tizen 2.3
[framework/web/wrt-commons.git] / modules_mobile / core / src / thread.cpp
1 /*
2  * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved
3  *
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
7  *
8  *        http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  */
16 /*
17  * @file        thread.cpp
18  * @author      Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com)
19  * @version     1.0
20  * @brief       This file is the implementation file of thread
21  */
22 #include <stddef.h>
23 #include <dpl/thread.h>
24 #include <dpl/log/log.h>
25 #include <sys/time.h>
26 #include <algorithm>
27 #include <dpl/assert.h>
28 #include <errno.h>
29 #include <time.h>
30 #include <string.h>
31
32 namespace // anonymous
33 {
34 static const size_t NANOSECONDS_PER_SECOND =
35     static_cast<uint64_t>(1000 * 1000 * 1000);
36
37 static const size_t NANOSECONDS_PER_MILISECOND =
38     static_cast<uint64_t>(1000 * 1000);
39
40 static const size_t NANOSECONDS_PER_MICROSECOND =
41     static_cast<uint64_t>(1000);
42
43 static const pthread_t g_mainThread = pthread_self();
44
45 class ThreadSpecific
46 {
47   public:
48     pthread_key_t threadSpecific;
49
50     ThreadSpecific() :
51         threadSpecific(0)
52     {
53         threadSpecific = 0;
54         pthread_key_create(&threadSpecific, NULL);
55     }
56
57     virtual ~ThreadSpecific()
58     {
59         pthread_key_delete(threadSpecific);
60     }
61 };
62
63 static ThreadSpecific g_threadSpecific;
64 } // namespace anonymous
65
66 namespace DPL {
67 bool g_TLSforMainCreated = false;
68
69 Thread::Thread() :
70     m_thread(0),
71     m_abandon(false),
72     m_running(false),
73     m_directInvoke(false)
74 {}
75
76 Thread::~Thread()
77 {
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
82     Quit();
83
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();
88          ++iterator)
89     {
90         iterator->eventDeleteProc(iterator->event, iterator->userParam);
91     }
92
93     m_eventList.clear();
94 }
95
96 bool Thread::IsMainThread()
97 {
98     return (pthread_equal(pthread_self(), g_mainThread));
99 }
100
101 Thread *Thread::GetCurrentThread()
102 {
103     if (pthread_equal(pthread_self(), g_mainThread)) {
104         return NULL;
105     }
106
107     void *threadSpecific = pthread_getspecific(g_threadSpecific.threadSpecific);
108
109     // Is this a managed thread ?
110     if (threadSpecific == NULL) {
111         Throw(Exception::UnmanagedThread);
112     }
113
114     return static_cast<Thread *>(threadSpecific);
115 }
116
117 void *Thread::StaticThreadEntry(void *param)
118 {
119     LogPedantic("Entered static thread entry");
120
121     // Retrieve context
122     Thread *This = static_cast<Thread *>(param);
123     Assert(This != NULL);
124
125     // Set thread specific
126     int result = pthread_setspecific(g_threadSpecific.threadSpecific, This);
127
128     if (result != 0) {
129         LogError("Failed to set threadSpecific. Error: " << strerror(result));
130     }
131
132     // Enter thread proc
133     // Do not allow exceptions to hit pthread core
134     UNHANDLED_EXCEPTION_HANDLER_BEGIN
135     {
136         This->ThreadEntry();
137     }
138     UNHANDLED_EXCEPTION_HANDLER_END
139
140     // Critical section
141     {
142         // Leave running state
143         Mutex::ScopedLock lock(&This->m_stateMutex);
144
145         This->m_running = false;
146
147         // Abandon thread
148         if (This->m_abandon) {
149             LogPedantic("Thread was abandoned");
150             pthread_detach(This->m_thread);
151         } else {
152             LogPedantic("Thread is joinable");
153         }
154     }
155
156     return NULL;
157 }
158
159 int Thread::ThreadEntry()
160 {
161     LogPedantic("Entered default thread entry");
162     return Exec();
163 }
164
165 void Thread::ProcessEvents()
166 {
167     LogPedantic("Processing events");
168
169     // Steal current event list
170     InternalEventList stolenEvents;
171
172     // Enter event list critical section
173     {
174         Mutex::ScopedLock lock(&m_eventMutex);
175         m_eventList.swap(stolenEvents);
176         m_eventInvoker.Reset();
177     }
178
179     // Process event list
180     LogPedantic("Stolen " << stolenEvents.size() << " internal events");
181
182     for (InternalEventList::iterator iterator = stolenEvents.begin();
183          iterator != stolenEvents.end();
184          ++iterator)
185     {
186         // Dispatch immediate event
187         iterator->eventDispatchProc(iterator->event, iterator->userParam);
188
189         // Delete event
190         iterator->eventDeleteProc(iterator->event, iterator->userParam);
191     }
192 }
193
194 void Thread::ProcessTimedEvents()
195 {
196     // Critical section on timed events mutex
197     {
198         Mutex::ScopedLock lock(&m_timedEventMutex);
199
200         // Get current time
201         unsigned long currentTimeMiliseconds = GetCurrentTimeMiliseconds();
202
203         // Info
204         LogPedantic(
205             "Processing timed events. Time now: " << currentTimeMiliseconds <<
206             " ms");
207
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)
214         {
215             // Info
216             LogPedantic(
217                 "Transforming timed event into immediate event. Absolute due time: "
218                 <<
219                 (m_timedEventVector.begin()->registerTimeMiliseconds +
220                  m_timedEventVector.begin()->dueTimeMiliseconds) <<
221                 " ms");
222
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);
228
229             // Remove timed eventand fix heap
230             std::pop_heap(m_timedEventVector.begin(), m_timedEventVector.end());
231             m_timedEventVector.pop_back();
232         }
233     }
234 }
235
236 unsigned long Thread::GetCurrentTimeMiliseconds() const
237 {
238     timeval tv;
239     gettimeofday(&tv, NULL);
240     return static_cast<unsigned long>(tv.tv_sec) * 1000 +
241            static_cast<unsigned long>(tv.tv_usec) / 1000;
242 }
243
244 int Thread::Exec()
245 {
246     LogPedantic("Executing thread event processing");
247
248     const std::size_t MIN_HANDLE_LIST_SIZE = 4;
249
250     // Start processing of events
251     WaitableHandleListEx handleList;
252
253     // index 0: Quit waitable event handle
254     handleList.push_back(std::make_pair(m_quitEvent.GetHandle(), WaitMode::Read));
255
256     // index 1: Event occurred event handle
257     handleList.push_back(std::make_pair(m_eventInvoker.GetHandle(),
258                                         WaitMode::Read));
259
260     // index 2: Timed event occurred event handle
261     handleList.push_back(std::make_pair(m_timedEventInvoker.GetHandle(),
262                                         WaitMode::Read));
263
264     // index 3: Waitable handle watch support invoker
265     handleList.push_back(std::make_pair(WaitableHandleWatchSupport::
266                                             WaitableInvokerHandle(),
267                                         WaitMode::Read));
268
269     //
270     // Watch list might have been initialized before threaded started
271     // Need to fill waitable event watch list in this case
272     //
273     {
274         WaitableHandleListEx waitableHandleWatchHandles =
275             WaitableHandleWatchSupport::WaitableWatcherHandles();
276         std::copy(
277             waitableHandleWatchHandles.begin(),
278             waitableHandleWatchHandles.end(), std::back_inserter(handleList));
279     }
280
281     // Quit flag
282     bool quit = false;
283
284     while (!quit) {
285         // Retrieve minimum wait time, according to timed events list
286         unsigned long minimumWaitTime;
287
288         // Critical section on timed events mutex
289         {
290             Mutex::ScopedLock lock(&m_timedEventMutex);
291
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;
298
299                 // Are we already late with timed event ?
300                 if (currentTimeMiliseconds > destinationTimeMiliseconds) {
301                     minimumWaitTime = 0;
302                 } else {
303                     minimumWaitTime = destinationTimeMiliseconds -
304                         currentTimeMiliseconds;
305                 }
306             } else {
307                 minimumWaitTime = 0xFFFFFFFF; // Infinity
308             }
309         }
310
311         // Info
312         LogPedantic(
313             "Thread loop minimum wait time: " << minimumWaitTime << " ms");
314
315         // Do thread waiting
316         WaitableHandleIndexList waitableHandleIndexList =
317             WaitForMultipleHandles(handleList, minimumWaitTime);
318
319         if (waitableHandleIndexList.empty()) {
320             // Timeout occurred. Process timed events.
321             LogPedantic("Timed event list elapsed invoker");
322             ProcessTimedEvents();
323             continue;
324         }
325
326         // Go through each index
327         for (WaitableHandleIndexList::const_iterator
328              waitableHandleIndexIterator = waitableHandleIndexList.begin();
329              waitableHandleIndexIterator != waitableHandleIndexList.end();
330              ++waitableHandleIndexIterator)
331         {
332             size_t index = *waitableHandleIndexIterator;
333
334             LogPedantic("Event loop triggered with index: " << index);
335
336             switch (index) {
337             case 0:
338                 // Quit waitable event handle
339                 quit = true;
340                 break;
341
342             case 1:
343                 // Event occurred event handle
344                 ProcessEvents();
345
346                 // Handle direct invoker
347                 if (m_directInvoke) {
348                     m_directInvoke = false;
349
350                     LogPedantic("Handling direct invoker");
351
352                     // Update list
353                     while (handleList.size() > MIN_HANDLE_LIST_SIZE) {
354                         handleList.pop_back();
355                     }
356
357                     // Insert current waitable event handles instead
358                     {
359                         WaitableHandleListEx waitableHandleWatchHandles =
360                             WaitableHandleWatchSupport::WaitableWatcherHandles();
361                         std::copy(
362                             waitableHandleWatchHandles.begin(),
363                             waitableHandleWatchHandles.end(),
364                             std::back_inserter(handleList));
365                     }
366                 }
367
368                 // Done
369                 break;
370
371             case 2:
372                 // Timed event list changed
373                 LogPedantic("Timed event list changed invoker");
374                 ProcessTimedEvents();
375
376                 // Reset timed event invoker
377                 m_timedEventInvoker.Reset();
378
379                 // Done
380                 break;
381
382             case 3:
383                 // Waitable handle watch support invoker
384                 LogPedantic("Waitable handle watch invoker event occurred");
385
386                 // First, remove all previous handles
387                 while (handleList.size() > MIN_HANDLE_LIST_SIZE) {
388                     handleList.pop_back();
389                 }
390
391                 // Insert current waitable event handles instead
392                 {
393                     WaitableHandleListEx waitableHandleWatchHandles =
394                         WaitableHandleWatchSupport::WaitableWatcherHandles();
395                     std::copy(
396                         waitableHandleWatchHandles.begin(),
397                         waitableHandleWatchHandles.end(),
398                         std::back_inserter(handleList));
399                 }
400
401                 // Handle invoker in waitable watch support
402                 WaitableHandleWatchSupport::InvokerFinished();
403
404                 LogPedantic("Waitable handle watch invoker event handled");
405
406                 // Done
407                 break;
408
409             default:
410                 // Waitable event watch list
411                 LogPedantic("Waitable handle watch event occurred");
412
413                 // Handle event in waitable handle watch
414                 {
415                     std::pair<WaitableHandle,
416                               WaitMode::Type> handle = handleList[index];
417                     WaitableHandleWatchSupport::HandleWatcher(handle.first,
418                                                               handle.second);
419                 }
420
421                 if (m_directInvoke) {
422                     m_directInvoke = false;
423
424                     LogPedantic("Handling direct invoker");
425
426                     // Update list
427                     while (handleList.size() > MIN_HANDLE_LIST_SIZE) {
428                         handleList.pop_back();
429                     }
430
431                     // Insert current waitable event handles instead
432                     {
433                         WaitableHandleListEx waitableHandleWatchHandles =
434                             WaitableHandleWatchSupport::
435                                 WaitableWatcherHandles();
436                         std::copy(waitableHandleWatchHandles.begin(),
437                                   waitableHandleWatchHandles.end(),
438                                   std::back_inserter(handleList));
439                     }
440                 }
441
442                 LogPedantic("Waitable handle watch event handled");
443
444                 // Done
445                 break;
446             }
447         }
448     }
449
450     LogPedantic("Leaving thread event processing");
451     return 0;
452 }
453
454 void Thread::Run()
455 {
456     LogPedantic("Running thread");
457
458     // Critical section
459     {
460         Mutex::ScopedLock lock(&m_stateMutex);
461
462         if (m_running) {
463             return;
464         }
465
466         // Try to create new thread
467         if (pthread_create(&m_thread, NULL, &StaticThreadEntry, this) != 0) {
468             Throw(Exception::RunFailed);
469         }
470
471         // At default, we abandon thread
472         m_abandon = true;
473
474         // Enter running state
475         m_running = true;
476     }
477
478     LogPedantic("Thread run");
479 }
480
481 void Thread::Quit()
482 {
483     pthread_t joinableThread;
484
485     // Critical section
486     {
487         Mutex::ScopedLock lock(&m_stateMutex);
488
489         // Is thread running ?
490         if (!m_running) {
491             return;
492         }
493
494         LogPedantic("Quitting thread...");
495
496         // Do not abandon thread, we will join
497         m_abandon = false;
498
499         // Singal quit waitable event
500         m_quitEvent.Signal();
501
502         // Copy joinable thread identifier, because
503         // we are leaving critical section
504         joinableThread = m_thread;
505     }
506
507     // Wait for joinable thread
508     void *result;
509
510     if (pthread_join(joinableThread, &result) != 0) {
511         Throw(Exception::QuitFailed);
512     }
513
514     LogPedantic("Thread quit");
515 }
516
517 void Thread::PushEvent(void *event,
518                        EventDispatchProc eventDispatchProc,
519                        EventDeleteProc eventDeleteProc,
520                        void *userParam)
521 {
522     // Enter event list critical section
523     Mutex::ScopedLock lock(&m_eventMutex);
524
525     // Push new event
526     m_eventList.push_back(InternalEvent(event, userParam, eventDispatchProc,
527                                         eventDeleteProc));
528
529     // Trigger invoker
530     m_eventInvoker.Signal();
531
532     LogPedantic("Event pushed and invoker signaled");
533 }
534
535 void Thread::PushTimedEvent(void *event,
536                             double dueTimeSeconds,
537                             EventDispatchProc eventDispatchProc,
538                             EventDeleteProc eventDeleteProc,
539                             void *userParam)
540 {
541     // Check for developer errors
542     Assert(dueTimeSeconds >= 0.0);
543
544     // Enter timed event list critical section
545     Mutex::ScopedLock lock(&m_timedEventMutex);
546
547     // Get current time
548     unsigned long currentTimeMiliseconds = GetCurrentTimeMiliseconds();
549
550     // Convert to miliseconds
551     unsigned long dueTimeMiliseconds =
552         static_cast<unsigned long>(1000.0 * dueTimeSeconds);
553
554     // Push new timed event
555     m_timedEventVector.push_back(InternalTimedEvent(event, userParam,
556                                                     dueTimeMiliseconds,
557                                                     currentTimeMiliseconds,
558                                                     eventDispatchProc,
559                                                     eventDeleteProc));
560
561     // Heapify timed events
562     std::make_heap(m_timedEventVector.begin(), m_timedEventVector.end());
563
564     // Trigger invoker
565     m_timedEventInvoker.Signal();
566
567     LogPedantic(
568         "Timed event pushed and invoker signaled: due time: " <<
569         dueTimeMiliseconds << " ms, absolute due time: " <<
570         currentTimeMiliseconds + dueTimeMiliseconds << " ms");
571 }
572
573 Thread *Thread::GetInvokerThread()
574 {
575     return this;
576 }
577
578 void Thread::HandleDirectInvoker()
579 {
580     // We must be in ProcessEvents call stack
581     // Mark that situation to handle direct invoker
582     m_directInvoke = true;
583 }
584
585 void Thread::Sleep(uint64_t seconds)
586 {
587     NanoSleep(seconds * NANOSECONDS_PER_SECOND);
588 }
589
590 void Thread::MiliSleep(uint64_t miliseconds)
591 {
592     NanoSleep(miliseconds * NANOSECONDS_PER_MILISECOND);
593 }
594
595 void Thread::MicroSleep(uint64_t microseconds)
596 {
597     NanoSleep(microseconds * NANOSECONDS_PER_MICROSECOND);
598 }
599
600 void Thread::NanoSleep(uint64_t nanoseconds)
601 {
602     timespec requestedTime = {
603         static_cast<time_t>(
604             nanoseconds / NANOSECONDS_PER_SECOND),
605
606         static_cast<long>(
607             nanoseconds % NANOSECONDS_PER_SECOND)
608     };
609
610     timespec remainingTime;
611
612     for (;;) {
613         if (nanosleep(&requestedTime, &remainingTime) == 0) {
614             break;
615         }
616
617         int error = errno;
618         Assert(error == EINTR);
619
620         requestedTime = remainingTime;
621     }
622 }
623 } // namespace DPL