Source/WebKit2/ChangeLog

 12012-08-13 Byungwoo Lee <bw80.lee@samsung.com>
 2
 3 [EFL][WK2] WorkQueue::dispatchAfterDelay() doesn't work properly.
 4 https://bugs.webkit.org/show_bug.cgi?id=91179
 5
 6 Reviewed by NOBODY (OOPS!).
 7
 8 With WorkQueue::dispatchAfterDelay(), a function should be dispatched
 9 on the WorkQueue thread after the delay that specified. But because of
 10 the implementation of the dispatchAfterDelay() function that uses
 11 ecore timer for getting timer event, the function will be dispatched
 12 on the main run loop. (ecore timer is handled by the ecore main loop
 13 which runs on the main run loop, not on the WorkQueue thread)
 14 This patch uses timerfd to get timer event, instead of ecore timer.
 15
 16 * Platform/WorkQueue.h:
 17 (TimerWorkItem):
 18 (WorkQueue::TimerWorkItem::function):
 19 (WorkQueue::TimerWorkItem::timerFileDescriptor):
 20 (WorkQueue::TimerWorkItem::expireTime):
 21 (WorkQueue):
 22 * Platform/efl/WorkQueueEfl.cpp:
 23 (WorkQueue::TimerWorkItem::create):
 24 (WorkQueue::TimerWorkItem::TimerWorkItem):
 25 (WorkQueue::TimerWorkItem::~TimerWorkItem):
 26 (WorkQueue::TimerWorkItem::expired):
 27 (WorkQueue::performFileDescriptorWork):
 28 (WorkQueue::performTimerFileDescriptorWork):
 29 (WorkQueue::dispatchAfterDelay):
 30
1312012-08-13 Tom Sepez <tsepez@chromium.org>
232
333 [chromium] release FrameLoaderClientImpl::m_pluginWidget refptr upon Plugin Document detach.

Source/WebKit2/Platform/WorkQueue.h

@@private:
187187 HashMap<int, Vector<EventSource*> > m_eventSources;
188188 typedef HashMap<int, Vector<EventSource*> >::iterator EventSourceIterator;
189189#elif PLATFORM(EFL)
 190 class TimerWorkItem {
 191 public:
 192 static PassOwnPtr<TimerWorkItem> create(Function<void()>, double delay);
 193 ~TimerWorkItem();
 194 Function<void()> function() const { return m_function; }
 195 int timerFileDescriptor() const { return m_timerFileDescriptor; }
 196 double expireTime() const { return m_expireTime; }
 197
 198 protected:
 199 TimerWorkItem(Function<void()>, int timerFileDescriptor, double expireTime);
 200
 201 private:
 202 Function<void()> m_function;
 203 int m_timerFileDescriptor;
 204 double m_expireTime;
 205 };
 206
190207 fd_set m_fileDescriptorSet;
191208 int m_maxFileDescriptor;
192209 int m_readFromPipeDescriptor;

@@private:
199216 int m_socketDescriptor;
200217 Function<void()> m_socketEventHandler;
201218
202  HashMap<int, OwnPtr<Ecore_Timer> > m_timers;
 219 Vector<OwnPtr<TimerWorkItem> > m_timerWorkItems;
 220 Mutex m_timerWorkItemsLock;
203221
204222 void sendMessageToThread(const char*);
205223 static void* workQueueThread(WorkQueue*);
206224 void performWork();
207225 void performFileDescriptorWork();
208  static bool timerFired(void*);
 226 static bool timerFileDescriptorExpired(int timerFileDescriptor, fd_set* readFileDescriptorSet);
 227 void performTimerFileDescriptorWork(fd_set* readFileDescriptorSet);
209228#endif
210229};
211230

Source/WebKit2/Platform/efl/WorkQueueEfl.cpp

2020#include "config.h"
2121#include "WorkQueue.h"
2222
 23#include <sys/timerfd.h>
