blob: d28f22b1fb02b4dcb08a4aa3591f5b40a4afc341 [file] [log] [blame]
/*
* Copyright (c) 2008 Apple Inc. All rights reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
* This file contains Original Code and/or Modifications of Original Code
* as defined in and that are subject to the Apple Public Source License
* Version 2.0 (the 'License'). You may not use this file except in
* compliance with the License. Please obtain a copy of the License at
* http://www.opensource.apple.com/apsl/ and read it before using this
* file.
*
* The Original Code and all software distributed under the License are
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
* Please see the License for the specific language governing rights and
* limitations under the License.
*
* @APPLE_LICENSE_HEADER_END@
*/
/* CFWindowsMessageQueue.c
Copyright 1999-2002, Apple, Inc. All rights reserved.
Responsibility: Christopher Kane
*/
#if DEPLOYMENT_TARGET_WINDOWS
#include "CFWindowsMessageQueue.h"
#include "CFInternal.h"
extern DWORD __CFRunLoopGetWindowsMessageQueueMask(CFRunLoopRef rl, CFStringRef mode);
extern void __CFRunLoopSetWindowsMessageQueueMask(CFRunLoopRef rl, DWORD mask, CFStringRef mode);
struct __CFWindowsMessageQueue {
CFRuntimeBase _base;
CFAllocatorRef _allocator;
CFSpinLock_t _lock;
DWORD _mask;
CFRunLoopSourceRef _source;
CFMutableArrayRef _runLoops;
};
/* Bit 3 in the base reserved bits is used for invalid state */
CF_INLINE Boolean __CFWindowsMessageQueueIsValid(CFWindowsMessageQueueRef wmq) {
return (Boolean)__CFBitfieldGetValue(((const CFRuntimeBase *)wmq)->_cfinfo[CF_INFO_BITS], 3, 3);
}
CF_INLINE void __CFWindowsMessageQueueSetValid(CFWindowsMessageQueueRef wmq) {
__CFBitfieldSetValue(((CFRuntimeBase *)wmq)->_cfinfo[CF_INFO_BITS], 3, 3, 1);
}
CF_INLINE void __CFWindowsMessageQueueUnsetValid(CFWindowsMessageQueueRef wmq) {
__CFBitfieldSetValue(((CFRuntimeBase *)wmq)->_cfinfo[CF_INFO_BITS], 3, 3, 0);
}
CF_INLINE void __CFWindowsMessageQueueLock(CFWindowsMessageQueueRef wmq) {
__CFSpinLock(&(wmq->_lock));
}
CF_INLINE void __CFWindowsMessageQueueUnlock(CFWindowsMessageQueueRef wmq) {
__CFSpinUnlock(&(wmq->_lock));
}
static Boolean __CFWindowsMessageQueueEqual(CFTypeRef cf1, CFTypeRef cf2) {
CFWindowsMessageQueueRef wmq1 = (CFWindowsMessageQueueRef)cf1;
CFWindowsMessageQueueRef wmq2 = (CFWindowsMessageQueueRef)cf2;
return (wmq1 == wmq2);
}
static CFHashCode __CFWindowsMessageQueueHash(CFTypeRef cf) {
CFWindowsMessageQueueRef wmq = (CFWindowsMessageQueueRef)cf;
return (CFHashCode)wmq;
}
static CFStringRef __CFWindowsMessageQueueCopyDescription(CFTypeRef cf) {
/* Some commentary, possibly as out of date as much of the rest of the file was
#warning CF: this and many other CopyDescription functions are probably
#warning CF: broken, in that some of these fields being printed out can
#warning CF: be NULL, when the object is in the invalid state
*/
CFWindowsMessageQueueRef wmq = (CFWindowsMessageQueueRef)cf;
CFMutableStringRef result;
result = CFStringCreateMutable(CFGetAllocator(wmq), 0);
__CFWindowsMessageQueueLock(wmq);
/* More commentary, which we don't really need to see with every build
#warning CF: here, and probably everywhere with a per-instance lock,
#warning CF: the locked state will always be true because we lock,
#warning CF: and you cannot call description if the object is locked;
#warning CF: probably should not lock description, and call it unsafe
*/
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);
__CFWindowsMessageQueueUnlock(wmq);
return result;
}
CFAllocatorRef __CFWindowsMessageQueueGetAllocator(CFTypeRef cf) {
CFWindowsMessageQueueRef wmq = (CFWindowsMessageQueueRef)cf;
return wmq->_allocator;
}
static void __CFWindowsMessageQueueDeallocate(CFTypeRef cf) {
CFWindowsMessageQueueRef wmq = (CFWindowsMessageQueueRef)cf;
CFAllocatorRef allocator = CFGetAllocator(wmq);
CFAllocatorDeallocate(allocator, wmq);
CFRelease(allocator);
DeleteCriticalSection(&(wmq->_lock));
}
static CFTypeID __kCFWindowsMessageQueueTypeID = _kCFRuntimeNotATypeID;
static const CFRuntimeClass __CFWindowsMessageQueueClass = {
0,
"CFWindowsMessageQueue",
NULL, // init
NULL, // copy
__CFWindowsMessageQueueDeallocate,
__CFWindowsMessageQueueEqual,
__CFWindowsMessageQueueHash,
NULL, //
__CFWindowsMessageQueueCopyDescription
};
__private_extern__ void __CFWindowsMessageQueueInitialize(void) {
__kCFWindowsMessageQueueTypeID = _CFRuntimeRegisterClass(&__CFWindowsMessageQueueClass);
}
CFTypeID CFWindowsMessageQueueGetTypeID(void) {
return __kCFWindowsMessageQueueTypeID;
}
CFWindowsMessageQueueRef CFWindowsMessageQueueCreate(CFAllocatorRef allocator, DWORD mask) {
CFWindowsMessageQueueRef memory;
UInt32 size = sizeof(struct __CFWindowsMessageQueue) - sizeof(CFRuntimeBase);
memory = (CFWindowsMessageQueueRef)_CFRuntimeCreateInstance(allocator, __kCFWindowsMessageQueueTypeID, size, NULL);
if (NULL == memory) {
return NULL;
}
__CFWindowsMessageQueueSetValid(memory);
CF_SPINLOCK_INIT_FOR_STRUCTS(memory->_lock);
memory->_mask = mask;
memory->_source = NULL;
memory->_runLoops = CFArrayCreateMutable(allocator, 0, NULL);
return memory;
}
void CFWindowsMessageQueueInvalidate(CFWindowsMessageQueueRef wmq) {
__CFGenericValidateType(wmq, __kCFWindowsMessageQueueTypeID);
CFRetain(wmq);
__CFWindowsMessageQueueLock(wmq);
if (__CFWindowsMessageQueueIsValid(wmq)) {
SInt32 idx;
__CFWindowsMessageQueueUnsetValid(wmq);
for (idx = CFArrayGetCount(wmq->_runLoops); idx--;) {
CFRunLoopWakeUp((CFRunLoopRef)CFArrayGetValueAtIndex(wmq->_runLoops, idx));
}
CFRelease(wmq->_runLoops);
wmq->_runLoops = NULL;
if (NULL != wmq->_source) {
CFRunLoopSourceInvalidate(wmq->_source);
CFRelease(wmq->_source);
wmq->_source = NULL;
}
}
__CFWindowsMessageQueueUnlock(wmq);
CFRelease(wmq);
}
Boolean CFWindowsMessageQueueIsValid(CFWindowsMessageQueueRef wmq) {
__CFGenericValidateType(wmq, __kCFWindowsMessageQueueTypeID);
return __CFWindowsMessageQueueIsValid(wmq);
}
DWORD CFWindowsMessageQueueGetMask(CFWindowsMessageQueueRef wmq) {
__CFGenericValidateType(wmq, __kCFWindowsMessageQueueTypeID);
return wmq->_mask;
}
static void __CFWindowsMessageQueueSchedule(void *info, CFRunLoopRef rl, CFStringRef mode) {
CFWindowsMessageQueueRef wmq = (CFWindowsMessageQueueRef)info;
__CFWindowsMessageQueueLock(wmq);
if (__CFWindowsMessageQueueIsValid(wmq)) {
uint32_t mask;
CFArrayAppendValue(wmq->_runLoops, rl);
mask = __CFRunLoopGetWindowsMessageQueueMask(rl, mode);
mask |= wmq->_mask;
__CFRunLoopSetWindowsMessageQueueMask(rl, mask, mode);
}
__CFWindowsMessageQueueUnlock(wmq);
}
static void __CFWindowsMessageQueueCancel(void *info, CFRunLoopRef rl, CFStringRef mode) {
CFWindowsMessageQueueRef wmq = (CFWindowsMessageQueueRef)info;
__CFWindowsMessageQueueLock(wmq);
#if DEPLOYMENT_TARGET_WINDOWS
//#warning CF: should fix up run loop modes mask here, if not done
//#warning CF: previously by the invalidation, where it should also
//#warning CF: be done
#else
#warning CF: should fix up run loop modes mask here, if not done
#warning CF: previously by the invalidation, where it should also
#warning CF: be done
#endif //DEPLOYMENT_TARGET_WINDOWS
if (NULL != wmq->_runLoops) {
SInt32 idx = CFArrayGetFirstIndexOfValue(wmq->_runLoops, CFRangeMake(0, CFArrayGetCount(wmq->_runLoops)), rl);
if (0 <= idx) CFArrayRemoveValueAtIndex(wmq->_runLoops, idx);
}
__CFWindowsMessageQueueUnlock(wmq);
}
static void __CFWindowsMessageQueuePerform(void *info) {
CFWindowsMessageQueueRef wmq = (CFWindowsMessageQueueRef)info;
MSG msg;
__CFWindowsMessageQueueLock(wmq);
if (!__CFWindowsMessageQueueIsValid(wmq)) {
__CFWindowsMessageQueueUnlock(wmq);
return;
}
__CFWindowsMessageQueueUnlock(wmq);
if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE | PM_NOYIELD)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
CFRunLoopSourceRef CFWindowsMessageQueueCreateRunLoopSource(CFAllocatorRef allocator, CFWindowsMessageQueueRef wmq, CFIndex order) {
CFRunLoopSourceRef result = NULL;
__CFWindowsMessageQueueLock(wmq);
if (NULL == wmq->_source) {
CFRunLoopSourceContext context;
context.version = 0;
context.info = (void *)wmq;
context.retain = CFRetain;
context.release = CFRelease;
context.copyDescription = __CFWindowsMessageQueueCopyDescription;
context.equal = __CFWindowsMessageQueueEqual;
context.hash = __CFWindowsMessageQueueHash;
context.schedule = __CFWindowsMessageQueueSchedule;
context.cancel = __CFWindowsMessageQueueCancel;
context.perform = __CFWindowsMessageQueuePerform;
wmq->_source = CFRunLoopSourceCreate(allocator, order, &context);
}
CFRetain(wmq->_source); /* This retain is for the receiver */
result = wmq->_source;
__CFWindowsMessageQueueUnlock(wmq);
return result;
}
#endif