/* * Copyright (C) 2010 Apple Inc. All rights reserved. * Portions Copyright (c) 2010 Motorola Mobility, Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef WorkQueue_h #define WorkQueue_h #if PLATFORM(MAC) #if HAVE(DISPATCH_H) #include <dispatch/dispatch.h> #endif #endif #include "WorkItem.h" #include <wtf/HashMap.h> #include <wtf/PassOwnPtr.h> #include <wtf/RefCounted.h> #include <wtf/Threading.h> #include <wtf/Vector.h> #if PLATFORM(QT) #include <QSocketNotifier> #include "PlatformProcessIdentifier.h" class QObject; class QThread; #elif PLATFORM(GTK) #include "PlatformProcessIdentifier.h" typedef struct _GMainContext GMainContext; typedef struct _GMainLoop GMainLoop; typedef gboolean (*GSourceFunc) (gpointer data); #endif class WorkQueue { WTF_MAKE_NONCOPYABLE(WorkQueue); public: explicit WorkQueue(const char* name); ~WorkQueue(); // Will schedule the given work item to run as soon as possible. void scheduleWork(PassOwnPtr<WorkItem>); // Will schedule the given work item to run after the given delay (in seconds). void scheduleWorkAfterDelay(PassOwnPtr<WorkItem>, double delay); void invalidate(); #if PLATFORM(MAC) enum MachPortEventType { // Fired when there is data on the given receive right. MachPortDataAvailable, // Fired when the receive right for this send right has been destroyed. MachPortDeadNameNotification }; // Will execute the given work item whenever the given mach port event fires. // Note that this will adopt the mach port and destroy it when the work queue is invalidated. void registerMachPortEventHandler(mach_port_t, MachPortEventType, PassOwnPtr<WorkItem>); void unregisterMachPortEventHandler(mach_port_t); #elif PLATFORM(WIN) void registerHandle(HANDLE, PassOwnPtr<WorkItem>); void unregisterAndCloseHandle(HANDLE); #elif PLATFORM(QT) QSocketNotifier* registerSocketEventHandler(int, QSocketNotifier::Type, PassOwnPtr<WorkItem>); void scheduleWorkOnTermination(WebKit::PlatformProcessIdentifier, PassOwnPtr<WorkItem>); #elif PLATFORM(GTK) void registerEventSourceHandler(int, int, PassOwnPtr<WorkItem>); void unregisterEventSourceHandler(int); void scheduleWorkOnTermination(WebKit::PlatformProcessIdentifier, PassOwnPtr<WorkItem>); #endif private: // FIXME: Use an atomic boolean here instead. Mutex m_isValidMutex; bool m_isValid; void platformInitialize(const char* name); void platformInvalidate(); #if PLATFORM(MAC) #if HAVE(DISPATCH_H) static void executeWorkItem(void*); Mutex m_eventSourcesMutex; class EventSource; HashMap<mach_port_t, EventSource*> m_eventSources; dispatch_queue_t m_dispatchQueue; #endif #elif PLATFORM(WIN) class WorkItemWin : public ThreadSafeRefCounted<WorkItemWin> { public: static PassRefPtr<WorkItemWin> create(PassOwnPtr<WorkItem>, WorkQueue*); virtual ~WorkItemWin(); WorkItem* item() const { return m_item.get(); } WorkQueue* queue() const { return m_queue; } protected: WorkItemWin(PassOwnPtr<WorkItem>, WorkQueue*); private: OwnPtr<WorkItem> m_item; WorkQueue* m_queue; }; class HandleWorkItem : public WorkItemWin { public: static PassRefPtr<HandleWorkItem> createByAdoptingHandle(HANDLE, PassOwnPtr<WorkItem>, WorkQueue*); virtual ~HandleWorkItem(); void setWaitHandle(HANDLE waitHandle) { m_waitHandle = waitHandle; } HANDLE waitHandle() const { return m_waitHandle; } private: HandleWorkItem(HANDLE, PassOwnPtr<WorkItem>, WorkQueue*); HANDLE m_handle; HANDLE m_waitHandle; }; static void CALLBACK handleCallback(void* context, BOOLEAN timerOrWaitFired); static void CALLBACK timerCallback(void* context, BOOLEAN timerOrWaitFired); static DWORD WINAPI workThreadCallback(void* context); bool tryRegisterAsWorkThread(); void unregisterAsWorkThread(); void performWorkOnRegisteredWorkThread(); static void unregisterWaitAndDestroyItemSoon(PassRefPtr<HandleWorkItem>); static DWORD WINAPI unregisterWaitAndDestroyItemCallback(void* context); volatile LONG m_isWorkThreadRegistered; Mutex m_workItemQueueLock; Vector<RefPtr<WorkItemWin> > m_workItemQueue; Mutex m_handlesLock; HashMap<HANDLE, RefPtr<HandleWorkItem> > m_handles; HANDLE m_timerQueue; #elif PLATFORM(QT) class WorkItemQt; HashMap<QObject*, WorkItemQt*> m_signalListeners; QThread* m_workThread; friend class WorkItemQt; #elif PLATFORM(GTK) static void* startWorkQueueThread(WorkQueue*); void workQueueThreadBody(); void scheduleWorkOnSource(GSource*, PassOwnPtr<WorkItem>, GSourceFunc); ThreadIdentifier m_workQueueThread; GMainContext* m_eventContext; Mutex m_eventLoopLock; GMainLoop* m_eventLoop; Mutex m_eventSourcesLock; class EventSource; HashMap<int, Vector<EventSource*> > m_eventSources; typedef HashMap<int, Vector<EventSource*> >::iterator EventSourceIterator; #endif }; #endif // WorkQueue_h