• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2010 Apple Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
14  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23  * THE POSSIBILITY OF SUCH DAMAGE.
24  */
25 
26 #include "config.h"
27 #include "WorkQueue.h"
28 
29 #include <mach/mach_port.h>
30 #include <wtf/PassOwnPtr.h>
31 
32 #if HAVE(DISPATCH_H)
33 
executeWorkItem(void * item)34 void WorkQueue::executeWorkItem(void* item)
35 {
36     WorkQueue* queue = static_cast<WorkQueue*>(dispatch_get_context(dispatch_get_current_queue()));
37     OwnPtr<WorkItem> workItem(static_cast<WorkItem*>(item));
38 
39     {
40         MutexLocker locker(queue->m_isValidMutex);
41         if (!queue->m_isValid)
42             return;
43     }
44 
45     workItem->execute();
46 }
47 
scheduleWork(PassOwnPtr<WorkItem> item)48 void WorkQueue::scheduleWork(PassOwnPtr<WorkItem> item)
49 {
50     dispatch_async_f(m_dispatchQueue, item.leakPtr(), executeWorkItem);
51 }
52 
scheduleWorkAfterDelay(PassOwnPtr<WorkItem> item,double delay)53 void WorkQueue::scheduleWorkAfterDelay(PassOwnPtr<WorkItem> item, double delay)
54 {
55     dispatch_time_t delayTime = dispatch_time(DISPATCH_TIME_NOW, delay * NSEC_PER_SEC);
56 
57     dispatch_after_f(delayTime, m_dispatchQueue, item.leakPtr(), executeWorkItem);
58 }
59 
60 class WorkQueue::EventSource {
61 public:
EventSource(MachPortEventType eventType,dispatch_source_t dispatchSource,PassOwnPtr<WorkItem> workItem)62     EventSource(MachPortEventType eventType, dispatch_source_t dispatchSource, PassOwnPtr<WorkItem> workItem)
63         : m_eventType(eventType)
64         , m_dispatchSource(dispatchSource)
65         , m_workItem(workItem)
66     {
67     }
68 
dispatchSource() const69     dispatch_source_t dispatchSource() const { return m_dispatchSource; }
70 
eventHandler(void * source)71     static void eventHandler(void* source)
72     {
73         EventSource* eventSource = static_cast<EventSource*>(source);
74 
75         eventSource->m_workItem->execute();
76     }
77 
cancelHandler(void * source)78     static void cancelHandler(void* source)
79     {
80         EventSource* eventSource = static_cast<EventSource*>(source);
81 
82         mach_port_t machPort = dispatch_source_get_handle(eventSource->m_dispatchSource);
83 
84         switch (eventSource->m_eventType) {
85         case MachPortDataAvailable:
86             // Release our receive right.
87             mach_port_mod_refs(mach_task_self(), machPort, MACH_PORT_RIGHT_RECEIVE, -1);
88             break;
89         case MachPortDeadNameNotification:
90             // Release our send right.
91             mach_port_deallocate(mach_task_self(), machPort);
92             break;
93         }
94     }
95 
finalizeHandler(void * source)96     static void finalizeHandler(void* source)
97     {
98         EventSource* eventSource = static_cast<EventSource*>(source);
99 
100         delete eventSource;
101     }
102 
103 private:
104     MachPortEventType m_eventType;
105 
106     // This is a weak reference, since m_dispatchSource references the event source.
107     dispatch_source_t m_dispatchSource;
108 
109     OwnPtr<WorkItem> m_workItem;
110 };
111 
registerMachPortEventHandler(mach_port_t machPort,MachPortEventType eventType,PassOwnPtr<WorkItem> workItem)112 void WorkQueue::registerMachPortEventHandler(mach_port_t machPort, MachPortEventType eventType, PassOwnPtr<WorkItem> workItem)
113 {
114     dispatch_source_type_t sourceType = 0;
115     switch (eventType) {
116     case MachPortDataAvailable:
117         sourceType = DISPATCH_SOURCE_TYPE_MACH_RECV;
118         break;
119     case MachPortDeadNameNotification:
120         sourceType = DISPATCH_SOURCE_TYPE_MACH_SEND;
121         break;
122     }
123 
124     dispatch_source_t dispatchSource = dispatch_source_create(sourceType, machPort, 0, m_dispatchQueue);
125 
126     EventSource* eventSource = new EventSource(eventType, dispatchSource, workItem);
127     dispatch_set_context(dispatchSource, eventSource);
128 
129     dispatch_source_set_event_handler_f(dispatchSource, &EventSource::eventHandler);
130     dispatch_source_set_cancel_handler_f(dispatchSource, &EventSource::cancelHandler);
131     dispatch_set_finalizer_f(dispatchSource, &EventSource::finalizeHandler);
132 
133     // Add the source to our set of sources.
134     {
135         MutexLocker locker(m_eventSourcesMutex);
136 
137         ASSERT(!m_eventSources.contains(machPort));
138 
139         m_eventSources.set(machPort, eventSource);
140 
141         // And start it!
142         dispatch_resume(dispatchSource);
143     }
144 }
145 
unregisterMachPortEventHandler(mach_port_t machPort)146 void WorkQueue::unregisterMachPortEventHandler(mach_port_t machPort)
147 {
148     ASSERT(machPort);
149 
150     MutexLocker locker(m_eventSourcesMutex);
151 
152     HashMap<mach_port_t, EventSource*>::iterator it = m_eventSources.find(machPort);
153     ASSERT(it != m_eventSources.end());
154 
155     ASSERT(m_eventSources.contains(machPort));
156 
157     EventSource* eventSource = it->second;
158     // Cancel and release the source. It will be deleted in its finalize handler.
159     dispatch_source_cancel(eventSource->dispatchSource());
160     dispatch_release(eventSource->dispatchSource());
161 
162     m_eventSources.remove(it);
163 }
164 
platformInitialize(const char * name)165 void WorkQueue::platformInitialize(const char* name)
166 {
167     m_dispatchQueue = dispatch_queue_create(name, 0);
168     dispatch_set_context(m_dispatchQueue, this);
169 }
170 
platformInvalidate()171 void WorkQueue::platformInvalidate()
172 {
173 #if !ASSERT_DISABLED
174     MutexLocker locker(m_eventSourcesMutex);
175     ASSERT(m_eventSources.isEmpty());
176 #endif
177 
178     dispatch_release(m_dispatchQueue);
179 }
180 
181 #else /* !HAVE(DISPATCH_H) */
182 
scheduleWork(PassOwnPtr<WorkItem> item)183 void WorkQueue::scheduleWork(PassOwnPtr<WorkItem> item)
184 {
185 }
186 
registerMachPortEventHandler(mach_port_t,MachPortEventType,PassOwnPtr<WorkItem>)187 void WorkQueue::registerMachPortEventHandler(mach_port_t, MachPortEventType, PassOwnPtr<WorkItem>)
188 {
189 }
190 
unregisterMachPortEventHandler(mach_port_t)191 void WorkQueue::unregisterMachPortEventHandler(mach_port_t)
192 {
193 }
194 
platformInitialize(const char *)195 void WorkQueue::platformInitialize(const char*)
196 {
197 }
198 
platformInvalidate()199 void WorkQueue::platformInvalidate()
200 {
201 }
202 
203 #endif
204