2324#include <wtf/Assertions.h>
2425
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  {
 26static const int invalidSocketDescriptor = -1;
 27static const int threadMessageSize = 1;
 28static const char finishThreadMessage[] = "F";
 29static const char wakupThreadMessage[] = "W";
 30
 31PassOwnPtr<WorkQueue::TimerWorkItem> WorkQueue::TimerWorkItem::create(Function<void()> function, double delay)
 32{
 33 if (delay < 0) {
 34 LOG_ERROR("delay should not be negative");
 35 return nullptr;
3236 }
33  ~TimerWorkItem() { }
3437
35  Function<void()> function() const { return m_function; }
36  WorkQueue* queue() const { return m_queue; }
 38 struct timespec currentTime;
 39 if (clock_gettime(CLOCK_MONOTONIC, &currentTime) == -1) {
 40 LOG_ERROR("Failed to get current time (%d)", errno);
 41 return nullptr;
 42 }
3743
38  int timerID() const { return m_timerID; }
 44 double current = currentTime.tv_sec + (static_cast<double>(currentTime.tv_nsec) / 1000000000);
 45 double expire = current + delay;
3946
40 private:
41  Function<void()> m_function;
42  WorkQueue* m_queue;
43  int m_timerID;
44 };
 47 struct itimerspec expireTime;
 48 expireTime.it_value.tv_sec = static_cast<time_t>(expire);
 49 expireTime.it_value.tv_nsec = static_cast<long>((expire - expireTime.it_value.tv_sec) * 1000000000);
 50 expireTime.it_interval.tv_sec = 0;
 51 expireTime.it_interval.tv_nsec = 0;
4552
46 static const int invalidSocketDescriptor = -1;
47 static const int threadMessageSize = 1;
48 static const char finishThreadMessage[] = "F";
49 static const char wakupThreadMessage[] = "W";
 53 int timerFileDescriptor;
 54 if ((timerFileDescriptor = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK)) < 0) {
 55 LOG_ERROR("Failed to create timerfd");
 56 return nullptr;
 57 }
 58
 59 if (timerfd_settime(timerFileDescriptor, TFD_TIMER_ABSTIME, &expireTime, 0) == -1) {
 60 LOG_ERROR("Failed to set timerfd(%d)", timerFileDescriptor);
 61 close(timerFileDescriptor);
 62 return nullptr;
 63 }
 64
 65 return adoptPtr(new TimerWorkItem(function, timerFileDescriptor, expire));
 66}
 67
 68WorkQueue::TimerWorkItem::TimerWorkItem(Function<void()> function, int timerFileDescriptor, double expireTime)
 69 : m_function(function)
 70 , m_timerFileDescriptor(timerFileDescriptor)
 71 , m_expireTime(expireTime)
 72{
 73}
 74
 75WorkQueue::TimerWorkItem::~TimerWorkItem()
 76{
 77 struct itimerspec timerValue;
 78 timerValue.it_value.tv_sec = 0;
 79 timerValue.it_value.tv_nsec = 0;
 80 timerValue.it_interval.tv_sec = 0;
 81 timerValue.it_interval.tv_nsec = 0;
 82
 83 if (m_timerFileDescriptor < 0)
 84 return;
 85
 86 if (timerfd_settime(m_timerFileDescriptor, 0, &timerValue, 0) == -1)
 87 LOG_ERROR("Failed to clear timerfd(%d)", m_timerFileDescriptor);
 88 close(m_timerFileDescriptor);
 89}
5090
5191void WorkQueue::platformInitialize(const char* name)
5292{

@@void WorkQueue::performFileDescriptorWork()
102142
103143 if (m_socketDescriptor != invalidSocketDescriptor && FD_ISSET(m_socketDescriptor, &readFileDescriptorSet))
104144 m_socketEventHandler();
 145
 146 performTimerFileDescriptorWork(&readFileDescriptorSet);
 147 }
 148}
 149
 150bool WorkQueue::timerFileDescriptorExpired(int timerFileDescriptor, fd_set* readFileDescriptorSet)
 151{
 152 if (timerFileDescriptor < 0 || !readFileDescriptorSet)
 153 return false;
 154
 155 if (!FD_ISSET(timerFileDescriptor, readFileDescriptorSet))
 156 return false;
 157
 158 int bytesRead;
 159 uint64_t expirations;
 160 if ((bytesRead = read(timerFileDescriptor, &expirations, sizeof(uint64_t))) != sizeof(uint64_t)) {
 161 if (bytesRead != -1)
 162 LOG_ERROR("timerfd(%d) read error", timerFileDescriptor);
 163 else if (errno != EAGAIN)
 164 LOG_ERROR("timerfd(%d) read error(%d)", timerFileDescriptor, errno);
 165 return false;
 166 }
 167
 168 return true;
 169}
 170
 171void WorkQueue::performTimerFileDescriptorWork(fd_set* readFileDescriptorSet)
 172{
 173 m_timerWorkItemsLock.lock();
 174 while (!m_timerWorkItems.isEmpty()) {
 175 Vector<OwnPtr<TimerWorkItem> > timerWorkItems;
 176 m_timerWorkItems.swap(timerWorkItems);
 177
 178 for (size_t i = 0; i < timerWorkItems.size(); ++i) {
 179 if (!timerFileDescriptorExpired(timerWorkItems[i]->timerFileDescriptor(), readFileDescriptorSet)) {
 180 m_timerWorkItems.append(timerWorkItems[i].release());
 181 continue;
 182 }
 183
 184 FD_CLR(timerWorkItems[i]->timerFileDescriptor(), &m_fileDescriptorSet);
 185
 186 m_timerWorkItemsLock.unlock();
 187 dispatch(timerWorkItems[i]->function());
 188 m_timerWorkItemsLock.lock();
 189 }
105190 }
 191 m_timerWorkItemsLock.unlock();
106192}
107193
108194void WorkQueue::sendMessageToThread(const char* message)

@@void WorkQueue::dispatch(const Function<void()>& function)
153239 sendMessageToThread(wakupThreadMessage);
154240}
155241
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 
168242void WorkQueue::dispatchAfterDelay(const Function<void()>& function, double delay)
169243{
170  static int timerId = 1;
171  m_timers.set(timerId, adoptPtr(ecore_timer_add(delay, reinterpret_cast<Ecore_Task_Cb>(timerFired), new TimerWorkItem(timerId, function, this))));
172  timerId++;
 244 MutexLocker locker(m_workItemQueueLock);
 245 OwnPtr<TimerWorkItem> timerWorkItem = TimerWorkItem::create(function, delay);
 246 if (!timerWorkItem)
 247 return;
 248
 249 FD_SET(timerWorkItem->timerFileDescriptor(), &m_fileDescriptorSet);
 250 size_t position = 0;
 251 for (; position < m_timerWorkItems.size(); position++)
 252 if (timerWorkItem->expireTime() < m_timerWorkItems[position]->expireTime())
 253 break;
 254 m_timerWorkItems.insert(position, timerWorkItem.release());
 255 sendMessageToThread(wakupThreadMessage);
173256}