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 PLATFORM(MAC)
31#if HAVE(DISPATCH_H)
32#include <dispatch/dispatch.h>
33#endif
34#endif
35
36#include "WorkItem.h"
37#include <wtf/HashMap.h>
38#include <wtf/PassOwnPtr.h>
39#include <wtf/RefCounted.h>
40#include <wtf/Threading.h>
41#include <wtf/Vector.h>
42
43#if PLATFORM(QT)
44#include <QSocketNotifier>
45#include "PlatformProcessIdentifier.h"
46class QObject;
47class QThread;
48#elif PLATFORM(GTK)
49#include "PlatformProcessIdentifier.h"
50typedef struct _GMainContext GMainContext;
51typedef struct _GMainLoop GMainLoop;
52typedef gboolean (*GSourceFunc) (gpointer data);
53#endif
54
55class WorkQueue {
56    WTF_MAKE_NONCOPYABLE(WorkQueue);
57
58public:
59    explicit WorkQueue(const char* name);
60    ~WorkQueue();
61
62    // Will schedule the given work item to run as soon as possible.
63    void scheduleWork(PassOwnPtr<WorkItem>);
64
65    // Will schedule the given work item to run after the given delay (in seconds).
66    void scheduleWorkAfterDelay(PassOwnPtr<WorkItem>, double delay);
67
68    void invalidate();
69
70#if PLATFORM(MAC)
71    enum MachPortEventType {
72        // Fired when there is data on the given receive right.
73        MachPortDataAvailable,
74
75        // Fired when the receive right for this send right has been destroyed.
76        MachPortDeadNameNotification
77    };
78
79    // Will execute the given work item whenever the given mach port event fires.
80    // Note that this will adopt the mach port and destroy it when the work queue is invalidated.
81    void registerMachPortEventHandler(mach_port_t, MachPortEventType, PassOwnPtr<WorkItem>);
82    void unregisterMachPortEventHandler(mach_port_t);
83#elif PLATFORM(WIN)
84    void registerHandle(HANDLE, PassOwnPtr<WorkItem>);
85    void unregisterAndCloseHandle(HANDLE);
86#elif PLATFORM(QT)
87    QSocketNotifier* registerSocketEventHandler(int, QSocketNotifier::Type, PassOwnPtr<WorkItem>);
88    void scheduleWorkOnTermination(WebKit::PlatformProcessIdentifier, PassOwnPtr<WorkItem>);
89#elif PLATFORM(GTK)
90    void registerEventSourceHandler(int, int, PassOwnPtr<WorkItem>);
91    void unregisterEventSourceHandler(int);
92    void scheduleWorkOnTermination(WebKit::PlatformProcessIdentifier, PassOwnPtr<WorkItem>);
93#endif
94
95private:
96    // FIXME: Use an atomic boolean here instead.
97    Mutex m_isValidMutex;
98    bool m_isValid;
99
100    void platformInitialize(const char* name);
101    void platformInvalidate();
102
103#if PLATFORM(MAC)
104#if HAVE(DISPATCH_H)
105    static void executeWorkItem(void*);
106    Mutex m_eventSourcesMutex;
107    class EventSource;
108    HashMap<mach_port_t, EventSource*> m_eventSources;
109    dispatch_queue_t m_dispatchQueue;
110#endif
111#elif PLATFORM(WIN)
112    class WorkItemWin : public ThreadSafeRefCounted<WorkItemWin> {
113    public:
114        static PassRefPtr<WorkItemWin> create(PassOwnPtr<WorkItem>, WorkQueue*);
115        virtual ~WorkItemWin();
116
117        WorkItem* item() const { return m_item.get(); }
118        WorkQueue* queue() const { return m_queue; }
119
120    protected:
121        WorkItemWin(PassOwnPtr<WorkItem>, WorkQueue*);
122
123    private:
124        OwnPtr<WorkItem> m_item;
125        WorkQueue* m_queue;
126    };
127
128    class HandleWorkItem : public WorkItemWin {
129    public:
130        static PassRefPtr<HandleWorkItem> createByAdoptingHandle(HANDLE, PassOwnPtr<WorkItem>, WorkQueue*);
131        virtual ~HandleWorkItem();
132
133        void setWaitHandle(HANDLE waitHandle) { m_waitHandle = waitHandle; }
134        HANDLE waitHandle() const { return m_waitHandle; }
135
136    private:
137        HandleWorkItem(HANDLE, PassOwnPtr<WorkItem>, WorkQueue*);
138
139        HANDLE m_handle;
140        HANDLE m_waitHandle;
141    };
142
143    static void CALLBACK handleCallback(void* context, BOOLEAN timerOrWaitFired);
144    static void CALLBACK timerCallback(void* context, BOOLEAN timerOrWaitFired);
145    static DWORD WINAPI workThreadCallback(void* context);
146
147    bool tryRegisterAsWorkThread();
148    void unregisterAsWorkThread();
149    void performWorkOnRegisteredWorkThread();
150
151    static void unregisterWaitAndDestroyItemSoon(PassRefPtr<HandleWorkItem>);
152    static DWORD WINAPI unregisterWaitAndDestroyItemCallback(void* context);
153
154    volatile LONG m_isWorkThreadRegistered;
155
156    Mutex m_workItemQueueLock;
157    Vector<RefPtr<WorkItemWin> > m_workItemQueue;
158
159    Mutex m_handlesLock;
160    HashMap<HANDLE, RefPtr<HandleWorkItem> > m_handles;
161
162    HANDLE m_timerQueue;
163#elif PLATFORM(QT)
164    class WorkItemQt;
165    HashMap<QObject*, WorkItemQt*> m_signalListeners;
166    QThread* m_workThread;
167    friend class WorkItemQt;
168#elif PLATFORM(GTK)
169    static void* startWorkQueueThread(WorkQueue*);
170    void workQueueThreadBody();
171    void scheduleWorkOnSource(GSource*, PassOwnPtr<WorkItem>, GSourceFunc);
172
173    ThreadIdentifier m_workQueueThread;
174    GMainContext* m_eventContext;
175    Mutex m_eventLoopLock;
176    GMainLoop* m_eventLoop;
177    Mutex m_eventSourcesLock;
178    class EventSource;
179    HashMap<int, Vector<EventSource*> > m_eventSources;
180    typedef HashMap<int, Vector<EventSource*> >::iterator EventSourceIterator;
181#endif
182};
183
184#endif // WorkQueue_h
185