]> git.saurik.com Git - apple/cf.git/blob - CFMessagePort.c
CF-476.10.tar.gz
[apple/cf.git] / CFMessagePort.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 /* CFMessagePort.c
24 Copyright 1998-2002, Apple, Inc. All rights reserved.
25 Responsibility: Christopher Kane
26 */
27
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>
33 #include <limits.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>
39 #include <math.h>
40 #include <mach/mach_time.h>
41 #include <dlfcn.h>
42
43
44 #define __kCFMessagePortMaxNameLengthMax 255
45
46 #if defined(BOOTSTRAP_MAX_NAME_LEN)
47 #define __kCFMessagePortMaxNameLength BOOTSTRAP_MAX_NAME_LEN
48 #else
49 #define __kCFMessagePortMaxNameLength 128
50 #endif
51
52 #if __kCFMessagePortMaxNameLengthMax < __kCFMessagePortMaxNameLength
53 #undef __kCFMessagePortMaxNameLength
54 #define __kCFMessagePortMaxNameLength __kCFMessagePortMaxNameLengthMax
55 #endif
56
57 static CFSpinLock_t __CFAllMessagePortsLock = CFSpinLockInit;
58 static CFMutableDictionaryRef __CFAllLocalMessagePorts = NULL;
59 static CFMutableDictionaryRef __CFAllRemoteMessagePorts = NULL;
60
61 struct __CFMessagePort {
62 CFRuntimeBase _base;
63 CFSpinLock_t _lock;
64 CFStringRef _name;
65 CFMachPortRef _port; /* immutable; invalidated */
66 CFMutableDictionaryRef _replies;
67 int32_t _convCounter;
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 */
74 };
75
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 */
80
81 CF_INLINE Boolean __CFMessagePortIsValid(CFMessagePortRef ms) {
82 return (Boolean)__CFBitfieldGetValue(((const CFRuntimeBase *)ms)->_cfinfo[CF_INFO_BITS], 0, 0);
83 }
84
85 CF_INLINE void __CFMessagePortSetValid(CFMessagePortRef ms) {
86 __CFBitfieldSetValue(((CFRuntimeBase *)ms)->_cfinfo[CF_INFO_BITS], 0, 0, 1);
87 }
88
89 CF_INLINE void __CFMessagePortUnsetValid(CFMessagePortRef ms) {
90 __CFBitfieldSetValue(((CFRuntimeBase *)ms)->_cfinfo[CF_INFO_BITS], 0, 0, 0);
91 }
92
93 CF_INLINE Boolean __CFMessagePortExtraMachRef(CFMessagePortRef ms) {
94 return (Boolean)__CFBitfieldGetValue(((const CFRuntimeBase *)ms)->_cfinfo[CF_INFO_BITS], 1, 1);
95 }
96
97 CF_INLINE void __CFMessagePortSetExtraMachRef(CFMessagePortRef ms) {
98 __CFBitfieldSetValue(((CFRuntimeBase *)ms)->_cfinfo[CF_INFO_BITS], 1, 1, 1);
99 }
100
101 CF_INLINE void __CFMessagePortUnsetExtraMachRef(CFMessagePortRef ms) {
102 __CFBitfieldSetValue(((CFRuntimeBase *)ms)->_cfinfo[CF_INFO_BITS], 1, 1, 0);
103 }
104
105 CF_INLINE Boolean __CFMessagePortIsRemote(CFMessagePortRef ms) {
106 return (Boolean)__CFBitfieldGetValue(((const CFRuntimeBase *)ms)->_cfinfo[CF_INFO_BITS], 2, 2);
107 }
108
109 CF_INLINE void __CFMessagePortSetRemote(CFMessagePortRef ms) {
110 __CFBitfieldSetValue(((CFRuntimeBase *)ms)->_cfinfo[CF_INFO_BITS], 2, 2, 1);
111 }
112
113 CF_INLINE void __CFMessagePortUnsetRemote(CFMessagePortRef ms) {
114 __CFBitfieldSetValue(((CFRuntimeBase *)ms)->_cfinfo[CF_INFO_BITS], 2, 2, 0);
115 }
116
117 CF_INLINE Boolean __CFMessagePortIsDeallocing(CFMessagePortRef ms) {
118 return (Boolean)__CFBitfieldGetValue(((const CFRuntimeBase *)ms)->_cfinfo[CF_INFO_BITS], 3, 3);
119 }
120
121 CF_INLINE void __CFMessagePortSetIsDeallocing(CFMessagePortRef ms) {
122 __CFBitfieldSetValue(((CFRuntimeBase *)ms)->_cfinfo[CF_INFO_BITS], 3, 3, 1);
123 }
124
125 CF_INLINE void __CFMessagePortLock(CFMessagePortRef ms) {
126 __CFSpinLock(&(ms->_lock));
127 }
128
129 CF_INLINE void __CFMessagePortUnlock(CFMessagePortRef ms) {
130 __CFSpinUnlock(&(ms->_lock));
131 }
132
133 // Just a heuristic
134 #define __CFMessagePortMaxInlineBytes 4096*10
135
136 struct __CFMessagePortMachMsg0 {
137 int32_t msgid;
138 int32_t byteslen;
139 uint8_t bytes[__CFMessagePortMaxInlineBytes];
140 };
141
142 struct __CFMessagePortMachMsg1 {
143 mach_msg_descriptor_t desc;
144 int32_t msgid;
145 };
146
147 struct __CFMessagePortMachMessage {
148 mach_msg_header_t head;
149 mach_msg_body_t body;
150 union {
151 struct __CFMessagePortMachMsg0 msg0;
152 struct __CFMessagePortMachMsg1 msg1;
153 } contents;
154 };
155
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);
161 } else {
162 size += sizeof(struct __CFMessagePortMachMsg1);
163 }
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);
178 }
179 memset(msg->contents.msg0.bytes + byteslen, 0, ((byteslen + 3) & ~0x3) - byteslen);
180 } else {
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);
189 }
190 return msg;
191 }
192
193 static CFStringRef __CFMessagePortCopyDescription(CFTypeRef cf) {
194 CFMessagePortRef ms = (CFMessagePortRef)cf;
195 CFStringRef result;
196 const char *locked;
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);
202 }
203 if (NULL == contextDesc) {
204 contextDesc = CFStringCreateWithFormat(kCFAllocatorSystemDefault, NULL, CFSTR("<CFMessagePort context %p>"), ms->_context.info);
205 }
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);
207 } else {
208 void *addr = ms->_callout;
209 Dl_info info;
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>")));
212 }
213 if (NULL != contextDesc) {
214 CFRelease(contextDesc);
215 }
216 return result;
217 }
218
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);
227 }
228 if (NULL != ms->_name) {
229 CFRelease(ms->_name);
230 }
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);
235 }
236 CFMachPortInvalidate(ms->_port);
237 CFRelease(ms->_port);
238 }
239
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;
248 CFIndex cnt = 0;
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]);
255 }
256 }
257 __CFSpinUnlock(&__CFAllMessagePortsLock);
258 if (remotePorts) {
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]);
263 }
264 CFAllocatorDeallocate(kCFAllocatorSystemDefault, remotePorts);
265 }
266 }
267
268 static CFTypeID __kCFMessagePortTypeID = _kCFRuntimeNotATypeID;
269
270 static const CFRuntimeClass __CFMessagePortClass = {
271 0,
272 "CFMessagePort",
273 NULL, // init
274 NULL, // copy
275 __CFMessagePortDeallocate,
276 NULL,
277 NULL,
278 NULL, //
279 __CFMessagePortCopyDescription
280 };
281
282 __private_extern__ void __CFMessagePortInitialize(void) {
283 __kCFMessagePortTypeID = _CFRuntimeRegisterClass(&__CFMessagePortClass);
284 }
285
286 CFTypeID CFMessagePortGetTypeID(void) {
287 return __kCFMessagePortTypeID;
288 }
289
290 static CFStringRef __CFMessagePortSanitizeStringName(CFAllocatorRef allocator, CFStringRef name, uint8_t **utfnamep, CFIndex *utfnamelenp) {
291 uint8_t *utfname;
292 CFIndex utflen;
293 CFStringRef result;
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) {
303 *utfnamep = utfname;
304 } else {
305 CFAllocatorDeallocate(allocator, utfname);
306 }
307 if (NULL != utfnamelenp) {
308 *utfnamelenp = utflen;
309 }
310 return result;
311 }
312
313 static void __CFMessagePortDummyCallback(CFMachPortRef port, void *msg, CFIndex size, void *info) {
314 // not supposed to be implemented
315 }
316
317 static void __CFMessagePortInvalidationCallBack(CFMachPortRef port, void *info) {
318 // info has been setup as the CFMessagePort owning the CFMachPort
319 CFMessagePortInvalidate(info);
320 }
321
322 static CFMessagePortRef __CFMessagePortCreateLocal(CFAllocatorRef allocator, CFStringRef name, CFMessagePortCallBack callout, CFMessagePortContext *context, Boolean *shouldFreeInfo, Boolean perPID) {
323 CFMessagePortRef memory;
324 uint8_t *utfname = NULL;
325
326 if (shouldFreeInfo) *shouldFreeInfo = true;
327 if (NULL != name) {
328 name = __CFMessagePortSanitizeStringName(allocator, name, &utfname, NULL);
329 }
330 __CFSpinLock(&__CFAllMessagePortsLock);
331 if (!perPID && NULL != name) {
332 CFMessagePortRef existing;
333 if (NULL != __CFAllLocalMessagePorts && CFDictionaryGetValueIfPresent(__CFAllLocalMessagePorts, name, (const void **)&existing)) {
334 CFRetain(existing);
335 __CFSpinUnlock(&__CFAllMessagePortsLock);
336 CFRelease(name);
337 CFAllocatorDeallocate(allocator, utfname);
338 return (CFMessagePortRef)(existing);
339 }
340 }
341 __CFSpinUnlock(&__CFAllMessagePortsLock);
342 CFIndex size = sizeof(struct __CFMessagePort) - sizeof(CFRuntimeBase);
343 memory = (CFMessagePortRef)_CFRuntimeCreateInstance(allocator, __kCFMessagePortTypeID, size, NULL);
344 if (NULL == memory) {
345 if (NULL != name) {
346 CFRelease(name);
347 }
348 CFAllocatorDeallocate(allocator, utfname);
349 return NULL;
350 }
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;
368
369 if (NULL != name) {
370 CFMachPortRef native = NULL;
371 kern_return_t ret;
372 mach_port_t bs, mp;
373 task_get_bootstrap_port(mach_task_self(), &bs);
374 if (!perPID) {
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);
382 } else {
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
387 CFRelease(memory);
388 return NULL;
389 }
390 }
391 }
392 if (!native) {
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);
400 CFRelease(native);
401 CFAllocatorDeallocate(allocator, utfname);
402 // name is released by deallocation
403 CFRelease(memory);
404 return NULL;
405 }
406 }
407 CFMachPortSetInvalidationCallBack(native, __CFMessagePortInvalidationCallBack);
408 memory->_port = native;
409 }
410
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;
416 }
417 __CFSpinLock(&__CFAllMessagePortsLock);
418 if (!perPID && NULL != name) {
419 CFMessagePortRef existing;
420 if (NULL != __CFAllLocalMessagePorts && CFDictionaryGetValueIfPresent(__CFAllLocalMessagePorts, name, (const void **)&existing)) {
421 CFRetain(existing);
422 __CFSpinUnlock(&__CFAllMessagePortsLock);
423 CFRelease(memory);
424 return (CFMessagePortRef)(existing);
425 }
426 if (NULL == __CFAllLocalMessagePorts) {
427 __CFAllLocalMessagePorts = CFDictionaryCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeDictionaryKeyCallBacks, NULL);
428 }
429 CFDictionaryAddValue(__CFAllLocalMessagePorts, name, memory);
430 }
431 __CFSpinUnlock(&__CFAllMessagePortsLock);
432 if (shouldFreeInfo) *shouldFreeInfo = false;
433 return memory;
434 }
435
436 CFMessagePortRef CFMessagePortCreateLocal(CFAllocatorRef allocator, CFStringRef name, CFMessagePortCallBack callout, CFMessagePortContext *context, Boolean *shouldFreeInfo) {
437 return __CFMessagePortCreateLocal(allocator, name, callout, context, shouldFreeInfo, false);
438 }
439
440 CFMessagePortRef CFMessagePortCreatePerProcessLocal(CFAllocatorRef allocator, CFStringRef name, CFMessagePortCallBack callout, CFMessagePortContext *context, Boolean *shouldFreeInfo) {
441 return __CFMessagePortCreateLocal(allocator, name, callout, context, shouldFreeInfo, true);
442 }
443
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;
449 CFIndex size;
450 mach_port_t bp, port;
451 kern_return_t ret;
452
453 name = __CFMessagePortSanitizeStringName(allocator, name, &utfname, NULL);
454 if (NULL == name) {
455 return NULL;
456 }
457 __CFSpinLock(&__CFAllMessagePortsLock);
458 if (!perPID && NULL != name) {
459 CFMessagePortRef existing;
460 if (NULL != __CFAllRemoteMessagePorts && CFDictionaryGetValueIfPresent(__CFAllRemoteMessagePorts, name, (const void **)&existing)) {
461 CFRetain(existing);
462 __CFSpinUnlock(&__CFAllMessagePortsLock);
463 CFRelease(name);
464 CFAllocatorDeallocate(allocator, utfname);
465 return (CFMessagePortRef)(existing);
466 }
467 }
468 __CFSpinUnlock(&__CFAllMessagePortsLock);
469 size = sizeof(struct __CFMessagePort) - sizeof(CFMessagePortContext) - sizeof(CFRuntimeBase);
470 memory = (CFMessagePortRef)_CFRuntimeCreateInstance(allocator, __kCFMessagePortTypeID, size, NULL);
471 if (NULL == memory) {
472 if (NULL != name) {
473 CFRelease(name);
474 }
475 CFAllocatorDeallocate(allocator, utfname);
476 return NULL;
477 }
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;
491 ctx.version = 0;
492 ctx.info = memory;
493 ctx.retain = NULL;
494 ctx.release = 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
502 CFRelease(memory);
503 return NULL;
504 }
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)) {
512 CFRetain(existing);
513 __CFSpinUnlock(&__CFAllMessagePortsLock);
514 CFRelease(memory);
515 return (CFMessagePortRef)(existing);
516 }
517 if (NULL == __CFAllRemoteMessagePorts) {
518 __CFAllRemoteMessagePorts = CFDictionaryCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeDictionaryKeyCallBacks, NULL);
519 }
520 CFDictionaryAddValue(__CFAllRemoteMessagePorts, name, memory);
521 }
522 __CFSpinUnlock(&__CFAllMessagePortsLock);
523 return (CFMessagePortRef)memory;
524 }
525
526 CFMessagePortRef CFMessagePortCreateRemote(CFAllocatorRef allocator, CFStringRef name) {
527 return __CFMessagePortCreateRemote(allocator, name, false, 0);
528 }
529
530 CFMessagePortRef CFMessagePortCreatePerProcessRemote(CFAllocatorRef allocator, CFStringRef name, CFIndex pid) {
531 return __CFMessagePortCreateRemote(allocator, name, true, pid);
532 }
533
534 Boolean CFMessagePortIsRemote(CFMessagePortRef ms) {
535 __CFGenericValidateType(ms, __kCFMessagePortTypeID);
536 return __CFMessagePortIsRemote(ms);
537 }
538
539 CFStringRef CFMessagePortGetName(CFMessagePortRef ms) {
540 __CFGenericValidateType(ms, __kCFMessagePortTypeID);
541 return ms->_name;
542 }
543
544 Boolean CFMessagePortSetName(CFMessagePortRef ms, CFStringRef name) {
545 CFAllocatorRef allocator = CFGetAllocator(ms);
546 uint8_t *utfname = NULL;
547
548 __CFGenericValidateType(ms, __kCFMessagePortTypeID);
549 if (ms->_perPID || __CFMessagePortIsRemote(ms)) return false;
550 name = __CFMessagePortSanitizeStringName(allocator, name, &utfname, NULL);
551 if (NULL == name) {
552 return false;
553 }
554 __CFSpinLock(&__CFAllMessagePortsLock);
555 if (NULL != name) {
556 CFMessagePortRef existing;
557 if (NULL != __CFAllLocalMessagePorts && CFDictionaryGetValueIfPresent(__CFAllLocalMessagePorts, name, (const void **)&existing)) {
558 __CFSpinUnlock(&__CFAllMessagePortsLock);
559 CFRelease(name);
560 CFAllocatorDeallocate(allocator, utfname);
561 return false;
562 }
563 }
564 __CFSpinUnlock(&__CFAllMessagePortsLock);
565
566 if (NULL != name && (NULL == ms->_name || !CFEqual(ms->_name, name))) {
567 CFMachPortRef oldPort = ms->_port;
568 CFMachPortRef native = NULL;
569 kern_return_t ret;
570 mach_port_t bs, mp;
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);
579 } else {
580 mach_port_destroy(mach_task_self(), mp);
581 CFAllocatorDeallocate(allocator, utfname);
582 CFRelease(name);
583 return false;
584 }
585 }
586 if (!native) {
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);
594 CFRelease(native);
595 CFAllocatorDeallocate(allocator, utfname);
596 CFRelease(name);
597 return false;
598 }
599 }
600 CFMachPortSetInvalidationCallBack(native, __CFMessagePortInvalidationCallBack);
601 ms->_port = native;
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);
606 }
607 CFMachPortInvalidate(oldPort);
608 CFRelease(oldPort);
609 }
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);
620 }
621 if (NULL != ms->_name) {
622 CFDictionaryRemoveValue(__CFAllLocalMessagePorts, ms->_name);
623 CFRelease(ms->_name);
624 }
625 ms->_name = name;
626 CFDictionaryAddValue(__CFAllLocalMessagePorts, name, ms);
627 __CFSpinUnlock(&__CFAllMessagePortsLock);
628 }
629
630 CFAllocatorDeallocate(allocator, utfname);
631 return true;
632 }
633
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));
639 }
640
641 void CFMessagePortInvalidate(CFMessagePortRef ms) {
642 __CFGenericValidateType(ms, __kCFMessagePortTypeID);
643 if (!__CFMessagePortIsDeallocing(ms)) {
644 CFRetain(ms);
645 }
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;
653 void *info = NULL;
654
655 __CFMessagePortUnsetValid(ms);
656 if (!__CFMessagePortIsRemote(ms)) {
657 info = ms->_context.info;
658 ms->_context.info = NULL;
659 }
660 ms->_source = NULL;
661 ms->_replyPort = NULL;
662 __CFMessagePortUnlock(ms);
663
664 __CFSpinLock(&__CFAllMessagePortsLock);
665 if (0 == ms->_perPID && NULL != (__CFMessagePortIsRemote(ms) ? __CFAllRemoteMessagePorts : __CFAllLocalMessagePorts)) {
666 CFDictionaryRemoveValue(__CFMessagePortIsRemote(ms) ? __CFAllRemoteMessagePorts : __CFAllLocalMessagePorts, name);
667 }
668 __CFSpinUnlock(&__CFAllMessagePortsLock);
669 if (NULL != callout) {
670 callout(ms, info);
671 }
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);
681 }
682 if (NULL != source) {
683 CFRunLoopSourceInvalidate(source);
684 CFRelease(source);
685 }
686 if (NULL != replyPort) {
687 CFMachPortInvalidate(replyPort);
688 CFRelease(replyPort);
689 }
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));
693 }
694 } else {
695 __CFMessagePortUnlock(ms);
696 }
697 if (!__CFMessagePortIsDeallocing(ms)) {
698 CFRelease(ms);
699 }
700 }
701
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);
707 return false;
708 }
709 if (NULL != ms->_replyPort && !CFMachPortIsValid(ms->_replyPort)) {
710 CFMessagePortInvalidate(ms);
711 return false;
712 }
713 if (NULL != ms->_source && !CFRunLoopSourceIsValid(ms->_source)) {
714 CFMessagePortInvalidate(ms);
715 return false;
716 }
717 return true;
718 }
719
720 CFMessagePortInvalidationCallBack CFMessagePortGetInvalidationCallBack(CFMessagePortRef ms) {
721 __CFGenericValidateType(ms, __kCFMessagePortTypeID);
722 return ms->_icallout;
723 }
724
725 void CFMessagePortSetInvalidationCallBack(CFMessagePortRef ms, CFMessagePortInvalidationCallBack callout) {
726 __CFGenericValidateType(ms, __kCFMessagePortTypeID);
727 if (!__CFMessagePortIsValid(ms) && NULL != callout) {
728 callout(ms, ms->_context.info);
729 } else {
730 ms->_icallout = callout;
731 }
732 }
733
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);
741 return;
742 }
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);
749 if (0 <= byteslen) {
750 reply = CFDataCreate(kCFAllocatorSystemDefault, replymsg->contents.msg0.bytes, byteslen);
751 } else {
752 reply = (void *)~0; // means NULL data
753 }
754 } else {
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);
758 }
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);
763 }
764 }
765 __CFMessagePortUnlock(ms);
766 }
767
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;
773 int64_t termTSR;
774 uint32_t sendOpts = 0, sendTimeOut = 0;
775 int32_t desiredReply;
776 Boolean didRegister = false;
777 kern_return_t ret;
778
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;
785 context.version = 0;
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);
791 }
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);
800 if (didRegister) {
801 CFRunLoopAddSource(currentRL, source, replyMode);
802 }
803 }
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);
810 }
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);
815 if (didRegister) {
816 CFRunLoopRemoveSource(currentRL, source, replyMode);
817 }
818 if (source) CFRelease(source);
819 CFAllocatorDeallocate(kCFAllocatorSystemDefault, sendmsg);
820 return (MACH_SEND_TIMED_OUT == ret) ? kCFMessagePortSendTimeout : kCFMessagePortTransportError;
821 }
822 CFAllocatorDeallocate(kCFAllocatorSystemDefault, sendmsg);
823 if (replyMode == NULL) {
824 return kCFMessagePortSuccess;
825 }
826 CFRetain(remote); // retain during run loop to avoid invalidation causing freeing
827 _CFMachPortInstallNotifyPort(currentRL, replyMode);
828 termTSR = mach_absolute_time() + __CFTimeIntervalToTSR(rcvTimeout);
829 for (;;) {
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()) {
834 break;
835 }
836 if (!CFMessagePortIsValid(remote)) {
837 // no reason that reply port alone should go invalid so we don't check for that
838 break;
839 }
840 }
841 // Should we uninstall the notify port? A complex question...
842 if (didRegister) {
843 CFRunLoopRemoveSource(currentRL, source, replyMode);
844 }
845 if (source) CFRelease(source);
846 if (NULL == reply) {
847 CFDictionaryRemoveValue(remote->_replies, (void *)(uintptr_t)desiredReply);
848 CFRelease(remote);
849 return CFMessagePortIsValid(remote) ? kCFMessagePortReceiveTimeout : -5;
850 }
851 if (NULL != returnDatap) {
852 *returnDatap = ((void *)~0 == reply) ? NULL : reply;
853 } else if ((void *)~0 != reply) {
854 CFRelease(reply);
855 }
856 CFDictionaryRemoveValue(remote->_replies, (void *)(uintptr_t)desiredReply);
857 CFRelease(remote);
858 return kCFMessagePortSuccess;
859 }
860
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;
865 }
866
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;
871 void *context_info;
872 void (*context_release)(const void *);
873 CFDataRef returnData, data = NULL;
874 void *return_bytes = NULL;
875 CFIndex return_len = 0;
876 int32_t msgid;
877
878 __CFMessagePortLock(ms);
879 if (!__CFMessagePortIsValid(ms)) {
880 __CFMessagePortUnlock(ms);
881 return NULL;
882 }
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;
887 } else {
888 context_info = ms->_context.info;
889 context_release = NULL;
890 }
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);
896 if (0 <= byteslen) {
897 data = CFDataCreateWithBytesNoCopy(kCFAllocatorSystemDefault, msgp->contents.msg0.bytes, byteslen, kCFAllocatorNull);
898 }
899 } else {
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);
902 }
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);
918 } else {
919 return_bytes = NULL;
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
924 as simple a way). */
925 memmove(return_bytes, CFDataGetBytePtr(returnData), return_len);
926 }
927 }
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;
931 }
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);
935 }
936 if (returnData) CFRelease(returnData);
937 if (context_release) {
938 context_release(context_info);
939 }
940 return replymsg;
941 }
942
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;
951 context.version = 1;
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;
957 context.hash = NULL;
958 context.getPort = __CFMessagePortGetPort;
959 context.perform = __CFMessagePortPerform;
960 ms->_source = CFRunLoopSourceCreate(allocator, order, (CFRunLoopSourceContext *)&context);
961 }
962 if (NULL != ms->_source) {
963 result = (CFRunLoopSourceRef)CFRetain(ms->_source);
964 }
965 __CFMessagePortUnlock(ms);
966 return result;
967 }
968
969