[EFL][WK2] Add RunLoopEfl and WorkQueueEfl
[WebKit-https.git] / Source / WebKit2 / Platform / efl / WorkQueueEfl.cpp
1 /*
2     Copyright (C) 2012 Samsung Electronics
3
4     This library is free software; you can redistribute it and/or
5     modify it under the terms of the GNU Library General Public
6     License as published by the Free Software Foundation; either
7     version 2 of the License, or (at your option) any later version.
8
9     This library is distributed in the hope that it will be useful,
10     but WITHOUT ANY WARRANTY; without even the implied warranty of
11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12     Library General Public License for more details.
13
14     You should have received a copy of the GNU Library General Public License
15     along with this library; see the file COPYING.LIB.  If not, write to
16     the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17     Boston, MA 02110-1301, USA.
18  */
19
20 #include "config.h"
21 #include "WorkQueue.h"
22
23 #include <wtf/Assertions.h>
24
25 class TimerWorkItem {
26 public:
27     TimerWorkItem(int timerID, const Function<void()>& function, WorkQueue* queue)
28         : m_function(function)
29         , m_queue(queue)
30         , m_timerID(timerID)
31     {
32     }
33     ~TimerWorkItem() { }
34
35     Function<void()> function() const { return m_function; }
36     WorkQueue* queue() const { return m_queue; }
37
38     int timerID() const { return m_timerID; }
39
40 private:
41     Function<void()> m_function;
42     WorkQueue* m_queue;
43     int m_timerID;
44 };
45
46 static const int invalidSocketDescriptor = -1;
47 static const int threadMessageSize = 1;
48 static const char finishThreadMessage[] = "F";
49 static const char wakupThreadMessage[] = "W";
50
51 void WorkQueue::platformInitialize(const char* name)
52 {
53     int fds[2];
54     if (pipe(fds))
55         ASSERT_NOT_REACHED();
56
57     m_readFromPipeDescriptor = fds[0];
58     m_writeToPipeDescriptor = fds[1];
59     FD_ZERO(&m_fileDescriptorSet);
60     FD_SET(m_readFromPipeDescriptor, &m_fileDescriptorSet);
61     m_maxFileDescriptor = m_readFromPipeDescriptor;
62
63     m_socketDescriptor = invalidSocketDescriptor;
64
65     m_threadLoop = true;
66     createThread(reinterpret_cast<WTF::ThreadFunction>(&WorkQueue::workQueueThread), this, name);
67 }
68
69 void WorkQueue::platformInvalidate()
70 {
71     sendMessageToThread(finishThreadMessage);
72 }
73
74 void WorkQueue::performWork()
75 {
76     m_workItemQueueLock.lock();
77
78     while (!m_workItemQueue.isEmpty()) {
79         Vector<Function<void()> > workItemQueue;
80         m_workItemQueue.swap(workItemQueue);
81
82         m_workItemQueueLock.unlock();
83         for (size_t i = 0; i < workItemQueue.size(); ++i)
84             workItemQueue[i]();
85         m_workItemQueueLock.lock();
86     }
87     m_workItemQueueLock.unlock();
88 }
89
90 void WorkQueue::performFileDescriptorWork()
91 {
92     fd_set readFileDescriptorSet = m_fileDescriptorSet;
93
94     if (select(m_maxFileDescriptor + 1, &readFileDescriptorSet, 0, 0, 0) >= 0) {
95         if (FD_ISSET(m_readFromPipeDescriptor, &readFileDescriptorSet)) {
96             char readBuf[threadMessageSize];
97             if (read(m_readFromPipeDescriptor, readBuf, threadMessageSize) == -1)
98                 LOG_ERROR("Failed to read from WorkQueueThread pipe");
99             if (!strncmp(readBuf, finishThreadMessage, threadMessageSize))
100                 m_threadLoop = false;
101         }
102
103         if (m_socketDescriptor != invalidSocketDescriptor && FD_ISSET(m_socketDescriptor, &readFileDescriptorSet))
104             m_socketEventHandler();
105     }
106 }
107
108 void WorkQueue::sendMessageToThread(const char* message)
109 {
110     if (write(m_writeToPipeDescriptor, message, threadMessageSize) == -1)
111         LOG_ERROR("Failed to wake up WorkQueue Thread");
112 }
113
114 void* WorkQueue::workQueueThread(WorkQueue* workQueue)
115 {
116     while (workQueue->m_threadLoop) {
117         workQueue->performWork();
118         workQueue->performFileDescriptorWork();
119     }
120
121     close(workQueue->m_readFromPipeDescriptor);
122     close(workQueue->m_writeToPipeDescriptor);
123
124     return 0;
125 }
126
127 void WorkQueue::registerSocketEventHandler(int fileDescriptor, const Function<void()>& function)
128 {
129     if (m_socketDescriptor != invalidSocketDescriptor)
130         LOG_ERROR("%d is already registerd.", fileDescriptor);
131
132     m_socketDescriptor = fileDescriptor;
133     m_socketEventHandler = function;
134
135     if (fileDescriptor > m_maxFileDescriptor)
136         m_maxFileDescriptor = fileDescriptor;
137     FD_SET(fileDescriptor, &m_fileDescriptorSet);
138 }
139
140 void WorkQueue::unregisterSocketEventHandler(int fileDescriptor)
141 {
142     m_socketDescriptor = invalidSocketDescriptor;
143
144     if (fileDescriptor == m_maxFileDescriptor)
145         m_maxFileDescriptor = m_readFromPipeDescriptor;
146     FD_CLR(fileDescriptor, &m_fileDescriptorSet);
147 }
148
149 void WorkQueue::dispatch(const Function<void()>& function)
150 {
151     MutexLocker locker(m_workItemQueueLock);
152     m_workItemQueue.append(function);
153     sendMessageToThread(wakupThreadMessage);
154 }
155
156 bool WorkQueue::timerFired(void* data)
157 {
158     TimerWorkItem* item = static_cast<TimerWorkItem*>(data);
159     if (item && item->queue()->m_isValid) {
160         item->queue()->dispatch(item->function());
161         item->queue()->m_timers.take(item->timerID());
162         delete item;
163     }
164
165     return ECORE_CALLBACK_CANCEL;
166 }
167
168 void WorkQueue::dispatchAfterDelay(const Function<void()>& function, double delay)
169 {
170     static int timerId = 0;
171     m_timers.set(timerId, adoptPtr(ecore_timer_add(delay, reinterpret_cast<Ecore_Task_Cb>(timerFired), new TimerWorkItem(timerId, function, this))));
172     timerId++;
173 }