7 #include <mach/mach_error.h>
8 #include <mach/notify.h>
9 #include <servers/bootstrap.h>
10 #include <sys/types.h>
12 #include <sys/signal.h>
14 #define MAX(A, B) ((A) < (B) ? (B) : (A))
16 static __inline__
unsigned long long ReadTSR() {
18 unsigned long long time64
;
19 unsigned long word
[2];
22 /* Read from Pentium and Pentium Pro 64-bit timestamp counter.
23 * The counter is set to 0 at processor reset and increments on
24 * every clock cycle. */
25 __asm__
volatile("rdtsc" : : : "eax", "edx");
26 __asm__
volatile("movl %%eax,%0" : "=m" (now
.word
[0]) : : "eax");
27 __asm__
volatile("movl %%edx,%0" : "=m" (now
.word
[1]) : : "edx");
28 #elif defined(__ppc__)
29 /* Read from PowerPC 64-bit time base register. The increment
30 * rate of the time base is implementation-dependent, but is
31 * 1/4th the bus clock cycle on 603/604 processors. */
34 __asm__
volatile("mftbu %0" : "=r" (now
.word
[0]));
35 __asm__
volatile("mftb %0" : "=r" (now
.word
[1]));
36 __asm__
volatile("mftbu %0" : "=r" (t3
));
37 } while (now
.word
[0] != t3
);
39 #warning Do not know how to read a time stamp register on this architecture
46 unsigned int msgt_name
: 8,
56 mach_msg_type_t msgtl_header
;
57 unsigned short msgtl_name
;
58 unsigned short msgtl_size
;
59 natural_t msgtl_number
;
60 } mach_msg_type_long_t
;
61 #define MACH_MSG_TYPE_INTEGER_32 0
65 mach_msg_header_t header
;
66 mach_msg_trailer_t trailer
; // subtract this when sending
67 } ipc_trivial_message
;
70 mach_msg_header_t header
;
73 mach_msg_trailer_t trailer
; // subtract this when sending
77 mach_msg_header_t header
;
79 mach_msg_ool_descriptor_t descriptor
;
80 mach_msg_trailer_t trailer
; // subtract this when sending
81 } ipc_complex_message
;
91 mach_msg_header_t
*req_msg
;
93 mach_msg_header_t
*reply_msg
;
105 char *server_port_name
;
107 void signal_handler(int sig
) {
110 void usage(const char *progname
) {
111 fprintf(stderr
, "usage: %s [options]\n", progname
);
112 fprintf(stderr
, "where options are:\n");
113 fprintf(stderr
, " -verbose\t\tbe verbose\n");
114 fprintf(stderr
, " -oneway\t\tdo not request return reply\n");
115 fprintf(stderr
, " -count num\t\tnumber of messages to send\n");
116 fprintf(stderr
, " -type trivial|inline|complex\ttype of messages to send\n");
117 fprintf(stderr
, " -numints num\tnumber of 32-bit ints to send in messages\n");
118 fprintf(stderr
, " -clients num\tnumber of client threads to run\n");
119 fprintf(stderr
, " -delay num\t\tmicroseconds to sleep clients between messages\n");
120 fprintf(stderr
, " -name portname\tname of port on which to communicate\n");
121 fprintf(stderr
, "default values are:\n");
122 fprintf(stderr
, " . not verbose\n");
123 fprintf(stderr
, " . not oneway\n");
124 fprintf(stderr
, " . client sends 10000 messages\n");
125 fprintf(stderr
, " . inline message type\n");
126 fprintf(stderr
, " . 64 32-bit integers in inline/complex messages\n");
127 fprintf(stderr
, " . avail_cpus - 1 clients\n");
128 fprintf(stderr
, " . no delay\n");
129 fprintf(stderr
, " . port name 'TEST'\n");
133 void parse_args(int argc
, char *argv
[]) {
134 host_basic_info_data_t info
;
135 mach_msg_type_number_t count
;
136 kern_return_t result
;
138 /* Initialize defaults */
141 msg_type
= msg_type_trivial
;
145 server_port_name
= "TEST";
147 count
= HOST_BASIC_INFO_COUNT
;
148 result
= host_info(mach_host_self(), HOST_BASIC_INFO
,
149 (host_info_t
)&info
, &count
);
150 if (result
== KERN_SUCCESS
)
151 num_clients
= MAX(1, info
.avail_cpus
- 1);
155 const char *progname
= argv
[0];
158 if (0 == strcmp("-verbose", argv
[0])) {
161 } else if (0 == strcmp("-oneway", argv
[0])) {
164 } else if (0 == strcmp("-type", argv
[0])) {
167 if (0 == strcmp("trivial", argv
[1])) {
168 msg_type
= msg_type_trivial
;
169 } else if (0 == strcmp("inline", argv
[1])) {
170 msg_type
= msg_type_inline
;
171 } else if (0 == strcmp("complex", argv
[1])) {
172 msg_type
= msg_type_complex
;
175 argc
-= 2; argv
+= 2;
176 } else if (0 == strcmp("-name", argv
[0])) {
179 server_port_name
= argv
[1];
180 argc
-= 2; argv
+= 2;
181 } else if (0 == strcmp("-numints", argv
[0])) {
184 num_ints
= strtoul(argv
[1], NULL
, 0);
185 argc
-= 2; argv
+= 2;
186 } else if (0 == strcmp("-count", argv
[0])) {
189 num_msgs
= strtoul(argv
[1], NULL
, 0);
190 argc
-= 2; argv
+= 2;
191 } else if (0 == strcmp("-clients", argv
[0])) {
194 num_clients
= strtoul(argv
[1], NULL
, 0);
195 argc
-= 2; argv
+= 2;
196 } else if (0 == strcmp("-delay", argv
[0])) {
199 client_delay
= strtoul(argv
[1], NULL
, 0);
200 argc
-= 2; argv
+= 2;
206 void setup_server_ports(struct port_args
*ports
)
208 kern_return_t ret
= 0;
211 ports
->req_size
= MAX(sizeof(ipc_inline_message
) +
212 sizeof(u_int32_t
) * num_ints
,
213 sizeof(ipc_complex_message
));
214 ports
->reply_size
= sizeof(ipc_trivial_message
) -
215 sizeof(mach_msg_trailer_t
);
216 ports
->req_msg
= malloc(ports
->req_size
);
217 ports
->reply_msg
= malloc(ports
->reply_size
);
219 ret
= mach_port_allocate(mach_task_self(),
220 MACH_PORT_RIGHT_RECEIVE
,
222 if (KERN_SUCCESS
!= ret
) {
223 mach_error("mach_port_allocate(): ", ret
);
227 ret
= mach_port_insert_right(mach_task_self(),
230 MACH_MSG_TYPE_MAKE_SEND
);
231 if (KERN_SUCCESS
!= ret
) {
232 mach_error("mach_port_insert_right(): ", ret
);
236 ret
= task_get_bootstrap_port(mach_task_self(), &bsport
);
237 if (KERN_SUCCESS
!= ret
) {
238 mach_error("task_get_bootstrap_port(): ", ret
);
242 ret
= bootstrap_register(bsport
, server_port_name
, ports
->port
);
243 if (KERN_SUCCESS
!= ret
) {
244 mach_error("bootstrap_register(): ", ret
);
248 printf("server waiting for IPC messages from client on port '%s'.\n",
253 void setup_client_ports(struct port_args
*ports
)
255 kern_return_t ret
= 0;
257 case msg_type_trivial
:
258 ports
->req_size
= sizeof(ipc_trivial_message
);
260 case msg_type_inline
:
261 ports
->req_size
= sizeof(ipc_inline_message
) +
262 sizeof(u_int32_t
) * num_ints
;
264 case msg_type_complex
:
265 ports
->req_size
= sizeof(ipc_complex_message
);
268 ports
->req_size
-= sizeof(mach_msg_trailer_t
);
269 ports
->reply_size
= sizeof(ipc_trivial_message
);
270 ports
->req_msg
= malloc(ports
->req_size
);
271 ports
->reply_msg
= malloc(ports
->reply_size
);
273 ret
= mach_port_allocate(mach_task_self(),
274 MACH_PORT_RIGHT_RECEIVE
,
276 if (KERN_SUCCESS
!= ret
) {
277 mach_error("mach_port_allocate(): ", ret
);
281 printf("Client sending %d %s IPC messages to port '%s' in %s mode.\n",
282 num_msgs
, (msg_type
== msg_type_inline
) ?
283 "inline" : ((msg_type
== msg_type_complex
) ?
284 "complex" : "trivial"),
285 server_port_name
, (oneway
? "oneway" : "rpc"));
290 void server(struct port_args
*args
)
294 int totalmsg
= num_msgs
* num_clients
;
296 unsigned long long starttsc
, endtsc
, deltatsc
;
297 struct timeval starttv
, endtv
, deltatv
;
299 /* Call gettimeofday() once and throw away result; some implementations
300 * (like Mach's) cache some time zone info on first call. Then, call
301 * ReadTSR in case that helps warm things up, again discarding the
304 gettimeofday(&starttv
, NULL
);
307 gettimeofday(&starttv
, NULL
);
308 starttsc
= ReadTSR();
310 for (idx
= 0; idx
< totalmsg
; idx
++) {
312 printf("server awaiting message %d\n", idx
);
313 args
->req_msg
->msgh_bits
= 0;
314 args
->req_msg
->msgh_size
= args
->req_size
;
315 args
->req_msg
->msgh_local_port
= args
->port
;
316 ret
= mach_msg(args
->req_msg
,
317 MACH_RCV_MSG
|MACH_RCV_INTERRUPT
|MACH_RCV_LARGE
,
321 MACH_MSG_TIMEOUT_NONE
,
323 if (MACH_MSG_SUCCESS
!= ret
) {
324 mach_error("mach_msg (receive): ", ret
);
328 printf("server received message %d\n", idx
);
329 if (args
->req_msg
->msgh_bits
& MACH_MSGH_BITS_COMPLEX
) {
330 ret
= vm_deallocate(mach_task_self(),
331 (vm_address_t
)((ipc_complex_message
*)args
->req_msg
)->descriptor
.address
,
332 ((ipc_complex_message
*)args
->req_msg
)->descriptor
.size
);
335 if (1 == args
->req_msg
->msgh_id
) {
337 printf("server sending reply %d\n", idx
);
338 args
->reply_msg
->msgh_bits
= MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND
,
339 MACH_MSG_TYPE_MAKE_SEND
);
340 args
->reply_msg
->msgh_size
= args
->reply_size
;
341 args
->reply_msg
->msgh_remote_port
= args
->req_msg
->msgh_remote_port
;
342 args
->reply_msg
->msgh_local_port
= args
->req_msg
->msgh_local_port
;
343 args
->reply_msg
->msgh_id
= 2;
344 ret
= mach_msg(args
->reply_msg
,
349 MACH_MSG_TIMEOUT_NONE
,
351 if (MACH_MSG_SUCCESS
!= ret
) {
352 mach_error("mach_msg (send): ", ret
);
359 gettimeofday(&endtv
, NULL
);
362 deltatsc
= endtsc
- starttsc
;
363 deltatv
.tv_sec
= endtv
.tv_sec
- starttv
.tv_sec
;
364 deltatv
.tv_usec
= endtv
.tv_usec
- starttv
.tv_usec
;
365 if (endtv
.tv_usec
< starttv
.tv_usec
) {
367 deltatv
.tv_usec
+= 1000000;
370 double dsecs
= (double) deltatv
.tv_sec
+
371 1.0E-6 * (double) deltatv
.tv_usec
;
373 printf("\n%u messages during %qd time stamp ticks\n",
375 printf("%g time stamp ticks per message\n",
376 (double) deltatsc
/ (double) totalmsg
);
377 printf("\n%u messages during %u.%06u seconds\n",
378 totalmsg
, deltatv
.tv_sec
, deltatv
.tv_usec
);
379 printf("%g messages per second\n", (double)totalmsg
/ dsecs
);
380 printf("%g microseconds per message\n\n",
381 dsecs
* 1.0E6
/ (double) totalmsg
);
384 void *client(void *threadarg
)
386 struct port_args args
;
388 mach_msg_header_t
*req
, *reply
;
389 mach_port_t bsport
, servport
;
391 void *ints
= malloc(sizeof(u_int32_t
) * num_ints
);
393 /* find server port */
394 ret
= task_get_bootstrap_port(mach_task_self(), &bsport
);
395 if (KERN_SUCCESS
!= ret
) {
396 mach_error("task_get_bootstrap_port(): ", ret
);
399 ret
= bootstrap_look_up(bsport
, server_port_name
, &servport
);
400 if (KERN_SUCCESS
!= ret
) {
401 mach_error("bootstrap_look_up(): ", ret
);
405 setup_client_ports(&args
);
407 /* start message loop */
408 for (idx
= 0; idx
< num_msgs
; idx
++) {
410 reply
= args
.reply_msg
;
412 req
->msgh_bits
= MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND
,
413 MACH_MSG_TYPE_MAKE_SEND
);
414 req
->msgh_size
= args
.req_size
;
415 req
->msgh_remote_port
= servport
;
416 req
->msgh_local_port
= args
.port
;
417 req
->msgh_id
= oneway
? 0 : 1;
419 case msg_type_trivial
:
421 case msg_type_inline
:
422 ((ipc_inline_message
*)req
)->type
.msgt_name
= MACH_MSG_TYPE_INTEGER_32
;
423 ((ipc_inline_message
*)req
)->type
.msgt_size
= 32;
424 ((ipc_inline_message
*)req
)->type
.msgt_number
= num_ints
;
425 ((ipc_inline_message
*)req
)->type
.msgt_inline
= TRUE
;
426 ((ipc_inline_message
*)req
)->type
.msgt_longform
= FALSE
;
427 ((ipc_inline_message
*)req
)->type
.msgt_deallocate
= FALSE
;
428 ((ipc_inline_message
*)req
)->type
.msgt_unused
= 0;
430 case msg_type_complex
:
431 (req
)->msgh_bits
|= MACH_MSGH_BITS_COMPLEX
;
432 ((ipc_complex_message
*)req
)->body
.msgh_descriptor_count
= 1;
433 ((ipc_complex_message
*)req
)->descriptor
.address
= ints
;
434 ((ipc_complex_message
*)req
)->descriptor
.size
=
435 num_ints
* sizeof(u_int32_t
);
436 ((ipc_complex_message
*)req
)->descriptor
.deallocate
= FALSE
;
437 ((ipc_complex_message
*)req
)->descriptor
.copy
= MACH_MSG_VIRTUAL_COPY
;
438 ((ipc_complex_message
*)req
)->descriptor
.type
= MACH_MSG_OOL_DESCRIPTOR
;
442 printf("client sending message %d\n", idx
);
448 MACH_MSG_TIMEOUT_NONE
,
450 if (MACH_MSG_SUCCESS
!= ret
) {
451 mach_error("mach_msg (send): ", ret
);
452 fprintf(stderr
, "bailing after %u iterations\n", idx
);
458 printf("client awaiting reply %d\n", idx
);
459 reply
->msgh_bits
= 0;
460 reply
->msgh_size
= args
.reply_size
;
461 reply
->msgh_local_port
= args
.port
;
462 ret
= mach_msg(args
.reply_msg
,
463 MACH_RCV_MSG
|MACH_RCV_INTERRUPT
,
467 MACH_MSG_TIMEOUT_NONE
,
469 if (MACH_MSG_SUCCESS
!= ret
) {
470 mach_error("mach_msg (receive): ", ret
);
471 fprintf(stderr
, "bailing after %u iterations\n",
476 printf("client received reply %d\n", idx
);
480 usleep(client_delay
);
489 int main(int argc
, char *argv
[])
491 struct port_args portargs
;
494 signal(SIGINT
, signal_handler
);
495 parse_args(argc
, argv
);
497 setup_server_ports(&portargs
);
504 if (num_clients
> 1) {
505 for (i
= 1; i
< num_clients
; i
++) {