1#!/bin/sh 2 3# 4# Copyright (c) 2015 EMC Corp. 5# All rights reserved. 6# 7# Redistribution and use in source and binary forms, with or without 8# modification, are permitted provided that the following conditions 9# are met: 10# 1. Redistributions of source code must retain the above copyright 11# notice, this list of conditions and the following disclaimer. 12# 2. Redistributions in binary form must reproduce the above copyright 13# notice, this list of conditions and the following disclaimer in the 14# documentation and/or other materials provided with the distribution. 15# 16# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26# SUCH DAMAGE. 27# 28 29# Non threaded Mach IPC test scenario 30# https://people.freebsd.org/~pho/stress/log/kip018.txt 31 32ps -p1 | grep -q launchd || exit 0 33 34odir=`pwd` 35cd /tmp 36sed '1,/^EOF/d' < $odir/$0 > machipc2.c 37# Test fails without the -lpthread. Need to investigate why. 38cc -o machipc2 -Wall -Wextra -O2 -g machipc2.c -lmach -lpthread || exit 1 39rm machipc2.c 40cd $odir 41 42(cd ../testcases/swap; ./swap -t 5m -i 20 -h -v) & 43sleep 5 44/tmp/machipc2 45pkill swap 46rm -f /tmp/machipc2 47exit 0 48EOF 49/* 50 Inspired by: Michael Weber: http://www.foldr.org/~michaelw/log/2009/03/13/ 51 */ 52 53#include <sys/types.h> 54#include <sys/wait.h> 55 56#include <mach/mach.h> 57#include <servers/bootstrap.h> 58 59#include <err.h> 60#include <stdlib.h> 61#include <stdio.h> 62#include <string.h> 63#include <unistd.h> 64 65#define MACH_MSG_TYPE_INTEGER_32 2 66#define N 200000000 67 68typedef struct { 69 unsigned int msgt_name : 8, 70 msgt_size : 8, 71 msgt_number : 12, 72 msgt_inline : 1, 73 msgt_longform : 1, 74 msgt_deallocate : 1, 75 msgt_unused : 1; 76} mach_msg_type_t; 77 78struct integer_message { 79 mach_msg_header_t head; 80 mach_msg_type_t type; 81 82 int inline_integer; 83}; 84 85struct message_recv 86{ 87 mach_msg_header_t head; 88 mach_msg_type_t type; 89 int inline_integer; 90 mach_msg_trailer_t trailer; 91}; 92 93static task_t child_task = MACH_PORT_NULL; 94 95mach_port_t bootstrap_port; 96 97#define CHECK_MACH_ERROR(err, s) \ 98 do { \ 99 if (err != KERN_SUCCESS) { \ 100 fprintf(stderr, "%s: %s", s, mach_error_string(err)); \ 101 exit(1); \ 102 } \ 103 } while (0) 104 105static int 106setup_recv_port (mach_port_t *recv_port) 107{ 108 kern_return_t kerr; 109 mach_port_t port = MACH_PORT_NULL; 110 kerr = mach_port_allocate (mach_task_self (), 111 MACH_PORT_RIGHT_RECEIVE, &port); 112 CHECK_MACH_ERROR (kerr, "mach_port_allocate failed:"); 113 114 kerr = mach_port_insert_right (mach_task_self (), 115 port, port, MACH_MSG_TYPE_MAKE_SEND); 116 CHECK_MACH_ERROR (kerr, "mach_port_insert_right failed:"); 117 118 *recv_port = port; 119 120 return (0); 121} 122 123static int 124send_port (mach_port_t remote_port, mach_port_t port) 125{ 126 kern_return_t kerr; 127 128 struct { 129 mach_msg_header_t header; 130 mach_msg_body_t body; 131 mach_msg_port_descriptor_t task_port; 132 } msg; 133 134 msg.header.msgh_remote_port = remote_port; 135 msg.header.msgh_local_port = MACH_PORT_NULL; 136 msg.header.msgh_bits = MACH_MSGH_BITS (MACH_MSG_TYPE_COPY_SEND, 0) | 137 MACH_MSGH_BITS_COMPLEX; 138 msg.header.msgh_size = sizeof msg; 139 140 msg.body.msgh_descriptor_count = 1; 141 msg.task_port.name = port; 142 msg.task_port.disposition = MACH_MSG_TYPE_COPY_SEND; 143 msg.task_port.type = MACH_MSG_PORT_DESCRIPTOR; 144 145 kerr = mach_msg_send (&msg.header); 146 CHECK_MACH_ERROR(kerr, "mach_msg_send failed:"); 147 148 return (0); 149} 150 151static int 152recv_port(mach_port_t recv_port, mach_port_t *port) 153{ 154 kern_return_t kerr; 155 struct { 156 mach_msg_header_t header; 157 mach_msg_body_t body; 158 mach_msg_port_descriptor_t task_port; 159 mach_msg_trailer_t trailer; 160 } msg; 161 162 kerr = mach_msg(&msg.header, MACH_RCV_MSG, 163 0, sizeof msg, recv_port, 164 MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL); 165 CHECK_MACH_ERROR(kerr, "mach_msg failed:"); 166 167 *port = msg.task_port.name; 168 return (0); 169} 170 171void 172writeint(mach_port_t port) 173{ 174 struct integer_message message; 175 int kerr, i; 176 177 /* Fill the header fields : */ 178 message.head.msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, MACH_MSG_TYPE_MAKE_SEND); 179 message.head.msgh_size = sizeof( struct integer_message ); 180 message.head.msgh_local_port = MACH_PORT_NULL; 181 message.head.msgh_remote_port = port; 182 message.head.msgh_id = 0; /* Message id */ 183 message.head.msgh_size = sizeof(message); /* Message size */ 184 185 /* Set the message type */ 186 message.type.msgt_name = MACH_MSG_TYPE_INTEGER_32; 187 message.type.msgt_size = sizeof(message); 188 message.type.msgt_number = 1; 189 message.type.msgt_inline = TRUE; 190 message.type.msgt_longform = FALSE; 191 message.type.msgt_deallocate = FALSE; 192 193 for (i = 0; i < N; i++) { 194 message.inline_integer = i; 195 196 /* Send the message */ 197 kerr = mach_msg(&message.head, /* The header */ 198 MACH_SEND_MSG, /* Flags */ 199 sizeof(message), /* Send size */ 200 0, /* Max receive Size */ 201 port, /* Send port */ 202 MACH_MSG_TIMEOUT_NONE, /* No timeout */ 203 MACH_PORT_NULL); /* No notification */ 204 if (kerr) 205 errx(1, "client mach_msg: %s", mach_error_string(kerr)); 206 } 207} 208 209void 210readint(mach_port_t port) 211{ 212 struct message_recv rmessage = {}; 213 int kerr, i; 214 215 rmessage.head.msgh_local_port = port; 216 rmessage.head.msgh_size = sizeof(rmessage); 217 218 for (i = 0; i < N; i++) { 219 /* Receive a message */ 220 kerr = mach_msg(&rmessage.head, /* The header */ 221 MACH_RCV_MSG, /* Flags */ 222 0, /* Send size */ 223 sizeof(rmessage), /* Max receive size */ 224 port, /* Receive port */ 225 MACH_MSG_TIMEOUT_NONE, /* No timeout */ 226 MACH_PORT_NULL); /* No notification */ 227 if (kerr) 228 errx(1, "client mach_msg MACH_RCV_MSG: %s", mach_error_string(kerr)); 229 if (rmessage.inline_integer != i) 230 errx(1, "FAIL message.inline_integer = %d, i = %d", 231 rmessage.inline_integer, i); 232 } 233} 234 235void 236sampling_fork(void) 237{ 238 pid_t pid; 239 kern_return_t kerr; 240 mach_port_t parent_recv_port = MACH_PORT_NULL; 241 mach_port_t child_recv_port = MACH_PORT_NULL; 242 243 if (setup_recv_port(&parent_recv_port) != 0) 244 return; 245 kerr = task_set_bootstrap_port(mach_task_self(), parent_recv_port); 246 CHECK_MACH_ERROR(kerr, "task_set_bootstrap_port failed:"); 247 248 if ((pid = fork()) == -1) 249 err(1, "fork"); 250 251 if (pid == 0) { 252 kerr = task_get_bootstrap_port(mach_task_self(), &parent_recv_port); 253 CHECK_MACH_ERROR(kerr, "task_get_bootstrap_port failed:"); 254 if (setup_recv_port(&child_recv_port) != 0) 255 return; 256 if (send_port(parent_recv_port, mach_task_self()) != 0) 257 return; 258 if (send_port(parent_recv_port, child_recv_port) != 0) 259 return; 260 if (recv_port(child_recv_port, &bootstrap_port) != 0) 261 return; 262 kerr = task_set_bootstrap_port(mach_task_self(), bootstrap_port); 263 CHECK_MACH_ERROR(kerr, "task_set_bootstrap_port failed:"); 264 265 readint(child_recv_port); 266 267 _exit(0); 268 } 269 270 /* parent */ 271 kerr = task_set_bootstrap_port(mach_task_self(), bootstrap_port); 272 CHECK_MACH_ERROR(kerr, "task_set_bootstrap_port failed:"); 273 if (recv_port(parent_recv_port, &child_task) != 0) 274 return; 275 if (recv_port(parent_recv_port, &child_recv_port) != 0) 276 return; 277 if (send_port(child_recv_port, bootstrap_port) != 0) 278 return; 279 kerr = mach_port_deallocate(mach_task_self(), parent_recv_port); 280 CHECK_MACH_ERROR(kerr, "mach_port_deallocate failed:"); 281 282 writeint(child_recv_port); 283} 284 285int 286main(void) 287{ 288 sampling_fork(); 289 wait(NULL); 290 291 return (0); 292} 293