2 * Copyright (c) 2009 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@
23 /* CFWindowsMessageQueue.c
24 Copyright (c) 1999-2009, Apple Inc. All rights reserved.
25 Responsibility: Christopher Kane
28 #if DEPLOYMENT_TARGET_WINDOWS
30 #include "CFWindowsMessageQueue.h"
31 #include "CFInternal.h"
33 extern DWORD
__CFRunLoopGetWindowsMessageQueueMask(CFRunLoopRef rl
, CFStringRef mode
);
34 extern void __CFRunLoopSetWindowsMessageQueueMask(CFRunLoopRef rl
, DWORD mask
, CFStringRef mode
);
36 struct __CFWindowsMessageQueue
{
38 CFAllocatorRef _allocator
;
41 CFRunLoopSourceRef _source
;
42 CFMutableArrayRef _runLoops
;
45 /* Bit 3 in the base reserved bits is used for invalid state */
47 CF_INLINE Boolean
__CFWindowsMessageQueueIsValid(CFWindowsMessageQueueRef wmq
) {
48 return (Boolean
)__CFBitfieldGetValue(((const CFRuntimeBase
*)wmq
)->_cfinfo
[CF_INFO_BITS
], 3, 3);
51 CF_INLINE
void __CFWindowsMessageQueueSetValid(CFWindowsMessageQueueRef wmq
) {
52 __CFBitfieldSetValue(((CFRuntimeBase
*)wmq
)->_cfinfo
[CF_INFO_BITS
], 3, 3, 1);
55 CF_INLINE
void __CFWindowsMessageQueueUnsetValid(CFWindowsMessageQueueRef wmq
) {
56 __CFBitfieldSetValue(((CFRuntimeBase
*)wmq
)->_cfinfo
[CF_INFO_BITS
], 3, 3, 0);
59 CF_INLINE
void __CFWindowsMessageQueueLock(CFWindowsMessageQueueRef wmq
) {
60 __CFSpinLock(&(wmq
->_lock
));
63 CF_INLINE
void __CFWindowsMessageQueueUnlock(CFWindowsMessageQueueRef wmq
) {
64 __CFSpinUnlock(&(wmq
->_lock
));
67 static Boolean
__CFWindowsMessageQueueEqual(CFTypeRef cf1
, CFTypeRef cf2
) {
68 CFWindowsMessageQueueRef wmq1
= (CFWindowsMessageQueueRef
)cf1
;
69 CFWindowsMessageQueueRef wmq2
= (CFWindowsMessageQueueRef
)cf2
;
70 return (wmq1
== wmq2
);
73 static CFHashCode
__CFWindowsMessageQueueHash(CFTypeRef cf
) {
74 CFWindowsMessageQueueRef wmq
= (CFWindowsMessageQueueRef
)cf
;
75 return (CFHashCode
)wmq
;
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
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
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
);
99 CFAllocatorRef
__CFWindowsMessageQueueGetAllocator(CFTypeRef cf
) {
100 CFWindowsMessageQueueRef wmq
= (CFWindowsMessageQueueRef
)cf
;
101 return wmq
->_allocator
;
104 static void __CFWindowsMessageQueueDeallocate(CFTypeRef cf
) {
105 CFWindowsMessageQueueRef wmq
= (CFWindowsMessageQueueRef
)cf
;
106 CFAllocatorRef allocator
= CFGetAllocator(wmq
);
107 CFAllocatorDeallocate(allocator
, wmq
);
108 CFRelease(allocator
);
111 static CFTypeID __kCFWindowsMessageQueueTypeID
= _kCFRuntimeNotATypeID
;
113 static const CFRuntimeClass __CFWindowsMessageQueueClass
= {
115 "CFWindowsMessageQueue",
118 __CFWindowsMessageQueueDeallocate
,
119 __CFWindowsMessageQueueEqual
,
120 __CFWindowsMessageQueueHash
,
122 __CFWindowsMessageQueueCopyDescription
125 __private_extern__
void __CFWindowsMessageQueueInitialize(void) {
126 __kCFWindowsMessageQueueTypeID
= _CFRuntimeRegisterClass(&__CFWindowsMessageQueueClass
);
129 CFTypeID
CFWindowsMessageQueueGetTypeID(void) {
130 return __kCFWindowsMessageQueueTypeID
;
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
) {
140 __CFWindowsMessageQueueSetValid(memory
);
142 CF_SPINLOCK_INIT_FOR_STRUCTS(memory
->_lock
);
143 memory
->_mask
= (DWORD
)mask
;
144 memory
->_source
= NULL
;
145 memory
->_runLoops
= CFArrayCreateMutable(allocator
, 0, NULL
);
149 void CFWindowsMessageQueueInvalidate(CFWindowsMessageQueueRef wmq
) {
150 __CFGenericValidateType(wmq
, __kCFWindowsMessageQueueTypeID
);
152 __CFWindowsMessageQueueLock(wmq
);
153 if (__CFWindowsMessageQueueIsValid(wmq
)) {
155 __CFWindowsMessageQueueUnsetValid(wmq
);
156 for (idx
= CFArrayGetCount(wmq
->_runLoops
); idx
--;) {
157 CFRunLoopWakeUp((CFRunLoopRef
)CFArrayGetValueAtIndex(wmq
->_runLoops
, idx
));
159 CFRelease(wmq
->_runLoops
);
160 wmq
->_runLoops
= NULL
;
161 if (NULL
!= wmq
->_source
) {
162 CFRunLoopSourceInvalidate(wmq
->_source
);
163 CFRelease(wmq
->_source
);
167 __CFWindowsMessageQueueUnlock(wmq
);
171 Boolean
CFWindowsMessageQueueIsValid(CFWindowsMessageQueueRef wmq
) {
172 __CFGenericValidateType(wmq
, __kCFWindowsMessageQueueTypeID
);
173 return __CFWindowsMessageQueueIsValid(wmq
);
176 uint32_t CFWindowsMessageQueueGetMask(CFWindowsMessageQueueRef wmq
) {
177 __CFGenericValidateType(wmq
, __kCFWindowsMessageQueueTypeID
);
181 static void __CFWindowsMessageQueueSchedule(void *info
, CFRunLoopRef rl
, CFStringRef mode
) {
182 CFWindowsMessageQueueRef wmq
= (CFWindowsMessageQueueRef
)info
;
183 __CFWindowsMessageQueueLock(wmq
);
184 if (__CFWindowsMessageQueueIsValid(wmq
)) {
186 CFArrayAppendValue(wmq
->_runLoops
, rl
);
187 mask
= __CFRunLoopGetWindowsMessageQueueMask(rl
, mode
);
189 __CFRunLoopSetWindowsMessageQueueMask(rl
, mask
, mode
);
191 __CFWindowsMessageQueueUnlock(wmq
);
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
);
204 __CFWindowsMessageQueueUnlock(wmq
);
207 static void __CFWindowsMessageQueuePerform(void *info
) {
208 CFWindowsMessageQueueRef wmq
= (CFWindowsMessageQueueRef
)info
;
209 __CFWindowsMessageQueueLock(wmq
);
210 if (!__CFWindowsMessageQueueIsValid(wmq
)) {
211 __CFWindowsMessageQueueUnlock(wmq
);
214 __CFWindowsMessageQueueUnlock(wmq
);
215 extern void do_WIN32_MSG();
219 CFRunLoopSourceRef
CFWindowsMessageQueueCreateRunLoopSource(CFAllocatorRef allocator
, CFWindowsMessageQueueRef wmq
, CFIndex order
) {
220 CFRunLoopSourceRef result
= NULL
;
221 __CFWindowsMessageQueueLock(wmq
);
222 if (NULL
== wmq
->_source
) {
223 CFRunLoopSourceContext context
;
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
);
236 CFRetain(wmq
->_source
); /* This retain is for the receiver */
237 result
= wmq
->_source
;
238 __CFWindowsMessageQueueUnlock(wmq
);