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