]> git.saurik.com Git - apple/cf.git/blob - CFWindowsMessageQueue.c
CF-476.13.tar.gz
[apple/cf.git] / CFWindowsMessageQueue.c
1 /*
2 * Copyright (c) 2008 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 1999-2002, Apple, Inc. All rights reserved.
25 Responsibility: Christopher Kane
26 */
27
28 #if defined(__WIN32__)
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), (wmq->_lock.LockCount ? "Yes" : "No"), (__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 DeleteCriticalSection(&(wmq->_lock));
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, DWORD 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 = 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 DWORD 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 #if defined (__WIN32__)
199 //#warning CF: should fix up run loop modes mask here, if not done
200 //#warning CF: previously by the invalidation, where it should also
201 //#warning CF: be done
202 #else
203 #warning CF: should fix up run loop modes mask here, if not done
204 #warning CF: previously by the invalidation, where it should also
205 #warning CF: be done
206 #endif //__WIN32__
207 if (NULL != wmq->_runLoops) {
208 SInt32 idx = CFArrayGetFirstIndexOfValue(wmq->_runLoops, CFRangeMake(0, CFArrayGetCount(wmq->_runLoops)), rl);
209 if (0 <= idx) CFArrayRemoveValueAtIndex(wmq->_runLoops, idx);
210 }
211 __CFWindowsMessageQueueUnlock(wmq);
212 }
213
214 static void __CFWindowsMessageQueuePerform(void *info) {
215 CFWindowsMessageQueueRef wmq = (CFWindowsMessageQueueRef)info;
216 MSG msg;
217 __CFWindowsMessageQueueLock(wmq);
218 if (!__CFWindowsMessageQueueIsValid(wmq)) {
219 __CFWindowsMessageQueueUnlock(wmq);
220 return;
221 }
222 __CFWindowsMessageQueueUnlock(wmq);
223 if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE | PM_NOYIELD)) {
224 TranslateMessage(&msg);
225 DispatchMessage(&msg);
226 }
227 }
228
229 CFRunLoopSourceRef CFWindowsMessageQueueCreateRunLoopSource(CFAllocatorRef allocator, CFWindowsMessageQueueRef wmq, CFIndex order) {
230 CFRunLoopSourceRef result = NULL;
231 __CFWindowsMessageQueueLock(wmq);
232 if (NULL == wmq->_source) {
233 CFRunLoopSourceContext context;
234 context.version = 0;
235 context.info = (void *)wmq;
236 context.retain = CFRetain;
237 context.release = CFRelease;
238 context.copyDescription = __CFWindowsMessageQueueCopyDescription;
239 context.equal = __CFWindowsMessageQueueEqual;
240 context.hash = __CFWindowsMessageQueueHash;
241 context.schedule = __CFWindowsMessageQueueSchedule;
242 context.cancel = __CFWindowsMessageQueueCancel;
243 context.perform = __CFWindowsMessageQueuePerform;
244 wmq->_source = CFRunLoopSourceCreate(allocator, order, &context);
245 }
246 CFRetain(wmq->_source); /* This retain is for the receiver */
247 result = wmq->_source;
248 __CFWindowsMessageQueueUnlock(wmq);
249 return result;
250 }
251
252 #endif
253