]> git.saurik.com Git - apple/cf.git/blob - CFWindowsMessageQueue.c
bd1502dbe3572cf2593b18102f059e267a6dcf34
[apple/cf.git] / CFWindowsMessageQueue.c
1 /*
2 * Copyright (c) 2010 Apple Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24 /* CFWindowsMessageQueue.c
25 Copyright (c) 1999-2009, Apple Inc. All rights reserved.
26 Responsibility: Christopher Kane
27 */
28
29 #if DEPLOYMENT_TARGET_WINDOWS
30
31 #include "CFWindowsMessageQueue.h"
32 #include "CFInternal.h"
33
34 extern DWORD __CFRunLoopGetWindowsMessageQueueMask(CFRunLoopRef rl, CFStringRef mode);
35 extern void __CFRunLoopSetWindowsMessageQueueMask(CFRunLoopRef rl, DWORD mask, CFStringRef mode);
36
37 struct __CFWindowsMessageQueue {
38 CFRuntimeBase _base;
39 CFAllocatorRef _allocator;
40 CFSpinLock_t _lock;
41 DWORD _mask;
42 CFRunLoopSourceRef _source;
43 CFMutableArrayRef _runLoops;
44 };
45
46 /* Bit 3 in the base reserved bits is used for invalid state */
47
48 CF_INLINE Boolean __CFWindowsMessageQueueIsValid(CFWindowsMessageQueueRef wmq) {
49 return (Boolean)__CFBitfieldGetValue(((const CFRuntimeBase *)wmq)->_cfinfo[CF_INFO_BITS], 3, 3);
50 }
51
52 CF_INLINE void __CFWindowsMessageQueueSetValid(CFWindowsMessageQueueRef wmq) {
53 __CFBitfieldSetValue(((CFRuntimeBase *)wmq)->_cfinfo[CF_INFO_BITS], 3, 3, 1);
54 }
55
56 CF_INLINE void __CFWindowsMessageQueueUnsetValid(CFWindowsMessageQueueRef wmq) {
57 __CFBitfieldSetValue(((CFRuntimeBase *)wmq)->_cfinfo[CF_INFO_BITS], 3, 3, 0);
58 }
59
60 CF_INLINE void __CFWindowsMessageQueueLock(CFWindowsMessageQueueRef wmq) {
61 __CFSpinLock(&(wmq->_lock));
62 }
63
64 CF_INLINE void __CFWindowsMessageQueueUnlock(CFWindowsMessageQueueRef wmq) {
65 __CFSpinUnlock(&(wmq->_lock));
66 }
67
68 static Boolean __CFWindowsMessageQueueEqual(CFTypeRef cf1, CFTypeRef cf2) {
69 CFWindowsMessageQueueRef wmq1 = (CFWindowsMessageQueueRef)cf1;
70 CFWindowsMessageQueueRef wmq2 = (CFWindowsMessageQueueRef)cf2;
71 return (wmq1 == wmq2);
72 }
73
74 static CFHashCode __CFWindowsMessageQueueHash(CFTypeRef cf) {
75 CFWindowsMessageQueueRef wmq = (CFWindowsMessageQueueRef)cf;
76 return (CFHashCode)wmq;
77 }
78
79 static CFStringRef __CFWindowsMessageQueueCopyDescription(CFTypeRef cf) {
80 /* Some commentary, possibly as out of date as much of the rest of the file was
81 #warning CF: this and many other CopyDescription functions are probably
82 #warning CF: broken, in that some of these fields being printed out can
83 #warning CF: be NULL, when the object is in the invalid state
84 */
85 CFWindowsMessageQueueRef wmq = (CFWindowsMessageQueueRef)cf;
86 CFMutableStringRef result;
87 result = CFStringCreateMutable(CFGetAllocator(wmq), 0);
88 __CFWindowsMessageQueueLock(wmq);
89 /* More commentary, which we don't really need to see with every build
90 #warning CF: here, and probably everywhere with a per-instance lock,
91 #warning CF: the locked state will always be true because we lock,
92 #warning CF: and you cannot call description if the object is locked;
93 #warning CF: probably should not lock description, and call it unsafe
94 */
95 CFStringAppendFormat(result, NULL, CFSTR("<CFWindowsMessageQueue %p [%p]>{locked = %s, valid = %s, mask = 0x%x,\n run loops = %@}"), cf, CFGetAllocator(wmq), "unknown", (__CFWindowsMessageQueueIsValid(wmq) ? "Yes" : "No"), (UInt32)wmq->_mask, wmq->_runLoops);
96 __CFWindowsMessageQueueUnlock(wmq);
97 return result;
98 }
99
100 CFAllocatorRef __CFWindowsMessageQueueGetAllocator(CFTypeRef cf) {
101 CFWindowsMessageQueueRef wmq = (CFWindowsMessageQueueRef)cf;
102 return wmq->_allocator;
103 }
104
105 static void __CFWindowsMessageQueueDeallocate(CFTypeRef cf) {
106 CFWindowsMessageQueueRef wmq = (CFWindowsMessageQueueRef)cf;
107 CFAllocatorRef allocator = CFGetAllocator(wmq);
108 CFAllocatorDeallocate(allocator, wmq);
109 CFRelease(allocator);
110 }
111
112 static CFTypeID __kCFWindowsMessageQueueTypeID = _kCFRuntimeNotATypeID;
113
114 static const CFRuntimeClass __CFWindowsMessageQueueClass = {
115 0,
116 "CFWindowsMessageQueue",
117 NULL, // init
118 NULL, // copy
119 __CFWindowsMessageQueueDeallocate,
120 __CFWindowsMessageQueueEqual,
121 __CFWindowsMessageQueueHash,
122 NULL, //
123 __CFWindowsMessageQueueCopyDescription
124 };
125
126 __private_extern__ void __CFWindowsMessageQueueInitialize(void) {
127 __kCFWindowsMessageQueueTypeID = _CFRuntimeRegisterClass(&__CFWindowsMessageQueueClass);
128 }
129
130 CFTypeID CFWindowsMessageQueueGetTypeID(void) {
131 return __kCFWindowsMessageQueueTypeID;
132 }
133
134 CFWindowsMessageQueueRef CFWindowsMessageQueueCreate(CFAllocatorRef allocator, uint32_t mask) {
135 CFWindowsMessageQueueRef memory;
136 UInt32 size = sizeof(struct __CFWindowsMessageQueue) - sizeof(CFRuntimeBase);
137 memory = (CFWindowsMessageQueueRef)_CFRuntimeCreateInstance(allocator, __kCFWindowsMessageQueueTypeID, size, NULL);
138 if (NULL == memory) {
139 return NULL;
140 }
141 __CFWindowsMessageQueueSetValid(memory);
142
143 CF_SPINLOCK_INIT_FOR_STRUCTS(memory->_lock);
144 memory->_mask = (DWORD)mask;
145 memory->_source = NULL;
146 memory->_runLoops = CFArrayCreateMutable(allocator, 0, NULL);
147 return memory;
148 }
149
150 void CFWindowsMessageQueueInvalidate(CFWindowsMessageQueueRef wmq) {
151 __CFGenericValidateType(wmq, __kCFWindowsMessageQueueTypeID);
152 CFRetain(wmq);
153 __CFWindowsMessageQueueLock(wmq);
154 if (__CFWindowsMessageQueueIsValid(wmq)) {
155 SInt32 idx;
156 __CFWindowsMessageQueueUnsetValid(wmq);
157 for (idx = CFArrayGetCount(wmq->_runLoops); idx--;) {
158 CFRunLoopWakeUp((CFRunLoopRef)CFArrayGetValueAtIndex(wmq->_runLoops, idx));
159 }
160 CFRelease(wmq->_runLoops);
161 wmq->_runLoops = NULL;
162 if (NULL != wmq->_source) {
163 CFRunLoopSourceInvalidate(wmq->_source);
164 CFRelease(wmq->_source);
165 wmq->_source = NULL;
166 }
167 }
168 __CFWindowsMessageQueueUnlock(wmq);
169 CFRelease(wmq);
170 }
171
172 Boolean CFWindowsMessageQueueIsValid(CFWindowsMessageQueueRef wmq) {
173 __CFGenericValidateType(wmq, __kCFWindowsMessageQueueTypeID);
174 return __CFWindowsMessageQueueIsValid(wmq);
175 }
176
177 uint32_t CFWindowsMessageQueueGetMask(CFWindowsMessageQueueRef wmq) {
178 __CFGenericValidateType(wmq, __kCFWindowsMessageQueueTypeID);
179 return wmq->_mask;
180 }
181
182 static void __CFWindowsMessageQueueSchedule(void *info, CFRunLoopRef rl, CFStringRef mode) {
183 CFWindowsMessageQueueRef wmq = (CFWindowsMessageQueueRef)info;
184 __CFWindowsMessageQueueLock(wmq);
185 if (__CFWindowsMessageQueueIsValid(wmq)) {
186 uint32_t mask;
187 CFArrayAppendValue(wmq->_runLoops, rl);
188 mask = __CFRunLoopGetWindowsMessageQueueMask(rl, mode);
189 mask |= wmq->_mask;
190 __CFRunLoopSetWindowsMessageQueueMask(rl, mask, mode);
191 }
192 __CFWindowsMessageQueueUnlock(wmq);
193 }
194
195 static void __CFWindowsMessageQueueCancel(void *info, CFRunLoopRef rl, CFStringRef mode) {
196 CFWindowsMessageQueueRef wmq = (CFWindowsMessageQueueRef)info;
197 __CFWindowsMessageQueueLock(wmq);
198 //#warning CF: should fix up run loop modes mask here, if not done
199 //#warning CF: previously by the invalidation, where it should also
200 //#warning CF: be done
201 if (NULL != wmq->_runLoops) {
202 SInt32 idx = CFArrayGetFirstIndexOfValue(wmq->_runLoops, CFRangeMake(0, CFArrayGetCount(wmq->_runLoops)), rl);
203 if (0 <= idx) CFArrayRemoveValueAtIndex(wmq->_runLoops, idx);
204 }
205 __CFWindowsMessageQueueUnlock(wmq);
206 }
207
208 static void __CFWindowsMessageQueuePerform(void *info) {
209 CFWindowsMessageQueueRef wmq = (CFWindowsMessageQueueRef)info;
210 __CFWindowsMessageQueueLock(wmq);
211 if (!__CFWindowsMessageQueueIsValid(wmq)) {
212 __CFWindowsMessageQueueUnlock(wmq);
213 return;
214 }
215 __CFWindowsMessageQueueUnlock(wmq);
216 extern void do_WIN32_MSG();
217 do_WIN32_MSG();
218 }
219
220 CFRunLoopSourceRef CFWindowsMessageQueueCreateRunLoopSource(CFAllocatorRef allocator, CFWindowsMessageQueueRef wmq, CFIndex order) {
221 CFRunLoopSourceRef result = NULL;
222 __CFWindowsMessageQueueLock(wmq);
223 if (NULL == wmq->_source) {
224 CFRunLoopSourceContext context;
225 context.version = 0;
226 context.info = (void *)wmq;
227 context.retain = CFRetain;
228 context.release = CFRelease;
229 context.copyDescription = __CFWindowsMessageQueueCopyDescription;
230 context.equal = __CFWindowsMessageQueueEqual;
231 context.hash = __CFWindowsMessageQueueHash;
232 context.schedule = __CFWindowsMessageQueueSchedule;
233 context.cancel = __CFWindowsMessageQueueCancel;
234 context.perform = __CFWindowsMessageQueuePerform;
235 wmq->_source = CFRunLoopSourceCreate(allocator, order, &context);
236 }
237 CFRetain(wmq->_source); /* This retain is for the receiver */
238 result = wmq->_source;
239 __CFWindowsMessageQueueUnlock(wmq);
240 return result;
241 }
242
243 #endif
244