void * server(void *serverarg) { int idx; kern_return_t ret; int totalmsg = num_msgs * num_clients; mach_port_t recv_port; uint64_t starttm, endtm; int svr_num = (int)(uintptr_t)serverarg; struct port_args *args = &server_port_args[svr_num]; args->server_num = svr_num; setup_server_ports(args); thread_setup(args->server_num + 1); recv_port = (useset) ? args->rcv_set : args->port; for (idx = 0; idx < totalmsg; idx++) { if (verbose > 2) printf("server awaiting message %d\n", idx); ret = mach_msg(args->req_msg, MACH_RCV_MSG|MACH_RCV_INTERRUPT|MACH_RCV_LARGE, 0, args->req_size, recv_port, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL); if (MACH_RCV_INTERRUPTED == ret) break; if (MACH_MSG_SUCCESS != ret) { if (verbose) printf("mach_msg() ret=%d", ret); mach_error("mach_msg (receive): ", ret); exit(1); } if (verbose > 2) printf("server received message %d\n", idx); if (args->req_msg->msgh_bits & MACH_MSGH_BITS_COMPLEX) { ret = vm_deallocate(mach_task_self(), (vm_address_t)((ipc_complex_message *)args->req_msg)->descriptor.address, ((ipc_complex_message *)args->req_msg)->descriptor.size); } if (1 == args->req_msg->msgh_id) { if (verbose > 2) printf("server sending reply %d\n", idx); args->reply_msg->msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_MOVE_SEND_ONCE, 0); args->reply_msg->msgh_size = args->reply_size; args->reply_msg->msgh_remote_port = args->req_msg->msgh_remote_port; args->reply_msg->msgh_local_port = MACH_PORT_NULL; args->reply_msg->msgh_id = 2; ret = mach_msg(args->reply_msg, MACH_SEND_MSG, args->reply_size, 0, MACH_PORT_NULL, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL); if (MACH_MSG_SUCCESS != ret) { mach_error("mach_msg (send): ", ret); exit(1); } } } if (!useset) return NULL; if (verbose < 1) return NULL; uint64_t deltans = 0; /* * If we're using multiple sets, explicitly tear them all down * and measure the time. */ for (int ns = 0; ns < setcount; ns++) { if (verbose > 1) printf("\tTearing down set[%d] %#x...\n", ns, args->set[ns]); starttm = mach_absolute_time(); ret = mach_port_mod_refs(mach_task_self(), args->set[ns], MACH_PORT_RIGHT_PORT_SET, -1); endtm = mach_absolute_time(); deltans += abs_to_ns(endtm - starttm); if (ret != KERN_SUCCESS) { mach_error("mach_port_mod_refs(): ", ret); exit(1); } } uint64_t nlinks = (uint64_t)setcount * (uint64_t)portcount; printf("\tteardown of %llu links took %llu ns\n", nlinks, deltans); printf("\t%lluns per set\n", deltans / (uint64_t)setcount); return NULL; }
void * server(void *serverarg) { int kq; struct kevent64_s kev[1]; int err; struct port_args args; int idx; kern_return_t ret; int totalmsg = num_msgs * num_clients; args.server_num = (int) (long) serverarg; setup_server_ports(&args); thread_setup(args.server_num + 1); kq = kqueue(); if (kq == -1) { perror("kqueue"); exit(1); } EV_SET64(&kev[0], args.pset, EVFILT_MACHPORT, (EV_ADD | EV_CLEAR | EV_DISPATCH), #if DIRECT_MSG_RCV MACH_RCV_MSG|MACH_RCV_LARGE, 0, 0, (mach_vm_address_t)args.req_msg, args.req_size); #else 0, 0, 0, 0, 0); #endif err = kevent64(kq, kev, 1, NULL, 0, 0, NULL); if (err == -1) { perror("kevent"); exit(1); } for (idx = 0; idx < totalmsg; idx++) { if (verbose) printf("server awaiting message %d\n", idx); retry: EV_SET64(&kev[0], args.pset, EVFILT_MACHPORT, EV_ENABLE, #if DIRECT_MSG_RCV MACH_RCV_MSG|MACH_RCV_LARGE, 0, 0, (mach_vm_address_t)args.req_msg, args.req_size); #else 0, 0, 0, 0, 0); #endif err = kevent64(kq, kev, 1, kev, 1, 0, NULL); if (err == -1) { perror("kevent64"); exit(1); } if (err == 0) { // printf("kevent64: returned zero\n"); goto retry; } #if DIRECT_MSG_RCV ret = kev[0].fflags; if (MACH_MSG_SUCCESS != ret) { if (verbose) printf("kevent64() mach_msg_return=%d", ret); mach_error("kevent64 (msg receive): ", ret); exit(1); } #else if (kev[0].data != args.port) printf("kevent64(MACH_PORT_NULL) port name (0x%x) != expected (0x%x)\n", kev[0].data, args.port); args.req_msg->msgh_bits = 0; args.req_msg->msgh_size = args.req_size; args.req_msg->msgh_local_port = args.port; ret = mach_msg(args.req_msg, MACH_RCV_MSG|MACH_RCV_INTERRUPT|MACH_RCV_LARGE, 0, args.req_size, args.pset, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL); if (MACH_RCV_INTERRUPTED == ret) break; if (MACH_MSG_SUCCESS != ret) { if (verbose) printf("mach_msg() ret=%d", ret); mach_error("mach_msg (receive): ", ret); exit(1); } #endif if (verbose) printf("server received message %d\n", idx); if (args.req_msg->msgh_bits & MACH_MSGH_BITS_COMPLEX) { ret = vm_deallocate(mach_task_self(), (vm_address_t)((ipc_complex_message *)args.req_msg)->descriptor.address, ((ipc_complex_message *)args.req_msg)->descriptor.size); } if (1 == args.req_msg->msgh_id) { if (verbose) printf("server sending reply %d\n", idx); args.reply_msg->msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, MACH_MSG_TYPE_MAKE_SEND); args.reply_msg->msgh_size = args.reply_size; args.reply_msg->msgh_remote_port = args.req_msg->msgh_remote_port; args.reply_msg->msgh_local_port = args.req_msg->msgh_local_port; args.reply_msg->msgh_id = 2; ret = mach_msg(args.reply_msg, MACH_SEND_MSG, args.reply_size, 0, MACH_PORT_NULL, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL); if (MACH_MSG_SUCCESS != ret) { mach_error("mach_msg (send): ", ret); exit(1); } } } }