2 * Copyright (c) 2008 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 Copyright 1998-2002, Apple, Inc. All rights reserved.
25 Responsibility: Christopher Kane
28 #include <CoreFoundation/CFMessagePort.h>
29 #include <CoreFoundation/CFRunLoop.h>
30 #include <CoreFoundation/CFMachPort.h>
31 #include <CoreFoundation/CFDictionary.h>
32 #include <CoreFoundation/CFByteOrder.h>
34 #include "CFInternal.h"
35 #include <mach/mach.h>
36 #include <mach/message.h>
37 #include <mach/mach_error.h>
38 #include <bootstrap_priv.h>
40 #include <mach/mach_time.h>
44 #define __kCFMessagePortMaxNameLengthMax 255
46 #if defined(BOOTSTRAP_MAX_NAME_LEN)
47 #define __kCFMessagePortMaxNameLength BOOTSTRAP_MAX_NAME_LEN
49 #define __kCFMessagePortMaxNameLength 128
52 #if __kCFMessagePortMaxNameLengthMax < __kCFMessagePortMaxNameLength
53 #undef __kCFMessagePortMaxNameLength
54 #define __kCFMessagePortMaxNameLength __kCFMessagePortMaxNameLengthMax
57 static CFSpinLock_t __CFAllMessagePortsLock
= CFSpinLockInit
;
58 static CFMutableDictionaryRef __CFAllLocalMessagePorts
= NULL
;
59 static CFMutableDictionaryRef __CFAllRemoteMessagePorts
= NULL
;
61 struct __CFMessagePort
{
65 CFMachPortRef _port
; /* immutable; invalidated */
66 CFMutableDictionaryRef _replies
;
68 int32_t _perPID
; /* zero if not per-pid, else pid */
69 CFMachPortRef _replyPort
; /* only used by remote port; immutable once created; invalidated */
70 CFRunLoopSourceRef _source
; /* only used by local port; immutable once created; invalidated */
71 CFMessagePortInvalidationCallBack _icallout
;
72 CFMessagePortCallBack _callout
; /* only used by local port; immutable */
73 CFMessagePortContext _context
; /* not part of remote port; immutable; invalidated */
76 /* Bit 0 in the base reserved bits is used for invalid state */
77 /* Bit 1 of the base reserved bits is used for has-extra-port-refs state */
78 /* Bit 2 of the base reserved bits is used for is-remote state */
79 /* Bit 3 in the base reserved bits is used for is-deallocing state */
81 CF_INLINE Boolean
__CFMessagePortIsValid(CFMessagePortRef ms
) {
82 return (Boolean
)__CFBitfieldGetValue(((const CFRuntimeBase
*)ms
)->_cfinfo
[CF_INFO_BITS
], 0, 0);
85 CF_INLINE
void __CFMessagePortSetValid(CFMessagePortRef ms
) {
86 __CFBitfieldSetValue(((CFRuntimeBase
*)ms
)->_cfinfo
[CF_INFO_BITS
], 0, 0, 1);
89 CF_INLINE
void __CFMessagePortUnsetValid(CFMessagePortRef ms
) {
90 __CFBitfieldSetValue(((CFRuntimeBase
*)ms
)->_cfinfo
[CF_INFO_BITS
], 0, 0, 0);
93 CF_INLINE Boolean
__CFMessagePortExtraMachRef(CFMessagePortRef ms
) {
94 return (Boolean
)__CFBitfieldGetValue(((const CFRuntimeBase
*)ms
)->_cfinfo
[CF_INFO_BITS
], 1, 1);
97 CF_INLINE
void __CFMessagePortSetExtraMachRef(CFMessagePortRef ms
) {
98 __CFBitfieldSetValue(((CFRuntimeBase
*)ms
)->_cfinfo
[CF_INFO_BITS
], 1, 1, 1);
101 CF_INLINE
void __CFMessagePortUnsetExtraMachRef(CFMessagePortRef ms
) {
102 __CFBitfieldSetValue(((CFRuntimeBase
*)ms
)->_cfinfo
[CF_INFO_BITS
], 1, 1, 0);
105 CF_INLINE Boolean
__CFMessagePortIsRemote(CFMessagePortRef ms
) {
106 return (Boolean
)__CFBitfieldGetValue(((const CFRuntimeBase
*)ms
)->_cfinfo
[CF_INFO_BITS
], 2, 2);
109 CF_INLINE
void __CFMessagePortSetRemote(CFMessagePortRef ms
) {
110 __CFBitfieldSetValue(((CFRuntimeBase
*)ms
)->_cfinfo
[CF_INFO_BITS
], 2, 2, 1);
113 CF_INLINE
void __CFMessagePortUnsetRemote(CFMessagePortRef ms
) {
114 __CFBitfieldSetValue(((CFRuntimeBase
*)ms
)->_cfinfo
[CF_INFO_BITS
], 2, 2, 0);
117 CF_INLINE Boolean
__CFMessagePortIsDeallocing(CFMessagePortRef ms
) {
118 return (Boolean
)__CFBitfieldGetValue(((const CFRuntimeBase
*)ms
)->_cfinfo
[CF_INFO_BITS
], 3, 3);
121 CF_INLINE
void __CFMessagePortSetIsDeallocing(CFMessagePortRef ms
) {
122 __CFBitfieldSetValue(((CFRuntimeBase
*)ms
)->_cfinfo
[CF_INFO_BITS
], 3, 3, 1);
125 CF_INLINE
void __CFMessagePortLock(CFMessagePortRef ms
) {
126 __CFSpinLock(&(ms
->_lock
));
129 CF_INLINE
void __CFMessagePortUnlock(CFMessagePortRef ms
) {
130 __CFSpinUnlock(&(ms
->_lock
));
134 #define __CFMessagePortMaxInlineBytes 4096*10
136 struct __CFMessagePortMachMsg0
{
139 uint8_t bytes
[__CFMessagePortMaxInlineBytes
];
142 struct __CFMessagePortMachMsg1
{
143 mach_msg_descriptor_t desc
;
147 struct __CFMessagePortMachMessage
{
148 mach_msg_header_t head
;
149 mach_msg_body_t body
;
151 struct __CFMessagePortMachMsg0 msg0
;
152 struct __CFMessagePortMachMsg1 msg1
;
156 static struct __CFMessagePortMachMessage
*__CFMessagePortCreateMessage(CFAllocatorRef allocator
, bool reply
, mach_port_t port
, mach_port_t replyPort
, int32_t convid
, int32_t msgid
, const uint8_t *bytes
, int32_t byteslen
) {
157 struct __CFMessagePortMachMessage
*msg
;
158 int32_t size
= sizeof(mach_msg_header_t
) + sizeof(mach_msg_body_t
);
159 if (byteslen
< __CFMessagePortMaxInlineBytes
) {
160 size
+= 2 * sizeof(int32_t) + ((byteslen
+ 3) & ~0x3);
162 size
+= sizeof(struct __CFMessagePortMachMsg1
);
164 msg
= CFAllocatorAllocate(allocator
, size
, 0);
165 msg
->head
.msgh_id
= convid
;
166 msg
->head
.msgh_size
= size
;
167 msg
->head
.msgh_remote_port
= port
;
168 msg
->head
.msgh_local_port
= replyPort
;
169 msg
->head
.msgh_reserved
= 0;
170 // msg->head.msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, (replyPort ? MACH_MSG_TYPE_MAKE_SEND : 0));
171 msg
->head
.msgh_bits
= MACH_MSGH_BITS((reply
? MACH_MSG_TYPE_MOVE_SEND_ONCE
: MACH_MSG_TYPE_COPY_SEND
), (MACH_PORT_NULL
!= replyPort
? MACH_MSG_TYPE_MAKE_SEND_ONCE
: 0));
172 if (byteslen
< __CFMessagePortMaxInlineBytes
) {
173 msg
->body
.msgh_descriptor_count
= 0;
174 msg
->contents
.msg0
.msgid
= CFSwapInt32HostToLittle(msgid
);
175 msg
->contents
.msg0
.byteslen
= CFSwapInt32HostToLittle(byteslen
);
176 if (NULL
!= bytes
&& 0 < byteslen
) {
177 memmove(msg
->contents
.msg0
.bytes
, bytes
, byteslen
);
179 memset(msg
->contents
.msg0
.bytes
+ byteslen
, 0, ((byteslen
+ 3) & ~0x3) - byteslen
);
181 msg
->head
.msgh_bits
|= MACH_MSGH_BITS_COMPLEX
;
182 msg
->body
.msgh_descriptor_count
= 1;
183 msg
->contents
.msg1
.desc
.out_of_line
.deallocate
= false;
184 msg
->contents
.msg1
.desc
.out_of_line
.copy
= MACH_MSG_VIRTUAL_COPY
;
185 msg
->contents
.msg1
.desc
.out_of_line
.address
= (void *)bytes
;
186 msg
->contents
.msg1
.desc
.out_of_line
.size
= byteslen
;
187 msg
->contents
.msg1
.desc
.out_of_line
.type
= MACH_MSG_OOL_DESCRIPTOR
;
188 msg
->contents
.msg1
.msgid
= CFSwapInt32HostToLittle(msgid
);
193 static CFStringRef
__CFMessagePortCopyDescription(CFTypeRef cf
) {
194 CFMessagePortRef ms
= (CFMessagePortRef
)cf
;
197 CFStringRef contextDesc
= NULL
;
198 locked
= ms
->_lock
? "Yes" : "No";
199 if (!__CFMessagePortIsRemote(ms
)) {
200 if (NULL
!= ms
->_context
.info
&& NULL
!= ms
->_context
.copyDescription
) {
201 contextDesc
= ms
->_context
.copyDescription(ms
->_context
.info
);
203 if (NULL
== contextDesc
) {
204 contextDesc
= CFStringCreateWithFormat(kCFAllocatorSystemDefault
, NULL
, CFSTR("<CFMessagePort context %p>"), ms
->_context
.info
);
206 result
= CFStringCreateWithFormat(kCFAllocatorSystemDefault
, NULL
, CFSTR("<CFMessagePort %p [%p]>{locked = %s, valid = %s, remote = %s, name = %@}"), cf
, CFGetAllocator(ms
), locked
, (__CFMessagePortIsValid(ms
) ? "Yes" : "No"), (__CFMessagePortIsRemote(ms
) ? "Yes" : "No"), ms
->_name
);
208 void *addr
= ms
->_callout
;
210 const char *name
= (dladdr(addr
, &info
) && info
.dli_saddr
== addr
&& info
.dli_sname
) ? info
.dli_sname
: "???";
211 result
= CFStringCreateWithFormat(kCFAllocatorSystemDefault
, NULL
, CFSTR("<CFMessagePort %p [%p]>{locked = %s, valid = %s, remote = %s, name = %@, source = %p, callout = %s (%p), context = %@}"), cf
, CFGetAllocator(ms
), locked
, (__CFMessagePortIsValid(ms
) ? "Yes" : "No"), (__CFMessagePortIsRemote(ms
) ? "Yes" : "No"), ms
->_name
, ms
->_source
, name
, addr
, (NULL
!= contextDesc
? contextDesc
: CFSTR("<no description>")));
213 if (NULL
!= contextDesc
) {
214 CFRelease(contextDesc
);
219 static void __CFMessagePortDeallocate(CFTypeRef cf
) {
220 CFMessagePortRef ms
= (CFMessagePortRef
)cf
;
221 __CFMessagePortSetIsDeallocing(ms
);
222 CFMessagePortInvalidate(ms
);
223 // Delay cleanup of _replies until here so that invalidation during
224 // SendRequest does not cause _replies to disappear out from under that function.
225 if (NULL
!= ms
->_replies
) {
226 CFRelease(ms
->_replies
);
228 if (NULL
!= ms
->_name
) {
229 CFRelease(ms
->_name
);
231 if (NULL
!= ms
->_port
) {
232 if (__CFMessagePortExtraMachRef(ms
)) {
233 mach_port_mod_refs(mach_task_self(), CFMachPortGetPort(ms
->_port
), MACH_PORT_RIGHT_SEND
, -1);
234 mach_port_mod_refs(mach_task_self(), CFMachPortGetPort(ms
->_port
), MACH_PORT_RIGHT_RECEIVE
, -1);
236 CFMachPortInvalidate(ms
->_port
);
237 CFRelease(ms
->_port
);
240 // A remote message port for a local message port in the same process will get the
241 // same mach port, and the remote port will keep the mach port from being torn down,
242 // thus keeping the remote port from getting any sort of death notification and
243 // auto-invalidating; so we manually implement the 'auto-invalidation' here by
244 // tickling each remote port to check its state after any message port is destroyed,
245 // but most importantly after local message ports are destroyed.
246 __CFSpinLock(&__CFAllMessagePortsLock
);
247 CFMessagePortRef
*remotePorts
= NULL
;
249 if (NULL
!= __CFAllRemoteMessagePorts
) {
250 cnt
= CFDictionaryGetCount(__CFAllRemoteMessagePorts
);
251 remotePorts
= CFAllocatorAllocate(kCFAllocatorSystemDefault
, cnt
* sizeof(CFMessagePortRef
), __kCFAllocatorGCScannedMemory
);
252 CFDictionaryGetKeysAndValues(__CFAllRemoteMessagePorts
, NULL
, (const void **)remotePorts
);
253 for (CFIndex idx
= 0; idx
< cnt
; idx
++) {
254 CFRetain(remotePorts
[idx
]);
257 __CFSpinUnlock(&__CFAllMessagePortsLock
);
259 for (CFIndex idx
= 0; idx
< cnt
; idx
++) {
260 // as a side-effect, this will auto-invalidate the CFMessagePort if the CFMachPort is invalid
261 CFMessagePortIsValid(remotePorts
[idx
]);
262 CFRelease(remotePorts
[idx
]);
264 CFAllocatorDeallocate(kCFAllocatorSystemDefault
, remotePorts
);
268 static CFTypeID __kCFMessagePortTypeID
= _kCFRuntimeNotATypeID
;
270 static const CFRuntimeClass __CFMessagePortClass
= {
275 __CFMessagePortDeallocate
,
279 __CFMessagePortCopyDescription
282 __private_extern__
void __CFMessagePortInitialize(void) {
283 __kCFMessagePortTypeID
= _CFRuntimeRegisterClass(&__CFMessagePortClass
);
286 CFTypeID
CFMessagePortGetTypeID(void) {
287 return __kCFMessagePortTypeID
;
290 static CFStringRef
__CFMessagePortSanitizeStringName(CFAllocatorRef allocator
, CFStringRef name
, uint8_t **utfnamep
, CFIndex
*utfnamelenp
) {
294 utfname
= CFAllocatorAllocate(allocator
, __kCFMessagePortMaxNameLength
+ 1, 0);
295 CFStringGetBytes(name
, CFRangeMake(0, CFStringGetLength(name
)), kCFStringEncodingUTF8
, 0, false, utfname
, __kCFMessagePortMaxNameLength
, &utflen
);
296 utfname
[utflen
] = '\0';
297 /* A new string is created, because the original string may have been
298 truncated to the max length, and we want the string name to definitely
299 match the raw UTF-8 chunk that has been created. Also, this is useful
300 to get a constant string in case the original name string was mutable. */
301 result
= CFStringCreateWithBytes(allocator
, utfname
, utflen
, kCFStringEncodingUTF8
, false);
302 if (NULL
!= utfnamep
) {
305 CFAllocatorDeallocate(allocator
, utfname
);
307 if (NULL
!= utfnamelenp
) {
308 *utfnamelenp
= utflen
;
313 static void __CFMessagePortDummyCallback(CFMachPortRef port
, void *msg
, CFIndex size
, void *info
) {
314 // not supposed to be implemented
317 static void __CFMessagePortInvalidationCallBack(CFMachPortRef port
, void *info
) {
318 // info has been setup as the CFMessagePort owning the CFMachPort
319 CFMessagePortInvalidate(info
);
322 static CFMessagePortRef
__CFMessagePortCreateLocal(CFAllocatorRef allocator
, CFStringRef name
, CFMessagePortCallBack callout
, CFMessagePortContext
*context
, Boolean
*shouldFreeInfo
, Boolean perPID
) {
323 CFMessagePortRef memory
;
324 uint8_t *utfname
= NULL
;
326 if (shouldFreeInfo
) *shouldFreeInfo
= true;
328 name
= __CFMessagePortSanitizeStringName(allocator
, name
, &utfname
, NULL
);
330 __CFSpinLock(&__CFAllMessagePortsLock
);
331 if (!perPID
&& NULL
!= name
) {
332 CFMessagePortRef existing
;
333 if (NULL
!= __CFAllLocalMessagePorts
&& CFDictionaryGetValueIfPresent(__CFAllLocalMessagePorts
, name
, (const void **)&existing
)) {
335 __CFSpinUnlock(&__CFAllMessagePortsLock
);
337 CFAllocatorDeallocate(allocator
, utfname
);
338 return (CFMessagePortRef
)(existing
);
341 __CFSpinUnlock(&__CFAllMessagePortsLock
);
342 CFIndex size
= sizeof(struct __CFMessagePort
) - sizeof(CFRuntimeBase
);
343 memory
= (CFMessagePortRef
)_CFRuntimeCreateInstance(allocator
, __kCFMessagePortTypeID
, size
, NULL
);
344 if (NULL
== memory
) {
348 CFAllocatorDeallocate(allocator
, utfname
);
351 __CFMessagePortUnsetValid(memory
);
352 __CFMessagePortUnsetExtraMachRef(memory
);
353 __CFMessagePortUnsetRemote(memory
);
354 memory
->_lock
= CFSpinLockInit
;
355 memory
->_name
= name
;
356 memory
->_port
= NULL
;
357 memory
->_replies
= NULL
;
358 memory
->_convCounter
= 0;
359 memory
->_perPID
= perPID
? getpid() : 0; // actual value not terribly useful for local ports
360 memory
->_replyPort
= NULL
;
361 memory
->_source
= NULL
;
362 memory
->_icallout
= NULL
;
363 memory
->_callout
= callout
;
364 memory
->_context
.info
= NULL
;
365 memory
->_context
.retain
= NULL
;
366 memory
->_context
.release
= NULL
;
367 memory
->_context
.copyDescription
= NULL
;
370 CFMachPortRef native
= NULL
;
373 task_get_bootstrap_port(mach_task_self(), &bs
);
375 ret
= bootstrap_check_in(bs
, (char *)utfname
, &mp
); /* If we're started by launchd or the old mach_init */
376 if (ret
== KERN_SUCCESS
) {
377 ret
= mach_port_insert_right(mach_task_self(), mp
, mp
, MACH_MSG_TYPE_MAKE_SEND
);
378 if (KERN_SUCCESS
== ret
) {
379 CFMachPortContext ctx
= {0, memory
, NULL
, NULL
, NULL
};
380 native
= CFMachPortCreateWithPort(allocator
, mp
, __CFMessagePortDummyCallback
, &ctx
, NULL
);
381 __CFMessagePortSetExtraMachRef(memory
);
383 CFLog(kCFLogLevelWarning
, CFSTR("*** CFMessagePort: mach_port_insert_member() after bootstrap_check_in(): failed %d (0x%x) '%s', port = 0x%x, name = '%s'"), ret
, ret
, bootstrap_strerror(ret
), mp
, utfname
);
384 mach_port_destroy(mach_task_self(), mp
);
385 CFAllocatorDeallocate(allocator
, utfname
);
386 // name is released by deallocation
393 CFMachPortContext ctx
= {0, memory
, NULL
, NULL
, NULL
};
394 native
= CFMachPortCreate(allocator
, __CFMessagePortDummyCallback
, &ctx
, NULL
);
395 mp
= CFMachPortGetPort(native
);
396 ret
= bootstrap_register2(bs
, (char *)utfname
, mp
, perPID
? BOOTSTRAP_PER_PID_SERVICE
: 0);
397 if (ret
!= KERN_SUCCESS
) {
398 CFLog(kCFLogLevelWarning
, CFSTR("*** CFMessagePort: bootstrap_register(): failed %d (0x%x) '%s', port = 0x%x, name = '%s'\nSee /usr/include/servers/bootstrap_defs.h for the error codes."), ret
, ret
, bootstrap_strerror(ret
), mp
, utfname
);
399 CFMachPortInvalidate(native
);
401 CFAllocatorDeallocate(allocator
, utfname
);
402 // name is released by deallocation
407 CFMachPortSetInvalidationCallBack(native
, __CFMessagePortInvalidationCallBack
);
408 memory
->_port
= native
;
411 CFAllocatorDeallocate(allocator
, utfname
);
412 __CFMessagePortSetValid(memory
);
413 if (NULL
!= context
) {
414 memmove(&memory
->_context
, context
, sizeof(CFMessagePortContext
));
415 memory
->_context
.info
= context
->retain
? (void *)context
->retain(context
->info
) : context
->info
;
417 __CFSpinLock(&__CFAllMessagePortsLock
);
418 if (!perPID
&& NULL
!= name
) {
419 CFMessagePortRef existing
;
420 if (NULL
!= __CFAllLocalMessagePorts
&& CFDictionaryGetValueIfPresent(__CFAllLocalMessagePorts
, name
, (const void **)&existing
)) {
422 __CFSpinUnlock(&__CFAllMessagePortsLock
);
424 return (CFMessagePortRef
)(existing
);
426 if (NULL
== __CFAllLocalMessagePorts
) {
427 __CFAllLocalMessagePorts
= CFDictionaryCreateMutable(kCFAllocatorSystemDefault
, 0, &kCFTypeDictionaryKeyCallBacks
, NULL
);
429 CFDictionaryAddValue(__CFAllLocalMessagePorts
, name
, memory
);
431 __CFSpinUnlock(&__CFAllMessagePortsLock
);
432 if (shouldFreeInfo
) *shouldFreeInfo
= false;
436 CFMessagePortRef
CFMessagePortCreateLocal(CFAllocatorRef allocator
, CFStringRef name
, CFMessagePortCallBack callout
, CFMessagePortContext
*context
, Boolean
*shouldFreeInfo
) {
437 return __CFMessagePortCreateLocal(allocator
, name
, callout
, context
, shouldFreeInfo
, false);
440 CFMessagePortRef
CFMessagePortCreatePerProcessLocal(CFAllocatorRef allocator
, CFStringRef name
, CFMessagePortCallBack callout
, CFMessagePortContext
*context
, Boolean
*shouldFreeInfo
) {
441 return __CFMessagePortCreateLocal(allocator
, name
, callout
, context
, shouldFreeInfo
, true);
444 static CFMessagePortRef
__CFMessagePortCreateRemote(CFAllocatorRef allocator
, CFStringRef name
, Boolean perPID
, CFIndex pid
) {
445 CFMessagePortRef memory
;
446 CFMachPortRef native
;
447 CFMachPortContext ctx
;
448 uint8_t *utfname
= NULL
;
450 mach_port_t bp
, port
;
453 name
= __CFMessagePortSanitizeStringName(allocator
, name
, &utfname
, NULL
);
457 __CFSpinLock(&__CFAllMessagePortsLock
);
458 if (!perPID
&& NULL
!= name
) {
459 CFMessagePortRef existing
;
460 if (NULL
!= __CFAllRemoteMessagePorts
&& CFDictionaryGetValueIfPresent(__CFAllRemoteMessagePorts
, name
, (const void **)&existing
)) {
462 __CFSpinUnlock(&__CFAllMessagePortsLock
);
464 CFAllocatorDeallocate(allocator
, utfname
);
465 return (CFMessagePortRef
)(existing
);
468 __CFSpinUnlock(&__CFAllMessagePortsLock
);
469 size
= sizeof(struct __CFMessagePort
) - sizeof(CFMessagePortContext
) - sizeof(CFRuntimeBase
);
470 memory
= (CFMessagePortRef
)_CFRuntimeCreateInstance(allocator
, __kCFMessagePortTypeID
, size
, NULL
);
471 if (NULL
== memory
) {
475 CFAllocatorDeallocate(allocator
, utfname
);
478 __CFMessagePortUnsetValid(memory
);
479 __CFMessagePortUnsetExtraMachRef(memory
);
480 __CFMessagePortSetRemote(memory
);
481 memory
->_lock
= CFSpinLockInit
;
482 memory
->_name
= name
;
483 memory
->_port
= NULL
;
484 memory
->_replies
= CFDictionaryCreateMutable(kCFAllocatorSystemDefault
, 0, NULL
, NULL
);
485 memory
->_convCounter
= 0;
486 memory
->_perPID
= perPID
? pid
: 0;
487 memory
->_replyPort
= NULL
;
488 memory
->_source
= NULL
;
489 memory
->_icallout
= NULL
;
490 memory
->_callout
= NULL
;
495 ctx
.copyDescription
= NULL
;
496 task_get_bootstrap_port(mach_task_self(), &bp
);
497 ret
= bootstrap_look_up2(bp
, (char *)utfname
, &port
, perPID
? (pid_t
)pid
: 0, perPID
? BOOTSTRAP_PER_PID_SERVICE
: 0);
498 native
= (KERN_SUCCESS
== ret
) ? CFMachPortCreateWithPort(allocator
, port
, __CFMessagePortDummyCallback
, &ctx
, NULL
) : NULL
;
499 CFAllocatorDeallocate(allocator
, utfname
);
500 if (NULL
== native
) {
501 // name is released by deallocation
505 memory
->_port
= native
;
506 CFMachPortSetInvalidationCallBack(native
, __CFMessagePortInvalidationCallBack
);
507 __CFMessagePortSetValid(memory
);
508 __CFSpinLock(&__CFAllMessagePortsLock
);
509 if (!perPID
&& NULL
!= name
) {
510 CFMessagePortRef existing
;
511 if (NULL
!= __CFAllRemoteMessagePorts
&& CFDictionaryGetValueIfPresent(__CFAllRemoteMessagePorts
, name
, (const void **)&existing
)) {
513 __CFSpinUnlock(&__CFAllMessagePortsLock
);
515 return (CFMessagePortRef
)(existing
);
517 if (NULL
== __CFAllRemoteMessagePorts
) {
518 __CFAllRemoteMessagePorts
= CFDictionaryCreateMutable(kCFAllocatorSystemDefault
, 0, &kCFTypeDictionaryKeyCallBacks
, NULL
);
520 CFDictionaryAddValue(__CFAllRemoteMessagePorts
, name
, memory
);
522 __CFSpinUnlock(&__CFAllMessagePortsLock
);
523 return (CFMessagePortRef
)memory
;
526 CFMessagePortRef
CFMessagePortCreateRemote(CFAllocatorRef allocator
, CFStringRef name
) {
527 return __CFMessagePortCreateRemote(allocator
, name
, false, 0);
530 CFMessagePortRef
CFMessagePortCreatePerProcessRemote(CFAllocatorRef allocator
, CFStringRef name
, CFIndex pid
) {
531 return __CFMessagePortCreateRemote(allocator
, name
, true, pid
);
534 Boolean
CFMessagePortIsRemote(CFMessagePortRef ms
) {
535 __CFGenericValidateType(ms
, __kCFMessagePortTypeID
);
536 return __CFMessagePortIsRemote(ms
);
539 CFStringRef
CFMessagePortGetName(CFMessagePortRef ms
) {
540 __CFGenericValidateType(ms
, __kCFMessagePortTypeID
);
544 Boolean
CFMessagePortSetName(CFMessagePortRef ms
, CFStringRef name
) {
545 CFAllocatorRef allocator
= CFGetAllocator(ms
);
546 uint8_t *utfname
= NULL
;
548 __CFGenericValidateType(ms
, __kCFMessagePortTypeID
);
549 if (ms
->_perPID
|| __CFMessagePortIsRemote(ms
)) return false;
550 name
= __CFMessagePortSanitizeStringName(allocator
, name
, &utfname
, NULL
);
554 __CFSpinLock(&__CFAllMessagePortsLock
);
556 CFMessagePortRef existing
;
557 if (NULL
!= __CFAllLocalMessagePorts
&& CFDictionaryGetValueIfPresent(__CFAllLocalMessagePorts
, name
, (const void **)&existing
)) {
558 __CFSpinUnlock(&__CFAllMessagePortsLock
);
560 CFAllocatorDeallocate(allocator
, utfname
);
564 __CFSpinUnlock(&__CFAllMessagePortsLock
);
566 if (NULL
!= name
&& (NULL
== ms
->_name
|| !CFEqual(ms
->_name
, name
))) {
567 CFMachPortRef oldPort
= ms
->_port
;
568 CFMachPortRef native
= NULL
;
571 task_get_bootstrap_port(mach_task_self(), &bs
);
572 ret
= bootstrap_check_in(bs
, (char *)utfname
, &mp
); /* If we're started by launchd or the old mach_init */
573 if (ret
== KERN_SUCCESS
) {
574 ret
= mach_port_insert_right(mach_task_self(), mp
, mp
, MACH_MSG_TYPE_MAKE_SEND
);
575 if (KERN_SUCCESS
== ret
) {
576 CFMachPortContext ctx
= {0, ms
, NULL
, NULL
, NULL
};
577 native
= CFMachPortCreateWithPort(allocator
, mp
, __CFMessagePortDummyCallback
, &ctx
, NULL
);
578 __CFMessagePortSetExtraMachRef(ms
);
580 mach_port_destroy(mach_task_self(), mp
);
581 CFAllocatorDeallocate(allocator
, utfname
);
587 CFMachPortContext ctx
= {0, ms
, NULL
, NULL
, NULL
};
588 native
= CFMachPortCreate(allocator
, __CFMessagePortDummyCallback
, &ctx
, NULL
);
589 mp
= CFMachPortGetPort(native
);
590 ret
= bootstrap_register2(bs
, (char *)utfname
, mp
, 0);
591 if (ret
!= KERN_SUCCESS
) {
592 CFLog(kCFLogLevelWarning
, CFSTR("*** CFMessagePort: bootstrap_register(): failed %d (0x%x) '%s', port = 0x%x, name = '%s'\nSee /usr/include/servers/bootstrap_defs.h for the error codes."), ret
, ret
, bootstrap_strerror(ret
), mp
, utfname
);
593 CFMachPortInvalidate(native
);
595 CFAllocatorDeallocate(allocator
, utfname
);
600 CFMachPortSetInvalidationCallBack(native
, __CFMessagePortInvalidationCallBack
);
602 if (NULL
!= oldPort
&& oldPort
!= native
) {
603 if (__CFMessagePortExtraMachRef(ms
)) {
604 mach_port_mod_refs(mach_task_self(), CFMachPortGetPort(oldPort
), MACH_PORT_RIGHT_SEND
, -1);
605 mach_port_mod_refs(mach_task_self(), CFMachPortGetPort(oldPort
), MACH_PORT_RIGHT_RECEIVE
, -1);
607 CFMachPortInvalidate(oldPort
);
610 __CFSpinLock(&__CFAllMessagePortsLock
);
611 // This relocking without checking to see if something else has grabbed
612 // that name in the cache is rather suspect, but what would that even
613 // mean has happened? We'd expect the bootstrap_* calls above to have
614 // failed for this one and not gotten this far, or failed for all of the
615 // other simultaneous attempts to get the name (and having succeeded for
616 // this one, gotten here). So we're not going to try very hard here
617 // with the thread-safety.
618 if (NULL
== __CFAllLocalMessagePorts
) {
619 __CFAllLocalMessagePorts
= CFDictionaryCreateMutable(kCFAllocatorSystemDefault
, 0, &kCFTypeDictionaryKeyCallBacks
, NULL
);
621 if (NULL
!= ms
->_name
) {
622 CFDictionaryRemoveValue(__CFAllLocalMessagePorts
, ms
->_name
);
623 CFRelease(ms
->_name
);
626 CFDictionaryAddValue(__CFAllLocalMessagePorts
, name
, ms
);
627 __CFSpinUnlock(&__CFAllMessagePortsLock
);
630 CFAllocatorDeallocate(allocator
, utfname
);
634 void CFMessagePortGetContext(CFMessagePortRef ms
, CFMessagePortContext
*context
) {
635 __CFGenericValidateType(ms
, __kCFMessagePortTypeID
);
636 //#warning CF: assert that this is a local port
637 CFAssert1(0 == context
->version
, __kCFLogAssertion
, "%s(): context version not initialized to 0", __PRETTY_FUNCTION__
);
638 memmove(context
, &ms
->_context
, sizeof(CFMessagePortContext
));
641 void CFMessagePortInvalidate(CFMessagePortRef ms
) {
642 __CFGenericValidateType(ms
, __kCFMessagePortTypeID
);
643 if (!__CFMessagePortIsDeallocing(ms
)) {
646 __CFMessagePortLock(ms
);
647 if (__CFMessagePortIsValid(ms
)) {
648 CFMessagePortInvalidationCallBack callout
= ms
->_icallout
;
649 CFRunLoopSourceRef source
= ms
->_source
;
650 CFMachPortRef replyPort
= ms
->_replyPort
;
651 CFMachPortRef port
= ms
->_port
;
652 CFStringRef name
= ms
->_name
;
655 __CFMessagePortUnsetValid(ms
);
656 if (!__CFMessagePortIsRemote(ms
)) {
657 info
= ms
->_context
.info
;
658 ms
->_context
.info
= NULL
;
661 ms
->_replyPort
= NULL
;
662 __CFMessagePortUnlock(ms
);
664 __CFSpinLock(&__CFAllMessagePortsLock
);
665 if (0 == ms
->_perPID
&& NULL
!= (__CFMessagePortIsRemote(ms
) ? __CFAllRemoteMessagePorts
: __CFAllLocalMessagePorts
)) {
666 CFDictionaryRemoveValue(__CFMessagePortIsRemote(ms
) ? __CFAllRemoteMessagePorts
: __CFAllLocalMessagePorts
, name
);
668 __CFSpinUnlock(&__CFAllMessagePortsLock
);
669 if (NULL
!= callout
) {
672 // We already know we're going invalid, don't need this callback
673 // anymore; plus, this solves a reentrancy deadlock; also, this
674 // must be done before the deallocate of the Mach port, to
675 // avoid a race between the notification message which could be
676 // handled in another thread, and this NULL'ing out.
677 CFMachPortSetInvalidationCallBack(port
, NULL
);
678 // For hashing and equality purposes, cannot get rid of _port here
679 if (!__CFMessagePortIsRemote(ms
) && NULL
!= ms
->_context
.release
) {
680 ms
->_context
.release(info
);
682 if (NULL
!= source
) {
683 CFRunLoopSourceInvalidate(source
);
686 if (NULL
!= replyPort
) {
687 CFMachPortInvalidate(replyPort
);
688 CFRelease(replyPort
);
690 if (__CFMessagePortIsRemote(ms
)) {
691 // Get rid of our extra ref on the Mach port gotten from bs server
692 mach_port_deallocate(mach_task_self(), CFMachPortGetPort(port
));
695 __CFMessagePortUnlock(ms
);
697 if (!__CFMessagePortIsDeallocing(ms
)) {
702 Boolean
CFMessagePortIsValid(CFMessagePortRef ms
) {
703 __CFGenericValidateType(ms
, __kCFMessagePortTypeID
);
704 if (!__CFMessagePortIsValid(ms
)) return false;
705 if (NULL
!= ms
->_port
&& !CFMachPortIsValid(ms
->_port
)) {
706 CFMessagePortInvalidate(ms
);
709 if (NULL
!= ms
->_replyPort
&& !CFMachPortIsValid(ms
->_replyPort
)) {
710 CFMessagePortInvalidate(ms
);
713 if (NULL
!= ms
->_source
&& !CFRunLoopSourceIsValid(ms
->_source
)) {
714 CFMessagePortInvalidate(ms
);
720 CFMessagePortInvalidationCallBack
CFMessagePortGetInvalidationCallBack(CFMessagePortRef ms
) {
721 __CFGenericValidateType(ms
, __kCFMessagePortTypeID
);
722 return ms
->_icallout
;
725 void CFMessagePortSetInvalidationCallBack(CFMessagePortRef ms
, CFMessagePortInvalidationCallBack callout
) {
726 __CFGenericValidateType(ms
, __kCFMessagePortTypeID
);
727 if (!__CFMessagePortIsValid(ms
) && NULL
!= callout
) {
728 callout(ms
, ms
->_context
.info
);
730 ms
->_icallout
= callout
;
734 static void __CFMessagePortReplyCallBack(CFMachPortRef port
, void *msg
, CFIndex size
, void *info
) {
735 CFMessagePortRef ms
= info
;
736 struct __CFMessagePortMachMessage
*msgp
= msg
;
737 struct __CFMessagePortMachMessage
*replymsg
;
738 __CFMessagePortLock(ms
);
739 if (!__CFMessagePortIsValid(ms
)) {
740 __CFMessagePortUnlock(ms
);
743 // assert: (int32_t)msgp->head.msgh_id < 0
744 if (CFDictionaryContainsKey(ms
->_replies
, (void *)(uintptr_t)msgp
->head
.msgh_id
)) {
745 CFDataRef reply
= NULL
;
746 replymsg
= (struct __CFMessagePortMachMessage
*)msg
;
747 if (0 == replymsg
->body
.msgh_descriptor_count
) {
748 int32_t byteslen
= CFSwapInt32LittleToHost(replymsg
->contents
.msg0
.byteslen
);
750 reply
= CFDataCreate(kCFAllocatorSystemDefault
, replymsg
->contents
.msg0
.bytes
, byteslen
);
752 reply
= (void *)~0; // means NULL data
755 //#warning CF: should create a no-copy data here that has a custom VM-freeing allocator, and not vm_dealloc here
756 reply
= CFDataCreate(kCFAllocatorSystemDefault
, replymsg
->contents
.msg1
.desc
.out_of_line
.address
, replymsg
->contents
.msg1
.desc
.out_of_line
.size
);
757 vm_deallocate(mach_task_self(), (vm_address_t
)replymsg
->contents
.msg1
.desc
.out_of_line
.address
, replymsg
->contents
.msg1
.desc
.out_of_line
.size
);
759 CFDictionarySetValue(ms
->_replies
, (void *)(uintptr_t)msgp
->head
.msgh_id
, (void *)reply
);
760 } else { /* discard message */
761 if (1 == msgp
->body
.msgh_descriptor_count
) {
762 vm_deallocate(mach_task_self(), (vm_address_t
)msgp
->contents
.msg1
.desc
.out_of_line
.address
, msgp
->contents
.msg1
.desc
.out_of_line
.size
);
765 __CFMessagePortUnlock(ms
);
768 SInt32
CFMessagePortSendRequest(CFMessagePortRef remote
, SInt32 msgid
, CFDataRef data
, CFTimeInterval sendTimeout
, CFTimeInterval rcvTimeout
, CFStringRef replyMode
, CFDataRef
*returnDatap
) {
769 struct __CFMessagePortMachMessage
*sendmsg
;
770 CFRunLoopRef currentRL
= CFRunLoopGetCurrent();
771 CFRunLoopSourceRef source
= NULL
;
772 CFDataRef reply
= NULL
;
774 uint32_t sendOpts
= 0, sendTimeOut
= 0;
775 int32_t desiredReply
;
776 Boolean didRegister
= false;
779 //#warning CF: This should be an assert
780 // if (!__CFMessagePortIsRemote(remote)) return -999;
781 if (!__CFMessagePortIsValid(remote
)) return kCFMessagePortIsInvalid
;
782 __CFMessagePortLock(remote
);
783 if (NULL
== remote
->_replyPort
) {
784 CFMachPortContext context
;
786 context
.info
= remote
;
787 context
.retain
= (const void *(*)(const void *))CFRetain
;
788 context
.release
= (void (*)(const void *))CFRelease
;
789 context
.copyDescription
= (CFStringRef (*)(const void *))__CFMessagePortCopyDescription
;
790 remote
->_replyPort
= CFMachPortCreate(CFGetAllocator(remote
), __CFMessagePortReplyCallBack
, &context
, NULL
);
792 remote
->_convCounter
++;
793 desiredReply
= -remote
->_convCounter
;
794 sendmsg
= __CFMessagePortCreateMessage(kCFAllocatorSystemDefault
, false, CFMachPortGetPort(remote
->_port
), (replyMode
!= NULL
? CFMachPortGetPort(remote
->_replyPort
) : MACH_PORT_NULL
), -desiredReply
, msgid
, (data
? CFDataGetBytePtr(data
) : NULL
), (data
? CFDataGetLength(data
) : 0));
795 __CFMessagePortUnlock(remote
);
796 if (replyMode
!= NULL
) {
797 CFDictionarySetValue(remote
->_replies
, (void *)(uintptr_t)desiredReply
, NULL
);
798 source
= CFMachPortCreateRunLoopSource(CFGetAllocator(remote
), remote
->_replyPort
, -100);
799 didRegister
= !CFRunLoopContainsSource(currentRL
, source
, replyMode
);
801 CFRunLoopAddSource(currentRL
, source
, replyMode
);
804 if (sendTimeout
< 10.0*86400) {
805 // anything more than 10 days is no timeout!
806 sendOpts
= MACH_SEND_TIMEOUT
;
807 sendTimeout
*= 1000.0;
808 if (sendTimeout
< 1.0) sendTimeout
= 0.0;
809 sendTimeOut
= floor(sendTimeout
);
811 ret
= mach_msg((mach_msg_header_t
*)sendmsg
, MACH_SEND_MSG
|sendOpts
, sendmsg
->head
.msgh_size
, 0, MACH_PORT_NULL
, sendTimeOut
, MACH_PORT_NULL
);
812 if (KERN_SUCCESS
!= ret
) {
813 // need to deallocate the send-once right that might have been created
814 if (replyMode
!= NULL
) mach_port_deallocate(mach_task_self(), ((mach_msg_header_t
*)sendmsg
)->msgh_local_port
);
816 CFRunLoopRemoveSource(currentRL
, source
, replyMode
);
818 if (source
) CFRelease(source
);
819 CFAllocatorDeallocate(kCFAllocatorSystemDefault
, sendmsg
);
820 return (MACH_SEND_TIMED_OUT
== ret
) ? kCFMessagePortSendTimeout
: kCFMessagePortTransportError
;
822 CFAllocatorDeallocate(kCFAllocatorSystemDefault
, sendmsg
);
823 if (replyMode
== NULL
) {
824 return kCFMessagePortSuccess
;
826 CFRetain(remote
); // retain during run loop to avoid invalidation causing freeing
827 _CFMachPortInstallNotifyPort(currentRL
, replyMode
);
828 termTSR
= mach_absolute_time() + __CFTimeIntervalToTSR(rcvTimeout
);
830 CFRunLoopRunInMode(replyMode
, __CFTSRToTimeInterval(termTSR
- mach_absolute_time()), true);
831 // warning: what, if anything, should be done if remote is now invalid?
832 reply
= CFDictionaryGetValue(remote
->_replies
, (void *)(uintptr_t)desiredReply
);
833 if (NULL
!= reply
|| termTSR
< (int64_t)mach_absolute_time()) {
836 if (!CFMessagePortIsValid(remote
)) {
837 // no reason that reply port alone should go invalid so we don't check for that
841 // Should we uninstall the notify port? A complex question...
843 CFRunLoopRemoveSource(currentRL
, source
, replyMode
);
845 if (source
) CFRelease(source
);
847 CFDictionaryRemoveValue(remote
->_replies
, (void *)(uintptr_t)desiredReply
);
849 return CFMessagePortIsValid(remote
) ? kCFMessagePortReceiveTimeout
: -5;
851 if (NULL
!= returnDatap
) {
852 *returnDatap
= ((void *)~0 == reply
) ? NULL
: reply
;
853 } else if ((void *)~0 != reply
) {
856 CFDictionaryRemoveValue(remote
->_replies
, (void *)(uintptr_t)desiredReply
);
858 return kCFMessagePortSuccess
;
861 static mach_port_t
__CFMessagePortGetPort(void *info
) {
862 CFMessagePortRef ms
= info
;
863 if (!ms
->_port
) CFLog(kCFLogLevelWarning
, CFSTR("*** Warning: A local CFMessagePort (%p) is being put in a run loop, but it has not been named yet, so this will be a no-op and no messages are going to be received, even if named later."), info
);
864 return ms
->_port
? CFMachPortGetPort(ms
->_port
) : MACH_PORT_NULL
;
867 static void *__CFMessagePortPerform(void *msg
, CFIndex size
, CFAllocatorRef allocator
, void *info
) {
868 CFMessagePortRef ms
= info
;
869 struct __CFMessagePortMachMessage
*msgp
= msg
;
870 struct __CFMessagePortMachMessage
*replymsg
;
872 void (*context_release
)(const void *);
873 CFDataRef returnData
, data
= NULL
;
874 void *return_bytes
= NULL
;
875 CFIndex return_len
= 0;
878 __CFMessagePortLock(ms
);
879 if (!__CFMessagePortIsValid(ms
)) {
880 __CFMessagePortUnlock(ms
);
883 // assert: 0 < (int32_t)msgp->head.msgh_id
884 if (NULL
!= ms
->_context
.retain
) {
885 context_info
= (void *)ms
->_context
.retain(ms
->_context
.info
);
886 context_release
= ms
->_context
.release
;
888 context_info
= ms
->_context
.info
;
889 context_release
= NULL
;
891 __CFMessagePortUnlock(ms
);
892 /* Create no-copy, no-free-bytes wrapper CFData */
893 if (0 == msgp
->body
.msgh_descriptor_count
) {
894 int32_t byteslen
= CFSwapInt32LittleToHost(msgp
->contents
.msg0
.byteslen
);
895 msgid
= CFSwapInt32LittleToHost(msgp
->contents
.msg0
.msgid
);
897 data
= CFDataCreateWithBytesNoCopy(kCFAllocatorSystemDefault
, msgp
->contents
.msg0
.bytes
, byteslen
, kCFAllocatorNull
);
900 msgid
= CFSwapInt32LittleToHost(msgp
->contents
.msg1
.msgid
);
901 data
= CFDataCreateWithBytesNoCopy(kCFAllocatorSystemDefault
, msgp
->contents
.msg1
.desc
.out_of_line
.address
, msgp
->contents
.msg1
.desc
.out_of_line
.size
, kCFAllocatorNull
);
903 returnData
= ms
->_callout(ms
, msgid
, data
, context_info
);
904 /* Now, returnData could be (1) NULL, (2) an ordinary data < MAX_INLINE,
905 (3) ordinary data >= MAX_INLINE, (4) a no-copy data < MAX_INLINE,
906 (5) a no-copy data >= MAX_INLINE. In cases (2) and (4), we send the return
907 bytes inline in the Mach message, so can release the returnData object
908 here. In cases (3) and (5), we'll send the data out-of-line, we need to
909 create a copy of the memory, which we'll have the kernel autodeallocate
910 for us on send. In case (4) also, the bytes in the return data may be part
911 of the bytes in "data" that we sent into the callout, so if the incoming
912 data was received out of line, we wouldn't be able to clean up the out-of-line
913 wad until the message was sent either, if we didn't make the copy. */
914 if (NULL
!= returnData
) {
915 return_len
= CFDataGetLength(returnData
);
916 if (return_len
< __CFMessagePortMaxInlineBytes
) {
917 return_bytes
= (void *)CFDataGetBytePtr(returnData
);
920 vm_allocate(mach_task_self(), (vm_address_t
*)&return_bytes
, return_len
, VM_FLAGS_ANYWHERE
| VM_MAKE_TAG(VM_MEMORY_MACH_MSG
));
921 /* vm_copy would only be a win here if the source address
922 is page aligned; it is a lose in all other cases, since
923 the kernel will just do the memmove for us (but not in
925 memmove(return_bytes
, CFDataGetBytePtr(returnData
), return_len
);
928 replymsg
= __CFMessagePortCreateMessage(allocator
, true, msgp
->head
.msgh_remote_port
, MACH_PORT_NULL
, -1 * (int32_t)msgp
->head
.msgh_id
, msgid
, return_bytes
, return_len
);
929 if (1 == replymsg
->body
.msgh_descriptor_count
) {
930 replymsg
->contents
.msg1
.desc
.out_of_line
.deallocate
= true;
932 if (data
) CFRelease(data
);
933 if (1 == msgp
->body
.msgh_descriptor_count
) {
934 vm_deallocate(mach_task_self(), (vm_address_t
)msgp
->contents
.msg1
.desc
.out_of_line
.address
, msgp
->contents
.msg1
.desc
.out_of_line
.size
);
936 if (returnData
) CFRelease(returnData
);
937 if (context_release
) {
938 context_release(context_info
);
943 CFRunLoopSourceRef
CFMessagePortCreateRunLoopSource(CFAllocatorRef allocator
, CFMessagePortRef ms
, CFIndex order
) {
944 CFRunLoopSourceRef result
= NULL
;
945 __CFGenericValidateType(ms
, __kCFMessagePortTypeID
);
946 //#warning CF: This should be an assert
947 // if (__CFMessagePortIsRemote(ms)) return NULL;
948 __CFMessagePortLock(ms
);
949 if (NULL
== ms
->_source
&& __CFMessagePortIsValid(ms
)) {
950 CFRunLoopSourceContext1 context
;
952 context
.info
= (void *)ms
;
953 context
.retain
= (const void *(*)(const void *))CFRetain
;
954 context
.release
= (void (*)(const void *))CFRelease
;
955 context
.copyDescription
= (CFStringRef (*)(const void *))__CFMessagePortCopyDescription
;
956 context
.equal
= NULL
;
958 context
.getPort
= __CFMessagePortGetPort
;
959 context
.perform
= __CFMessagePortPerform
;
960 ms
->_source
= CFRunLoopSourceCreate(allocator
, order
, (CFRunLoopSourceContext
*)&context
);
962 if (NULL
!= ms
->_source
) {
963 result
= (CFRunLoopSourceRef
)CFRetain(ms
->_source
);
965 __CFMessagePortUnlock(ms
);