2 * Copyright (c) 2010 Apple Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
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
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.
21 * @APPLE_LICENSE_HEADER_END@
24 /* CFWindowsMessageQueue.c
25 Copyright (c) 1999-2009, Apple Inc. All rights reserved.
26 Responsibility: Christopher Kane
29 #if DEPLOYMENT_TARGET_WINDOWS
31 #include "CFWindowsMessageQueue.h"
32 #include "CFInternal.h"
34 extern DWORD
__CFRunLoopGetWindowsMessageQueueMask(CFRunLoopRef rl
, CFStringRef mode
);
35 extern void __CFRunLoopSetWindowsMessageQueueMask(CFRunLoopRef rl
, DWORD mask
, CFStringRef mode
);
37 struct __CFWindowsMessageQueue
{
39 CFAllocatorRef _allocator
;
42 CFRunLoopSourceRef _source
;
43 CFMutableArrayRef _runLoops
;
46 /* Bit 3 in the base reserved bits is used for invalid state */
48 CF_INLINE Boolean
__CFWindowsMessageQueueIsValid(CFWindowsMessageQueueRef wmq
) {
49 return (Boolean
)__CFBitfieldGetValue(((const CFRuntimeBase
*)wmq
)->_cfinfo
[CF_INFO_BITS
], 3, 3);
52 CF_INLINE
void __CFWindowsMessageQueueSetValid(CFWindowsMessageQueueRef wmq
) {
53 __CFBitfieldSetValue(((CFRuntimeBase
*)wmq
)->_cfinfo
[CF_INFO_BITS
], 3, 3, 1);
56 CF_INLINE
void __CFWindowsMessageQueueUnsetValid(CFWindowsMessageQueueRef wmq
) {
57 __CFBitfieldSetValue(((CFRuntimeBase
*)wmq
)->_cfinfo
[CF_INFO_BITS
], 3, 3, 0);
60 CF_INLINE
void __CFWindowsMessageQueueLock(CFWindowsMessageQueueRef wmq
) {
61 __CFSpinLock(&(wmq
->_lock
));
64 CF_INLINE
void __CFWindowsMessageQueueUnlock(CFWindowsMessageQueueRef wmq
) {
65 __CFSpinUnlock(&(wmq
->_lock
));
68 static Boolean
__CFWindowsMessageQueueEqual(CFTypeRef cf1
, CFTypeRef cf2
) {
69 CFWindowsMessageQueueRef wmq1
= (CFWindowsMessageQueueRef
)cf1
;
70 CFWindowsMessageQueueRef wmq2
= (CFWindowsMessageQueueRef
)cf2
;
71 return (wmq1
== wmq2
);
74 static CFHashCode
__CFWindowsMessageQueueHash(CFTypeRef cf
) {
75 CFWindowsMessageQueueRef wmq
= (CFWindowsMessageQueueRef
)cf
;
76 return (CFHashCode
)wmq
;
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
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
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
);
100 CFAllocatorRef
__CFWindowsMessageQueueGetAllocator(CFTypeRef cf
) {
101 CFWindowsMessageQueueRef wmq
= (CFWindowsMessageQueueRef
)cf
;
102 return wmq
->_allocator
;
105 static void __CFWindowsMessageQueueDeallocate(CFTypeRef cf
) {
106 CFWindowsMessageQueueRef wmq
= (CFWindowsMessageQueueRef
)cf
;
107 CFAllocatorRef allocator
= CFGetAllocator(wmq
);
108 CFAllocatorDeallocate(allocator
, wmq
);
109 CFRelease(allocator
);
112 static CFTypeID __kCFWindowsMessageQueueTypeID
= _kCFRuntimeNotATypeID
;
114 static const CFRuntimeClass __CFWindowsMessageQueueClass
= {
116 "CFWindowsMessageQueue",
119 __CFWindowsMessageQueueDeallocate
,
120 __CFWindowsMessageQueueEqual
,
121 __CFWindowsMessageQueueHash
,
123 __CFWindowsMessageQueueCopyDescription
126 __private_extern__
void __CFWindowsMessageQueueInitialize(void) {
127 __kCFWindowsMessageQueueTypeID
= _CFRuntimeRegisterClass(&__CFWindowsMessageQueueClass
);
130 CFTypeID
CFWindowsMessageQueueGetTypeID(void) {
131 return __kCFWindowsMessageQueueTypeID
;
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
) {
141 __CFWindowsMessageQueueSetValid(memory
);
143 CF_SPINLOCK_INIT_FOR_STRUCTS(memory
->_lock
);
144 memory
->_mask
= (DWORD
)mask
;
145 memory
->_source
= NULL
;
146 memory
->_runLoops
= CFArrayCreateMutable(allocator
, 0, NULL
);
150 void CFWindowsMessageQueueInvalidate(CFWindowsMessageQueueRef wmq
) {
151 __CFGenericValidateType(wmq
, __kCFWindowsMessageQueueTypeID
);
153 __CFWindowsMessageQueueLock(wmq
);
154 if (__CFWindowsMessageQueueIsValid(wmq
)) {
156 __CFWindowsMessageQueueUnsetValid(wmq
);
157 for (idx
= CFArrayGetCount(wmq
->_runLoops
); idx
--;) {
158 CFRunLoopWakeUp((CFRunLoopRef
)CFArrayGetValueAtIndex(wmq
->_runLoops
, idx
));
160 CFRelease(wmq
->_runLoops
);
161 wmq
->_runLoops
= NULL
;
162 if (NULL
!= wmq
->_source
) {
163 CFRunLoopSourceInvalidate(wmq
->_source
);
164 CFRelease(wmq
->_source
);
168 __CFWindowsMessageQueueUnlock(wmq
);
172 Boolean
CFWindowsMessageQueueIsValid(CFWindowsMessageQueueRef wmq
) {
173 __CFGenericValidateType(wmq
, __kCFWindowsMessageQueueTypeID
);
174 return __CFWindowsMessageQueueIsValid(wmq
);
177 uint32_t CFWindowsMessageQueueGetMask(CFWindowsMessageQueueRef wmq
) {
178 __CFGenericValidateType(wmq
, __kCFWindowsMessageQueueTypeID
);
182 static void __CFWindowsMessageQueueSchedule(void *info
, CFRunLoopRef rl
, CFStringRef mode
) {
183 CFWindowsMessageQueueRef wmq
= (CFWindowsMessageQueueRef
)info
;
184 __CFWindowsMessageQueueLock(wmq
);
185 if (__CFWindowsMessageQueueIsValid(wmq
)) {
187 CFArrayAppendValue(wmq
->_runLoops
, rl
);
188 mask
= __CFRunLoopGetWindowsMessageQueueMask(rl
, mode
);
190 __CFRunLoopSetWindowsMessageQueueMask(rl
, mask
, mode
);
192 __CFWindowsMessageQueueUnlock(wmq
);
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
);
205 __CFWindowsMessageQueueUnlock(wmq
);
208 static void __CFWindowsMessageQueuePerform(void *info
) {
209 CFWindowsMessageQueueRef wmq
= (CFWindowsMessageQueueRef
)info
;
210 __CFWindowsMessageQueueLock(wmq
);
211 if (!__CFWindowsMessageQueueIsValid(wmq
)) {
212 __CFWindowsMessageQueueUnlock(wmq
);
215 __CFWindowsMessageQueueUnlock(wmq
);
216 extern void do_WIN32_MSG();
220 CFRunLoopSourceRef
CFWindowsMessageQueueCreateRunLoopSource(CFAllocatorRef allocator
, CFWindowsMessageQueueRef wmq
, CFIndex order
) {
221 CFRunLoopSourceRef result
= NULL
;
222 __CFWindowsMessageQueueLock(wmq
);
223 if (NULL
== wmq
->_source
) {
224 CFRunLoopSourceContext context
;
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
);
237 CFRetain(wmq
->_source
); /* This retain is for the receiver */
238 result
= wmq
->_source
;
239 __CFWindowsMessageQueueUnlock(wmq
);