1/*
2 * Copyright (C) 2010 Apple Inc. All rights reserved.
3 * Portions Copyright (c) 2010 Motorola Mobility, Inc.  All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
15 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
16 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
18 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
19 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
20 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
21 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
22 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
23 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
24 * THE POSSIBILITY OF SUCH DAMAGE.
25 */
26
27#ifndef WorkQueue_h
28#define WorkQueue_h
29
30#if OS(DARWIN)
31#if HAVE(DISPATCH_H)
32#include <dispatch/dispatch.h>
33#endif
34#endif
35
36#include <wtf/Forward.h>
37#include <wtf/Functional.h>
38#include <wtf/HashMap.h>
39#include <wtf/PassOwnPtr.h>
40#include <wtf/RefCounted.h>
41#include <wtf/Threading.h>
42#include <wtf/Vector.h>
43
44#if (PLATFORM(QT) && !OS(DARWIN)) || PLATFORM(GTK) || PLATFORM(EFL)
45#include "PlatformProcessIdentifier.h"
46#endif
47
48#if PLATFORM(QT) && !OS(DARWIN)
49#include <QSocketNotifier>
50QT_BEGIN_NAMESPACE
51class QObject;
52class QThread;
53QT_END_NAMESPACE
54#elif PLATFORM(GTK)
55#include <wtf/gobject/GRefPtr.h>
56typedef gboolean (*GSourceFunc) (gpointer data);
57#elif PLATFORM(EFL)
58#include <Ecore.h>
59#endif
60
61class WorkQueue : public ThreadSafeRefCounted<WorkQueue> {
62public:
63    static PassRefPtr<WorkQueue> create(const char* name);
64    ~WorkQueue();
65
66    // Will dispatch the given function to run as soon as possible.
67    void dispatch(const Function<void()>&);
68
69    // Will dispatch the given function after the given delay (in seconds).
70    void dispatchAfterDelay(const Function<void()>&, double delay);
71
72#if OS(DARWIN)
73    dispatch_queue_t dispatchQueue() const { return m_dispatchQueue; }
74
75#elif OS(WINDOWS)
76    void registerHandle(HANDLE, const Function<void()>&);
77    void unregisterAndCloseHandle(HANDLE);
78#elif PLATFORM(QT)
79    QSocketNotifier* registerSocketEventHandler(int, QSocketNotifier::Type, const Function<void()>&);
80    void dispatchOnTermination(WebKit::PlatformProcessIdentifier, const Function<void()>&);
81#elif PLATFORM(GTK)
82    void registerSocketEventHandler(int, int, const Function<void()>& function, const Function<void()>& closeFunction);
83    void unregisterSocketEventHandler(int);
84    void dispatchOnTermination(WebKit::PlatformProcessIdentifier, const Function<void()>&);
85#elif PLATFORM(EFL)
86    void registerSocketEventHandler(int, const Function<void()>&);
87    void unregisterSocketEventHandler(int);
88#endif
89
90private:
91    explicit WorkQueue(const char* name);
92
93    void platformInitialize(const char* name);
94    void platformInvalidate();
95
96#if OS(DARWIN)
97    static void executeFunction(void*);
98    dispatch_queue_t m_dispatchQueue;
99#elif OS(WINDOWS)
100    class WorkItemWin : public ThreadSafeRefCounted<WorkItemWin> {
101    public:
102        static PassRefPtr<WorkItemWin> create(const Function<void()>&, WorkQueue*);
103        virtual ~WorkItemWin();
104
105        Function<void()>& function() { return m_function; }
106        WorkQueue* queue() const { return m_queue.get(); }
107
108    protected:
109        WorkItemWin(const Function<void()>&, WorkQueue*);
110
111    private:
112        Function<void()> m_function;
113        RefPtr<WorkQueue> m_queue;
114    };
115
116    class HandleWorkItem : public WorkItemWin {
117    public:
118        static PassRefPtr<HandleWorkItem> createByAdoptingHandle(HANDLE, const Function<void()>&, WorkQueue*);
119        virtual ~HandleWorkItem();
120
121        void setWaitHandle(HANDLE waitHandle) { m_waitHandle = waitHandle; }
122        HANDLE waitHandle() const { return m_waitHandle; }
123
124    private:
125        HandleWorkItem(HANDLE, const Function<void()>&, WorkQueue*);
126
127        HANDLE m_handle;
128        HANDLE m_waitHandle;
129    };
130
131    static void CALLBACK handleCallback(void* context, BOOLEAN timerOrWaitFired);
132    static void CALLBACK timerCallback(void* context, BOOLEAN timerOrWaitFired);
133    static DWORD WINAPI workThreadCallback(void* context);
134
135    bool tryRegisterAsWorkThread();
136    void unregisterAsWorkThread();
137    void performWorkOnRegisteredWorkThread();
138
139    static void unregisterWaitAndDestroyItemSoon(PassRefPtr<HandleWorkItem>);
140    static DWORD WINAPI unregisterWaitAndDestroyItemCallback(void* context);
141
142    volatile LONG m_isWorkThreadRegistered;
143
144    Mutex m_workItemQueueLock;
145    Vector<RefPtr<WorkItemWin>> m_workItemQueue;
146
147    Mutex m_handlesLock;
148    HashMap<HANDLE, RefPtr<HandleWorkItem>> m_handles;
149
150    HANDLE m_timerQueue;
151#elif PLATFORM(QT)
152    class WorkItemQt;
153    QThread* m_workThread;
154    friend class WorkItemQt;
155#elif PLATFORM(GTK)
156    static void startWorkQueueThread(WorkQueue*);
157    void workQueueThreadBody();
158    void dispatchOnSource(GSource*, const Function<void()>&, GSourceFunc);
159
160    ThreadIdentifier m_workQueueThread;
161    GRefPtr<GMainContext> m_eventContext;
162    Mutex m_eventLoopLock;
163    GRefPtr<GMainLoop> m_eventLoop;
164    Mutex m_eventSourcesLock;
165    class EventSource;
166    class SocketEventSource;
167    HashMap<int, Vector<SocketEventSource*>> m_eventSources;
168    typedef HashMap<int, Vector<SocketEventSource*>>::iterator SocketEventSourceIterator;
169#elif PLATFORM(EFL)
170    class TimerWorkItem {
171    public:
172        static PassOwnPtr<TimerWorkItem> create(Function<void()>, double expireTime);
173        void dispatch() { m_function(); }
174        double expireTime() const { return m_expireTime; }
175        bool expired(double currentTime) const { return currentTime >= m_expireTime; }
176
177    protected:
178        TimerWorkItem(Function<void()>, double expireTime);
179
180    private:
181        Function<void()> m_function;
182        double m_expireTime;
183    };
184
185    fd_set m_fileDescriptorSet;
186    int m_maxFileDescriptor;
187    int m_readFromPipeDescriptor;
188    int m_writeToPipeDescriptor;
189    Mutex m_writeToPipeDescriptorLock;
190
191    bool m_threadLoop;
192
193    Vector<Function<void()>> m_workItemQueue;
194    Mutex m_workItemQueueLock;
195
196    int m_socketDescriptor;
197    Function<void()> m_socketEventHandler;
198
199    Vector<OwnPtr<TimerWorkItem>> m_timerWorkItems;
200    Mutex m_timerWorkItemsLock;
201
202    void sendMessageToThread(const char*);
203    static void* workQueueThread(WorkQueue*);
204    void performWork();
205    void performFileDescriptorWork();
206    static double getCurrentTime();
207    struct timeval* getNextTimeOut();
208    void performTimerWork();
209    void insertTimerWorkItem(PassOwnPtr<TimerWorkItem>);
210#endif
211};
212
213#endif // WorkQueue_h
214