/*
- * Copyright (c) 1999-2007 Apple Inc. All rights reserved.
+ * Copyright (c) 1999-2013 Apple Inc. All rights reserved.
*
* @APPLE_OSREFERENCE_LICENSE_HEADER_START@
*
#include <mach/message.h>
#include <mach/mig_errors.h>
#include <mach/vm_statistics.h>
+#include <TargetConditionals.h>
+
+extern int proc_importance_assertion_begin_with_msg(mach_msg_header_t * msg, mach_msg_trailer_t * trailer, uint64_t * assertion_handlep);
+extern int proc_importance_assertion_complete(uint64_t assertion_handle);
#define MACH_MSG_TRAP(msg, opt, ssize, rsize, rname, to, not) \
mach_msg_trap((msg), (opt), (ssize), (rsize), (rname), (to), (not))
case MACH_MSG_TYPE_MOVE_SEND:
case MACH_MSG_TYPE_MOVE_SEND_ONCE:
/* destroy the send/send-once right */
- (void) mach_port_deallocate(mach_task_self(), port);
+ (void) mach_port_deallocate(mach_task_self_, port);
break;
case MACH_MSG_TYPE_MOVE_RECEIVE:
/* destroy the receive right */
- (void) mach_port_mod_refs(mach_task_self(), port,
+ (void) mach_port_mod_refs(mach_task_self_, port,
MACH_PORT_RIGHT_RECEIVE, -1);
break;
case MACH_MSG_TYPE_MAKE_SEND:
/* create a send right and then destroy it */
- (void) mach_port_insert_right(mach_task_self(), port,
+ (void) mach_port_insert_right(mach_task_self_, port,
port, MACH_MSG_TYPE_MAKE_SEND);
- (void) mach_port_deallocate(mach_task_self(), port);
+ (void) mach_port_deallocate(mach_task_self_, port);
break;
case MACH_MSG_TYPE_MAKE_SEND_ONCE:
/* create a send-once right and then destroy it */
- (void) mach_port_extract_right(mach_task_self(), port,
+ (void) mach_port_extract_right(mach_task_self_, port,
MACH_MSG_TYPE_MAKE_SEND_ONCE,
&port, &type);
- (void) mach_port_deallocate(mach_task_self(), port);
+ (void) mach_port_deallocate(mach_task_self_, port);
break;
}
}
mach_msg_destroy_memory(vm_offset_t addr, vm_size_t size)
{
if (size != 0)
- (void) vm_deallocate(mach_task_self(), addr, size);
+ (void) vm_deallocate(mach_task_self_, addr, size);
}
*/
mach_msg_destroy_port(msg->msgh_remote_port, MACH_MSGH_BITS_REMOTE(mbits));
+ mach_msg_destroy_port(msg->msgh_voucher_port, MACH_MSGH_BITS_VOUCHER(mbits));
if (mbits & MACH_MSGH_BITS_COMPLEX) {
- mach_msg_body_t *body;
- mach_msg_descriptor_t *saddr, *eaddr;
+ mach_msg_base_t *base;
+ mach_msg_type_number_t count, i;
+ mach_msg_descriptor_t *daddr;
- body = (mach_msg_body_t *) (msg + 1);
- saddr = (mach_msg_descriptor_t *)
- ((mach_msg_base_t *) msg + 1);
- eaddr = saddr + body->msgh_descriptor_count;
+ base = (mach_msg_base_t *) msg;
+ count = base->body.msgh_descriptor_count;
+
+ daddr = (mach_msg_descriptor_t *) (base + 1);
+ for (i = 0; i < count; i++) {
- for ( ; saddr < eaddr; saddr++) {
- switch (saddr->type.type) {
+ switch (daddr->type.type) {
- case MACH_MSG_PORT_DESCRIPTOR: {
+ case MACH_MSG_PORT_DESCRIPTOR: {
mach_msg_port_descriptor_t *dsc;
/*
* Destroy port rights carried in the message
*/
- dsc = &saddr->port;
- mach_msg_destroy_port(dsc->name, dsc->disposition);
+ dsc = &daddr->port;
+ mach_msg_destroy_port(dsc->name, dsc->disposition);
+ daddr = (mach_msg_descriptor_t *)(dsc + 1);
break;
- }
+ }
- case MACH_MSG_OOL_DESCRIPTOR : {
+ case MACH_MSG_OOL_DESCRIPTOR: {
mach_msg_ool_descriptor_t *dsc;
/*
* Destroy memory carried in the message
*/
- dsc = &saddr->out_of_line;
+ dsc = &daddr->out_of_line;
if (dsc->deallocate) {
mach_msg_destroy_memory((vm_offset_t)dsc->address,
dsc->size);
}
+ daddr = (mach_msg_descriptor_t *)(dsc + 1);
+ break;
+ }
+
+ case MACH_MSG_OOL_VOLATILE_DESCRIPTOR: {
+ mach_msg_ool_descriptor_t *dsc;
+
+ /*
+ * Just skip it.
+ */
+ dsc = &daddr->out_of_line;
+ daddr = (mach_msg_descriptor_t *)(dsc + 1);
break;
- }
+ }
- case MACH_MSG_OOL_PORTS_DESCRIPTOR : {
+ case MACH_MSG_OOL_PORTS_DESCRIPTOR: {
mach_port_t *ports;
mach_msg_ool_ports_descriptor_t *dsc;
mach_msg_type_number_t j;
/*
* Destroy port rights carried in the message
*/
- dsc = &saddr->ool_ports;
+ dsc = &daddr->ool_ports;
ports = (mach_port_t *) dsc->address;
for (j = 0; j < dsc->count; j++, ports++) {
mach_msg_destroy_port(*ports, dsc->disposition);
mach_msg_destroy_memory((vm_offset_t)dsc->address,
dsc->count * sizeof(mach_port_t));
}
+ daddr = (mach_msg_descriptor_t *)(dsc + 1);
break;
- }
+ }
}
}
}
mach_msg_size_t reply_alloc;
mach_msg_return_t mr;
kern_return_t kr;
- mach_port_t self = mach_task_self();
+ mach_port_t self = mach_task_self_;
+ voucher_mach_msg_state_t old_state = VOUCHER_MACH_MSG_STATE_UNCHANGED;
- options &= ~(MACH_SEND_MSG|MACH_RCV_MSG);
+ options &= ~(MACH_SEND_MSG|MACH_RCV_MSG|MACH_RCV_VOUCHER);
trailer_alloc = REQUESTED_TRAILER_SIZE(options);
- request_alloc = round_page(max_size + trailer_alloc);
+ request_alloc = (mach_msg_size_t)round_page(max_size + trailer_alloc);
request_size = (options & MACH_RCV_LARGE) ?
request_alloc : max_size + trailer_alloc;
- reply_alloc = round_page((options & MACH_SEND_TRAILER) ?
+ reply_alloc = (mach_msg_size_t)round_page((options & MACH_SEND_TRAILER) ?
(max_size + MAX_TRAILER_SIZE) :
max_size);
return kr;
}
- mr = mach_msg(&bufRequest->Head, MACH_RCV_MSG|options,
+ mr = mach_msg(&bufRequest->Head, MACH_RCV_MSG|MACH_RCV_VOUCHER|options,
0, request_size, rcv_name,
MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL);
if (!((mr == MACH_RCV_TOO_LARGE) && (options & MACH_RCV_LARGE)))
break;
- new_request_alloc = round_page(bufRequest->Head.msgh_size +
+ new_request_alloc = (mach_msg_size_t)round_page(bufRequest->Head.msgh_size +
trailer_alloc);
vm_deallocate(self,
(vm_address_t) bufRequest,
if (mr == MACH_MSG_SUCCESS) {
/* we have a request message */
+ old_state = voucher_mach_msg_adopt(&bufRequest->Head);
+
(void) (*demux)(&bufRequest->Head, &bufReply->Head);
if (!(bufReply->Head.msgh_bits & MACH_MSGH_BITS_COMPLEX)) {
}
done_once:
+ voucher_mach_msg_revert(old_state);
+
(void)vm_deallocate(self,
(vm_address_t) bufRequest,
request_alloc);
mach_msg_size_t reply_alloc;
mach_msg_return_t mr;
kern_return_t kr;
- mach_port_t self = mach_task_self();
+ mach_port_t self = mach_task_self_;
+ voucher_mach_msg_state_t old_state = VOUCHER_MACH_MSG_STATE_UNCHANGED;
+ boolean_t buffers_swapped = FALSE;
- options &= ~(MACH_SEND_MSG|MACH_RCV_MSG|MACH_RCV_OVERWRITE);
+ options &= ~(MACH_SEND_MSG|MACH_RCV_MSG|MACH_RCV_VOUCHER|MACH_RCV_OVERWRITE);
- reply_alloc = round_page((options & MACH_SEND_TRAILER) ?
- (max_size + MAX_TRAILER_SIZE) : max_size);
+ reply_alloc = (mach_msg_size_t)round_page((options & MACH_SEND_TRAILER) ?
+ (max_size + MAX_TRAILER_SIZE) : max_size);
kr = vm_allocate(self,
- (vm_address_t *)&bufReply,
- reply_alloc,
- VM_MAKE_TAG(VM_MEMORY_MACH_MSG)|TRUE);
- if (kr != KERN_SUCCESS)
+ (vm_address_t *)&bufReply,
+ reply_alloc,
+ VM_MAKE_TAG(VM_MEMORY_MACH_MSG)|TRUE);
+ if (kr != KERN_SUCCESS)
return kr;
request_alloc = 0;
trailer_alloc = REQUESTED_TRAILER_SIZE(options);
- new_request_alloc = round_page(max_size + trailer_alloc);
+ new_request_alloc = (mach_msg_size_t)round_page(max_size + trailer_alloc);
request_size = (options & MACH_RCV_LARGE) ?
- new_request_alloc : max_size + trailer_alloc;
+ new_request_alloc : max_size + trailer_alloc;
for (;;) {
if (request_alloc < new_request_alloc) {
request_alloc = new_request_alloc;
kr = vm_allocate(self,
- (vm_address_t *)&bufRequest,
- request_alloc,
- VM_MAKE_TAG(VM_MEMORY_MACH_MSG)|TRUE);
+ (vm_address_t *)&bufRequest,
+ request_alloc,
+ VM_MAKE_TAG(VM_MEMORY_MACH_MSG)|TRUE);
if (kr != KERN_SUCCESS) {
vm_deallocate(self,
- (vm_address_t)bufReply,
- reply_alloc);
+ (vm_address_t)bufReply,
+ reply_alloc);
return kr;
}
}
-
- mr = mach_msg(&bufRequest->Head, MACH_RCV_MSG|options,
- 0, request_size, rcv_name,
- MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL);
-
+
+ mr = mach_msg(&bufRequest->Head, MACH_RCV_MSG|MACH_RCV_VOUCHER|options,
+ 0, request_size, rcv_name,
+ MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL);
+
while (mr == MACH_MSG_SUCCESS) {
/* we have another request message */
+ buffers_swapped = FALSE;
+ old_state = voucher_mach_msg_adopt(&bufRequest->Head);
+
(void) (*demux)(&bufRequest->Head, &bufReply->Head);
if (!(bufReply->Head.msgh_bits & MACH_MSGH_BITS_COMPLEX)) {
if (bufReply->RetCode == MIG_NO_REPLY)
bufReply->Head.msgh_remote_port = MACH_PORT_NULL;
else if ((bufReply->RetCode != KERN_SUCCESS) &&
- (bufRequest->Head.msgh_bits & MACH_MSGH_BITS_COMPLEX)) {
+ (bufRequest->Head.msgh_bits & MACH_MSGH_BITS_COMPLEX)) {
/* destroy the request - but not the reply port */
bufRequest->Head.msgh_remote_port = MACH_PORT_NULL;
mach_msg_destroy(&bufRequest->Head);
mig_reply_error_t *bufTemp;
mr = mach_msg(
- &bufReply->Head,
- (MACH_MSGH_BITS_REMOTE(bufReply->Head.msgh_bits) ==
- MACH_MSG_TYPE_MOVE_SEND_ONCE) ?
- MACH_SEND_MSG|MACH_RCV_MSG|options :
- MACH_SEND_MSG|MACH_RCV_MSG|MACH_SEND_TIMEOUT|options,
- bufReply->Head.msgh_size, request_size, rcv_name,
- MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL);
+ &bufReply->Head,
+ (MACH_MSGH_BITS_REMOTE(bufReply->Head.msgh_bits) ==
+ MACH_MSG_TYPE_MOVE_SEND_ONCE) ?
+ MACH_SEND_MSG|MACH_RCV_MSG|MACH_RCV_TIMEOUT|MACH_RCV_VOUCHER|options :
+ MACH_SEND_MSG|MACH_RCV_MSG|MACH_SEND_TIMEOUT|MACH_RCV_TIMEOUT|MACH_RCV_VOUCHER|options,
+ bufReply->Head.msgh_size, request_size, rcv_name,
+ MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL);
/* swap request and reply */
bufTemp = bufRequest;
bufRequest = bufReply;
bufReply = bufTemp;
-
+ buffers_swapped = TRUE;
} else {
mr = mach_msg_overwrite(
&bufReply->Head,
(MACH_MSGH_BITS_REMOTE(bufReply->Head.msgh_bits) ==
MACH_MSG_TYPE_MOVE_SEND_ONCE) ?
- MACH_SEND_MSG|MACH_RCV_MSG|options :
- MACH_SEND_MSG|MACH_RCV_MSG|MACH_SEND_TIMEOUT|options,
+ MACH_SEND_MSG|MACH_RCV_MSG|MACH_RCV_TIMEOUT|MACH_RCV_VOUCHER|options :
+ MACH_SEND_MSG|MACH_RCV_MSG|MACH_SEND_TIMEOUT|MACH_RCV_TIMEOUT|MACH_RCV_VOUCHER|options,
bufReply->Head.msgh_size, request_size, rcv_name,
MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL,
&bufRequest->Head, 0);
}
-
+
if ((mr != MACH_SEND_INVALID_DEST) &&
- (mr != MACH_SEND_TIMED_OUT))
+ (mr != MACH_SEND_TIMED_OUT) &&
+ (mr != MACH_RCV_TIMED_OUT)) {
+
+ voucher_mach_msg_revert(old_state);
+ old_state = VOUCHER_MACH_MSG_STATE_UNCHANGED;
+
continue;
+ }
+ }
+ /*
+ * Need to destroy the reply msg in case if there was a send timeout or
+ * invalid destination. The reply msg would be swapped with request msg
+ * if buffers_swapped is true, thus destroy request msg instead of
+ * reply msg in such cases.
+ */
+ if (mr != MACH_RCV_TIMED_OUT) {
+ if (buffers_swapped) {
+ if (bufRequest->Head.msgh_bits & MACH_MSGH_BITS_COMPLEX)
+ mach_msg_destroy(&bufRequest->Head);
+ } else {
+ if (bufReply->Head.msgh_bits & MACH_MSGH_BITS_COMPLEX)
+ mach_msg_destroy(&bufReply->Head);
+ }
}
- if (bufReply->Head.msgh_bits & MACH_MSGH_BITS_COMPLEX)
- mach_msg_destroy(&bufReply->Head);
+ voucher_mach_msg_revert(old_state);
+ old_state = VOUCHER_MACH_MSG_STATE_UNCHANGED;
- mr = mach_msg(&bufRequest->Head, MACH_RCV_MSG|options,
- 0, request_size, rcv_name,
- MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL);
+ mr = mach_msg(&bufRequest->Head, MACH_RCV_MSG|MACH_RCV_VOUCHER|options,
+ 0, request_size, rcv_name,
+ MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL);
} /* while (mr == MACH_MSG_SUCCESS) */
-
+
if ((mr == MACH_RCV_TOO_LARGE) && (options & MACH_RCV_LARGE)) {
- new_request_alloc = round_page(bufRequest->Head.msgh_size +
- trailer_alloc);
+ new_request_alloc = (mach_msg_size_t)round_page(bufRequest->Head.msgh_size +
+ trailer_alloc);
request_size = new_request_alloc;
vm_deallocate(self,
- (vm_address_t) bufRequest,
- request_alloc);
+ (vm_address_t) bufRequest,
+ request_alloc);
continue;
}
break;
- } /* for(;;) */
+ } /* for(;;) */
- (void)vm_deallocate(self,
- (vm_address_t) bufRequest,
- request_alloc);
- (void)vm_deallocate(self,
- (vm_address_t) bufReply,
- reply_alloc);
- return mr;
+ (void)vm_deallocate(self,
+ (vm_address_t) bufRequest,
+ request_alloc);
+ (void)vm_deallocate(self,
+ (vm_address_t) bufReply,
+ reply_alloc);
+ return mr;
+}
+
+/*
+ * Routine: mach_msg_server_importance
+ * Purpose:
+ * A simple generic server function which handles importance
+ * promotion assertions for adaptive daemons.
+ */
+mach_msg_return_t
+mach_msg_server_importance(
+ boolean_t (*demux)(mach_msg_header_t *, mach_msg_header_t *),
+ mach_msg_size_t max_size,
+ mach_port_t rcv_name,
+ mach_msg_options_t options)
+{
+ return mach_msg_server(demux, max_size, rcv_name, options);
+}
+
+kern_return_t
+mach_voucher_deallocate(
+ mach_voucher_t voucher)
+{
+ return mach_port_deallocate(mach_task_self(), voucher);
}