#ifdef __sun
#pragma ident "@(#)lb_mmtest.c 1.0 08/21/06 Apple Inc."
#endif
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <mach/boolean.h>
#include <mach/mach_error.h>
#include <mach/mach.h>
#include <mach/notify.h>
#include <servers/bootstrap.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/signal.h>
#include <sys/time.h>
#include <sys/types.h>
#include "../libmicro.h"
typedef struct {
int server_mode;
boolean_t verbose;
boolean_t oneway;
int overwrite;
int msg_type;
int num_ints;
int num_msgs;
const char *server_port_name;
mach_port_t server_port;
mach_port_t reply_port;
int request_msg_size;
void *request_msg;
int reply_msg_size;
void *reply_msg;
void *ints;
long pid;
} tsd_t;
static boolean_t opt_verbose;
static boolean_t opt_oneway;
static int opt_num_msgs;
static int opt_msg_type;
static int opt_num_ints;
static char * opt_server_port_name;
#pragma mark *** definitions from MMTest.c
typedef struct {
mach_msg_header_t header;
mach_msg_trailer_t trailer; } ipc_trivial_message;
typedef struct {
mach_msg_header_t header;
u_int32_t numbers[0];
mach_msg_trailer_t trailer; } ipc_inline_message;
typedef struct {
mach_msg_header_t header;
mach_msg_body_t body;
mach_msg_ool_descriptor_t descriptor;
mach_msg_trailer_t trailer; } ipc_complex_message;
void signal_handler(int sig) {
}
enum {
msg_type_trivial = 0,
msg_type_inline = 1,
msg_type_complex = 2
};
void server(void *tsd);
void client(void *tsd);
#pragma mark *** routines from MMTest.c
void server(void *tsd) {
mach_msg_header_t *request;
mach_msg_header_t *reply;
mach_msg_option_t option;
kern_return_t ret;
tsd_t *ts = (tsd_t *)tsd;
request = (mach_msg_header_t *)ts->request_msg;
reply = (mach_msg_header_t *)ts->reply_msg;
#ifndef OPTIMIZED_SERVER
for (;;) {
#endif
if (ts->verbose) printf("Awaiting message\n");
option = MACH_RCV_MSG|MACH_RCV_INTERRUPT|MACH_RCV_LARGE;
ret = mach_msg(request,
option,
0,
ts->request_msg_size,
ts->server_port,
MACH_MSG_TIMEOUT_NONE,
MACH_PORT_NULL);
#ifdef OPTIMIZED_SERVER
for (;;) {
mach_msg_header_t *tmp;
#endif
if (MACH_MSG_SUCCESS != ret)
break;
if (ts->verbose) printf("Received message\n");
if (request->msgh_bits & MACH_MSGH_BITS_COMPLEX) {
ipc_complex_message *complex_request;
complex_request = (ipc_complex_message *)ts->request_msg;
ret = vm_deallocate(mach_task_self(),
(vm_address_t)complex_request->descriptor.address,
complex_request->descriptor.size);
}
if (1 == request->msgh_id) {
if (ts->verbose) printf("Sending reply\n");
reply->msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_MOVE_SEND_ONCE, 0);
reply->msgh_size = ts->reply_msg_size;
reply->msgh_remote_port = request->msgh_remote_port;
reply->msgh_local_port = MACH_PORT_NULL;
reply->msgh_id = 2;
#ifdef OPTIMIZED_SERVER
option = MACH_SEND_MSG|MACH_RCV_MSG|MACH_RCV_INTERRUPT|MACH_RCV_LARGE;
} else {
option = MACH_RCV_MSG|MACH_RCV_INTERRUPT|MACH_RCV_LARGE;
}
ret = mach_msg( reply,
option,
ts->reply_msg_size,
ts->request_msg_size,
ts->server_port,
MACH_MSG_TIMEOUT_NONE,
MACH_PORT_NULL);
tmp = reply;
reply = request;
request = tmp;
#else
ret = mach_msg(reply,
MACH_SEND_MSG,
ts->reply_msg_size,
0,
MACH_PORT_NULL,
MACH_MSG_TIMEOUT_NONE,
MACH_PORT_NULL);
if (ret != MACH_MSG_SUCCESS)
break;
}
#endif
}
if (MACH_RCV_INTERRUPTED != ret) {
mach_error("mach_msg: ", ret);
exit(1);
}
}
void client(void *tsd) {
mach_msg_header_t *request;
mach_msg_header_t *reply;
mach_msg_option_t option;
kern_return_t ret;
int idx;
tsd_t *ts = (tsd_t *)tsd;
#ifdef SWAP_BUFFERS
mach_msg_header_t *tmp;
#endif
request = (mach_msg_header_t *)ts->request_msg;
reply = (mach_msg_header_t *)ts->reply_msg;
for (idx = 0; idx < ts->num_msgs; idx++) {
request->msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND,
MACH_MSG_TYPE_MAKE_SEND_ONCE);
request->msgh_size = ts->request_msg_size;
request->msgh_remote_port = ts->server_port;
request->msgh_local_port = ts->reply_port;
if (ts->msg_type == msg_type_complex) {
ipc_complex_message *complexmsg = (ipc_complex_message *)request;
request->msgh_bits |= MACH_MSGH_BITS_COMPLEX;
complexmsg->body.msgh_descriptor_count = 1;
complexmsg->descriptor.address = ts->ints;
complexmsg->descriptor.size = ts->num_ints * sizeof(u_int32_t);
complexmsg->descriptor.deallocate = FALSE;
complexmsg->descriptor.copy = MACH_MSG_VIRTUAL_COPY;
complexmsg->descriptor.type = MACH_MSG_OOL_DESCRIPTOR;
}
if (ts->oneway) {
request->msgh_id = 0;
option = MACH_SEND_MSG;
} else {
request->msgh_id = 1;
option = MACH_SEND_MSG|MACH_RCV_MSG;
}
if (ts->verbose) printf("Sending request\n");
#ifdef SWAP_BUFFERS
ret = mach_msg( request,
option,
ts->request_msg_size,
ts->reply_msg_size,
ts->reply_port,
MACH_MSG_TIMEOUT_NONE,
MACH_PORT_NULL);
if (MACH_MSG_SUCCESS != ret) {
mach_error("client: mach_msg: ", ret);
fprintf(stderr, "bailing after %u iterations\n", idx);
exit(1);
}
tmp = request;
request = reply;
reply = tmp;
#else
ret = mach_msg_overwrite(request,
option,
ts->request_msg_size,
ts->reply_msg_size,
ts->reply_port,
MACH_MSG_TIMEOUT_NONE,
MACH_PORT_NULL,
reply,
0);
if (MACH_MSG_SUCCESS != ret) {
mach_error("client: mach_msg_overwrite: ", ret);
fprintf(stderr, "bailing after %u iterations\n", idx);
exit(1);
}
#endif
if (ts->verbose && !ts->oneway) printf("Received reply\n");
}
}
#pragma mark *** Darbench routines
int
benchmark_initbatch(void *tsd)
{
long pid;
tsd_t *ts = (tsd_t *)tsd;
ts->server_mode = -1;
ts->verbose = opt_verbose;
ts->oneway = opt_oneway;
ts->overwrite = 0;
ts->msg_type = opt_msg_type;
ts->num_ints = opt_num_ints;
ts->num_msgs = opt_num_msgs;
ts->server_port_name = opt_server_port_name;
ts->server_port = MACH_PORT_NULL;
ts->reply_port = MACH_PORT_NULL;
ts->request_msg = NULL;
ts->request_msg_size = 0;
ts->reply_msg = NULL;
ts->reply_msg_size = 0;
switch (ts->msg_type) {
case msg_type_trivial:
ts->request_msg_size = sizeof(ipc_trivial_message);
break;
case msg_type_inline:
ts->request_msg_size = sizeof(ipc_inline_message) +
sizeof(u_int32_t) * ts->num_ints;
break;
case msg_type_complex:
ts->request_msg_size = sizeof(ipc_complex_message);
ts->ints = malloc(sizeof(u_int32_t) * ts->num_ints);
break;
}
ts->request_msg = malloc(ts->request_msg_size);
ts->reply_msg = malloc(ts->reply_msg_size);
if (ts->server_mode) {
kern_return_t ret = 0;
mach_port_t bsport;
ts->reply_msg_size -= sizeof(mach_msg_trailer_t);
ret = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE,
&(ts->server_port));
if (KERN_SUCCESS != ret) {
mach_error("mach_port_allocate(): ", ret);
exit(1);
}
ret = mach_port_insert_right(mach_task_self(), ts->server_port,
ts->server_port, MACH_MSG_TYPE_MAKE_SEND);
if (KERN_SUCCESS != ret) {
mach_error("mach_port_insert_right(): ", ret);
exit(1);
}
ret = task_get_bootstrap_port(mach_task_self(), &bsport);
if (KERN_SUCCESS != ret) {
mach_error("task_get_bootstrap_port(): ", ret);
exit(1);
}
ret = bootstrap_check_in(bsport, (char *)ts->server_port_name,
&ts->server_port);
if (KERN_SUCCESS != ret) {
mach_error("bootstrap_register(): ", ret);
exit(1);
}
} else {
kern_return_t ret = 0;
mach_port_t bsport;
ts->request_msg_size -= sizeof(mach_msg_trailer_t);
ret = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE,
&(ts->reply_port));
if (KERN_SUCCESS != ret) {
mach_error("mach_port_allocate(): ", ret);
exit(1);
}
ret = task_get_bootstrap_port(mach_task_self(), &bsport);
if (KERN_SUCCESS != ret) {
mach_error("task_get_bootstrap_port(): ", ret);
exit(1);
}
ret = bootstrap_look_up(bsport, (char *)ts->server_port_name,
&(ts->server_port));
if (KERN_SUCCESS != ret) {
mach_error("bootstrap_look_up(): ", ret);
exit(1);
}
}
if (ts->verbose) {
if (ts->server_mode) {
printf("Server waiting for IPC messages from client on port '%s'.\n",
ts->server_port_name);
} else {
printf("Client sending %d %s IPC messages to port '%s' in %s mode.\n",
ts->num_msgs, (ts->msg_type == msg_type_inline) ? "inline" :
((ts->msg_type == msg_type_complex) ? "complex" : "trivial"),
ts->server_port_name, (ts->oneway ? "oneway" : "rpc"));
}
}
pid = fork();
switch (pid) {
case 0:
server(tsd);
exit(0);
break;
case -1:
return (-1);
default:
ts->pid = pid;
break;
}
return (0);
}
int
benchmark_finirun()
{
(void) fprintf(stderr, "benchmark_finirun\n");
return (0);
}
int
benchmark_init()
{
(void) sprintf(lm_optstr, "voc:t:n:p:");
lm_tsdsize = sizeof (tsd_t);
(void) sprintf(lm_usage,
" -v\t\tbe verbose\n"
" -o\t\tdo not request return reply (client)\n"
" -c num\t\tnumber of messages to send (client)\n"
" -t trivial|inline|complex\ttype of messages to send (client)\n"
" -n num\tnumber of 32-bit ints to send in messages\n"
"\t\t\t(client's value must be <= the server's)\n"
" -p portname\tname of port on which to communicate\n"
"\t\t\t(client and server must use the same value)\n");
opt_verbose = FALSE;
opt_oneway = FALSE;
opt_num_msgs = 10000;
opt_msg_type = msg_type_trivial;
opt_num_ints = 64;
opt_server_port_name = malloc(32);
strcpy(opt_server_port_name, "TEST");
return (0);
}
int
benchmark_fini()
{
free(opt_server_port_name);
return (0);
}
int
benchmark_finibatch(void *tsd)
{
tsd_t *ts = (tsd_t *)tsd;
kill(ts->pid, SIGKILL);
return (0);
}
char *
benchmark_result()
{
static char result = '\0';
(void) fprintf(stderr, "benchmark_result\n");
return (&result);
}
int
benchmark_finiworker(void *tsd)
{
return (0);
}
int
benchmark_optswitch(int opt, char *optarg)
{
(void) fprintf(stderr, "benchmark_optswitch\n");
switch (opt) {
case 'v':
opt_verbose = TRUE;
break;
case 'o':
opt_oneway = TRUE;
break;
case 'c':
opt_num_msgs = sizetoint(optarg);
break;
case 't':
if ( 0 == strcmp("trivial", optarg) )
opt_msg_type = msg_type_trivial;
else if ( 0 == strcmp("inline", optarg) )
opt_msg_type = msg_type_inline;
else if ( 0 == strcmp("complex", optarg) )
opt_msg_type = msg_type_complex;
else {
(void) fprintf(stderr, "incorrect argument for message type %s\n", optarg);
return (-1);
}
break;
case 'n':
opt_num_ints = sizetoint(optarg);
break;
case 'p':
strncpy(opt_server_port_name, optarg, 32);
break;
default:
return (-1);
}
return (0);
}
int
benchmark_initworker(void *tsd)
{
return (0);
}
int
benchmark_initrun()
{
(void) fprintf(stderr, "benchmark_initrun\n");
return (0);
}
int
benchmark(void *tsd, result_t *res)
{
int i;
for (i = 0; i < lm_optB; i++) {
client(tsd);
}
return (0);
}