/* file: ipctest.c */ /* author: MLehr */ /* * Copyright (C) 1994 * by the Rector and Board of Visitors of * the University of Virginia * * for more information: * Sanghyuk Son * Department of Computer Science * School of Engineering and Applied Science * University of Virginia * Charlottesville, VA 22903 */ /* The idea behind ipctest is to determine what the differences in performance between conventional Mach message passing and RT-Mach message passing are, if there are any. The program creates two client real-time threads which send messages back to the root thread for a certain number of iterations. When the time is up, the program displays how long it took. */ #include "MachUseful.h" /* The definitions in MachUseful.h make prototyping RT-Mach programs easier. MachUseful.h contains: * #includes of all necessary RT-Mach headers, so the programmer doesn't have to hunt * macros to initialize RT-Mach data structures so the programmer doesn't have to remember the precise format of the data structures * macros to call RT-Mach functions check return values automatically especially useful for functions which don't have man pages no additional overhead */ /* prototypes to keep gcc's -Wall happy */ int atoi (char *); void printf (char *, ...); void puts (char *); /********************************/ /* Depending on whether the program is to be compiled with conventional or real-time IPC, we use different definitions for message-passing routines, e.g., SEND_MSG() uses real-time IPC if USE_REAL_TIME is #defined, otherwise it uses conventional IPC Many of these macro definitions are defined in terms of other macros from MachUseful.h. */ #ifdef USE_REAL_TIME /* use RT-Mach's RT-IPC */ typedef rt_mach_msg_header_t my_msg_header_t; #define INIT_MSG(msg,header,descriptor,id,prio) \ INIT_RT_MESSAGE_HEADER (msg, \ header, \ descriptor, \ id, \ (prio).rt_deadline, \ (prio).rt_period, \ (prio).rt_priority) kern_return_t rt_mach_port_associate (thread_t thread, mach_port_t port, rt_priority_data_t *priority); kern_return_t rt_mach_port_allocate (task_t task, mach_port_right_t right, rt_mach_port_attr_t *port_attr, mach_port_t *name); void AssociateThreadWithPort (thread_t thread, mach_port_t port, rt_priority_t priority); void CreatePort (mach_msg_size_t messageSize, unsigned int numberBuffers, mach_port_t *port); #define ASSOCIATE_THREAD_WITH_PORT(thread,port,priority) \ AssociateThreadWithPort (thread, port, &(priority)); #define ALLOC_PORT(port,msgsize,nbufs,status) \ CreatePort (msgsize, nbufs, &port); #define SEND_RECV_MSG(port,header,ssiz,rsiz,status) \ SEND_RECEIVE_RT_MESSAGE (port, header, ssiz, rsiz, status) #define RECV_MSG(port,header,status) \ RECEIVE_RT_MESSAGE (port, header, status) #define SEND_MSG(port,header,status) \ SEND_RT_MESSAGE (port, header, status) #else /* USE_REAL_TIME */ /* use Mach's conventional IPC */ typedef mach_msg_header_t my_msg_header_t; #define INIT_MSG(msg,header,descriptor,id,prio) \ INIT_MESSAGE_HEADER (msg, header, descriptor, id) #define ASSOCIATE_THREAD_WITH_PORT(thread,port,priority) #define ALLOC_PORT(port,msgsize,nbufs,status) \ CREATE_PORT (port, status) #define SEND_RECV_MSG(port,header,ssiz,rsiz,status) \ SEND_RECEIVE_MESSAGE (port, header, ssiz, rsiz, status) #define RECV_MSG(port,header,status) \ RECEIVE_MESSAGE (port, header, status) #define SEND_MSG(port,header,status) \ SEND_MESSAGE (port, header, status) #endif /* USE_REAL_TIME */ /********************************/ #define ITERATIONS 0xffff typedef struct { my_msg_header_t header; /* note that this differs depending on whether USE_REAL_TIME is #defined */ mach_msg_type_t descriptor; } CountMsg; /* client data structures */ thread_t thread1; rt_thread_attr_data_t thread1Attr; mach_port_t thread1Port; thread_t thread2; rt_thread_attr_data_t thread2Attr; mach_port_t thread2Port; /* server data structures */ rt_priority_data_t priority; mach_port_t servicePort; unsigned int counter; unsigned int iterations; /********************************/ void AssociateThreadWithPort (thread_t thread, mach_port_t port, rt_priority_t priority) { kern_return_t status; /* RT-IPC needs to know which threads will be receiving from of this real-time port so that the Basic Priority Inheritance mechanism can work correctly */ RT_PORT_ASSOCIATE (thread, port, *priority, status); } /********************************/ void CreatePort (mach_msg_size_t messageSize, unsigned int numberBuffers, mach_port_t *port) { rt_mach_port_attr_t portAttributes; kern_return_t status; /* here we create a real-time port which will use the Basic Priority Inheritance Mechanism */ INIT_RT_PORT_ATTR (portAttributes, messageSize, numberBuffers, DISP_PRI, /* dispatch policy */ PRI_BPI, /* inheritance policy */ HANDOFF_MSG); /* handoff priority */ CREATE_RT_PORT (*port, portAttributes, status); } /********************************/ /* DoIt () is the entry point for the two client threads. After initializing, each client sends requests to the server until the task terminates. */ void DoIt (mach_port_t myPort) { CountMsg replymsg; CountMsg requestmsg; kern_return_t status; /* if this is RT-IPC, the kernel needs to know which thread will be receiving off of this port for Basic Priority Inheritance to work */ ASSOCIATE_THREAD_WITH_PORT (mach_thread_self (), myPort, priority); /* initialize the client's message buffers */ INIT_MSG (requestmsg, requestmsg.header, requestmsg.descriptor, 13, priority); INIT_MSG (replymsg, replymsg.header, replymsg.descriptor, 13, priority); requestmsg.header.msgh_local_port = myPort; replymsg.header.msgh_local_port = myPort; /* send requests to the server thread via the service port */ for (;;) { SEND_MSG (servicePort, requestmsg.header, status); RECV_MSG (myPort, replymsg.header, status); } /* note that the clients are terminated when the task is terminated */ } /********************************/ /* Main, after initializing, becomes the server thread. */ void main (int argc, char *argv []) { CountMsg replymsg; CountMsg requestmsg; kern_return_t status; mach_port_t realTimeClock; timespec_t endTime; timespec_t startTime; if (argc == 1) iterations = ITERATIONS; else if (argc == 2) { iterations = atoi (argv [1]); if (iterations <= 0) { puts ("iterations must be a postive integer"); exit (-1); } } else { puts ("usage: ipctest [iterations]"); exit (-1); } #ifdef USE_REAL_TIME puts ("using RT-IPC..."); #else puts ("using regular Mach IPC..."); #endif puts ("opening clock..."); OPEN_RT_CLOCK (realTimeClock, status); counter = 0; timespec_init_zero (startTime); INIT_RT_PRIORITY_ATTR (priority, startTime, startTime, 12); puts ("creating ports..."); /* create three IPC ports: one for the server to listen to, and two for the clients to listen to */ ALLOC_PORT (servicePort, sizeof (CountMsg), 3, status); ALLOC_PORT (thread1Port, sizeof (CountMsg), 3, status); ALLOC_PORT (thread2Port, sizeof (CountMsg), 3, status); /* if this is RT-IPC, the kernel needs to know which thread will be receiving off of the service port for Basic Priority Inheritance to work */ ASSOCIATE_THREAD_WITH_PORT (mach_thread_self (), servicePort, priority); /* initialize server's message buffers */ INIT_MESSAGE_HEADER (requestmsg, requestmsg.header, requestmsg.descriptor, 13); INIT_MESSAGE_HEADER (replymsg, replymsg.header, replymsg.descriptor, 13); /* start up the clients */ puts ("initializing threads..."); INIT_RT_THREAD_ATTR (thread1Attr, startTime, startTime, 12, FALSE, DoIt, /* entry point--see above */ (int *) thread1Port, 8092, status); INIT_RT_THREAD_ATTR (thread2Attr, startTime, startTime, 12, FALSE, DoIt, /* entry point--see above */ (int *) thread2Port, 8092, status); puts ("starting threads..."); CREATE_RT_THREAD (thread1, thread1Attr, status); CREATE_RT_THREAD (thread2, thread2Attr, status); /* start timing */ READ_TIME (realTimeClock, startTime, status); /* act as a server for a while */ for (;;) { if (counter++ >= iterations) break; /* service requests from the clients */ RECV_MSG (servicePort, requestmsg.header, status); replymsg.header.msgh_remote_port = requestmsg.header.msgh_remote_port; SEND_MSG (replymsg.header.msgh_remote_port, replymsg.header, status); } /* end timing */ READ_TIME (realTimeClock, endTime, status); /* display how we did */ printf ("iterations:\t%u\n", iterations); printf ("end time:\t"); timespec_print (stdout, endTime); puts (" -"); printf ("start time:\t"); timespec_print (stdout, startTime); timespec_sub (endTime, startTime); printf ("\n====================================\ntotal time:\t"); timespec_print (stdout, endTime); printf ("\n====================================\nmean time:\t"); timespec_div (endTime, iterations); timespec_print (stdout, endTime); putchar ('\n'); exit (0); }