5 * Created by Jerry Cottingham on 3/25/05.
6 * Copyright 2005 Apple Computer Inc. All rights reserved.
13 #include <sys/event.h> /* for kqueue tests */
14 #include <sys/sysctl.h> /* for determining hw */
15 #include <mach/mach.h>
16 #include <AvailabilityMacros.h> /* for determination of Mac OS X version (tiger, leopard, etc.) */
17 #include <libkern/OSByteOrder.h> /* for OSSwap32() */
19 extern char g_target_path
[ PATH_MAX
];
20 extern int g_skip_setuid_tests
;
21 extern int g_is_under_rosetta
;
24 int last_msg_seen
= 0;
25 pthread_cond_t my_cond
= PTHREAD_COND_INITIALIZER
;
26 pthread_mutex_t my_mutex
= PTHREAD_MUTEX_INITIALIZER
;
30 kmsg_send(mach_port_t remote_port
, int index
)
32 int msgh_id
= 1000 + index
;
34 mach_msg_header_t
* my_kmsg
= NULL
;
35 mach_msg_size_t size
= sizeof(mach_msg_header_t
) + sizeof(int)*index
;
37 my_kr
= vm_allocate( mach_task_self(),
38 (vm_address_t
*)&my_kmsg
,
40 VM_MAKE_TAG(VM_MEMORY_MACH_MSG
) | TRUE
);
41 if (my_kr
!= KERN_SUCCESS
)
43 my_kmsg
->msgh_bits
= MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND
, 0);
44 my_kmsg
->msgh_size
= size
;
45 my_kmsg
->msgh_remote_port
= remote_port
;
46 my_kmsg
->msgh_local_port
= MACH_PORT_NULL
;
47 my_kmsg
->msgh_reserved
= 0;
48 my_kmsg
->msgh_id
= msgh_id
;
49 my_kr
= mach_msg( my_kmsg
,
50 MACH_SEND_MSG
| MACH_MSG_OPTION_NONE
,
54 MACH_MSG_TIMEOUT_NONE
,
56 vm_deallocate( mach_task_self(), (vm_address_t
)my_kmsg
, size
);
61 kmsg_recv(mach_port_t portset
, mach_port_t port
, int * msgh_id_return
)
64 mach_msg_header_t
* my_kmsg
= NULL
;
66 my_kr
= vm_allocate( mach_task_self(),
67 (vm_address_t
*)&my_kmsg
,
69 VM_MAKE_TAG(VM_MEMORY_MACH_MSG
) | TRUE
);
70 if (my_kr
!= KERN_SUCCESS
)
72 my_kr
= mach_msg( my_kmsg
,
73 MACH_RCV_MSG
| MACH_MSG_OPTION_NONE
,
75 PAGE_SIZE
, /* receive size */
77 MACH_MSG_TIMEOUT_NONE
,
79 if ( my_kr
== KERN_SUCCESS
&&
80 msgh_id_return
!= NULL
)
81 *msgh_id_return
= my_kmsg
->msgh_id
;
82 vm_deallocate( mach_task_self(), (vm_address_t
)my_kmsg
, PAGE_SIZE
);
87 kmsg_consumer_thread(void * arg
)
89 #if !TARGET_OS_EMBEDDED
90 int my_kqueue
= *(int *)arg
;
93 struct kevent my_keventv
[3];
96 EV_SET( &my_keventv
[0], 0, 0, 0, 0, 0, 0 );
97 while ( !(my_keventv
[0].filter
== EVFILT_USER
&&
98 my_keventv
[0].ident
== 0)) {
99 /* keep getting events */
100 my_err
= kevent( my_kqueue
, NULL
, 0, my_keventv
, 1, NULL
);
101 if ( my_err
== -1 ) {
102 printf( "kevent call from consumer thread failed with error %d - \"%s\" \n", errno
, strerror( errno
) );
106 printf( "kevent call from consumer thread did not return any events when it should have \n" );
109 if ( my_keventv
[0].filter
== EVFILT_MACHPORT
) {
110 if ( my_keventv
[0].data
== 0 ) {
111 printf( "kevent call to get machport event returned 0 msg_size \n" );
114 my_kr
= kmsg_recv( my_keventv
[0].ident
, my_keventv
[0].data
, &msgid
);
115 if ( my_kr
!= KERN_SUCCESS
) {
116 printf( "kmsg_recv failed with error %d - %s \n", my_kr
, mach_error_string(my_kr
) );
119 my_keventv
[0].flags
= EV_ENABLE
;
120 my_err
= kevent( my_kqueue
, my_keventv
, 1, NULL
, 0, NULL
);
121 if ( my_err
== -1 ) {
122 printf( "kevent call to re-enable machport events failed with error %d - \"%s\" \n", errno
, strerror( errno
) );
125 if (msgid
== 1000 + msg_count
) {
126 pthread_mutex_lock(&my_mutex
);
128 pthread_cond_signal(&my_cond
);
129 pthread_mutex_unlock(&my_mutex
);
135 printf( "\t--> Not supported on EMBEDDED TARGET\n" );
140 /* **************************************************************************************************************
141 * Test kevent, kqueue system calls.
142 * **************************************************************************************************************
144 int kqueue_tests( void * the_argp
)
146 int my_err
, my_status
;
148 int my_kqueue64
= -1;
150 char * my_pathp
= NULL
;
151 pid_t my_pid
, my_wait_pid
;
152 size_t my_count
, my_index
;
153 int my_sockets
[ 2 ] = {-1, -1};
154 struct kevent my_keventv
[3];
155 #if !TARGET_OS_EMBEDDED
156 struct kevent64_s my_kevent64
;
158 struct timespec my_timeout
;
159 char my_buffer
[ 16 ];
162 kr
= vm_allocate((vm_map_t
) mach_task_self(), (vm_address_t
*)&my_pathp
, PATH_MAX
, VM_FLAGS_ANYWHERE
);
163 if(kr
!= KERN_SUCCESS
){
164 printf( "vm_allocate failed with error %d - \"%s\" \n", errno
, strerror( errno
) );
165 goto test_failed_exit
;
169 strcat( my_pathp
, &g_target_path
[0] );
170 strcat( my_pathp
, "/" );
172 /* create a test file */
173 my_err
= create_random_name( my_pathp
, 1 );
175 goto test_failed_exit
;
178 my_fd
= open( my_pathp
, O_RDWR
, 0 );
180 printf( "open call failed with error %d - \"%s\" \n", errno
, strerror( errno
) );
181 goto test_failed_exit
;
184 my_err
= socketpair( AF_UNIX
, SOCK_STREAM
, 0, &my_sockets
[0] );
185 if ( my_err
== -1 ) {
186 printf( "socketpair failed with errno %d - %s \n", errno
, strerror( errno
) );
187 goto test_failed_exit
;
190 /* fork here and use pipe to communicate */
192 if ( my_pid
== -1 ) {
193 printf( "fork failed with errno %d - %s \n", errno
, strerror( errno
) );
194 goto test_failed_exit
;
196 else if ( my_pid
== 0 ) {
198 * child process - tell parent we are ready to go.
200 my_count
= write( my_sockets
[1], "r", 1 );
201 if ( my_count
== -1 ) {
202 printf( "write call failed. got errno %d - %s. \n", errno
, strerror( errno
) );
206 my_count
= read( my_sockets
[1], &my_buffer
[0], 1 );
207 if ( my_count
== -1 ) {
208 printf( "read call failed with error %d - \"%s\" \n", errno
, strerror( errno
) );
211 if ( my_buffer
[0] != 'g' ) {
212 printf( "read call on socket failed to get \"all done\" message \n" );
216 /* now do some work that will trigger events our parent will track */
217 my_count
= write( my_fd
, "11111111", 8 );
218 if ( my_count
== -1 ) {
219 printf( "write call failed with error %d - \"%s\" \n", errno
, strerror( errno
) );
223 my_err
= unlink( my_pathp
);
224 if ( my_err
== -1 ) {
225 printf( "unlink failed with error %d - \"%s\" \n", errno
, strerror( errno
) );
229 /* wait for parent to tell us to exit */
230 my_count
= read( my_sockets
[1], &my_buffer
[0], 1 );
231 if ( my_count
== -1 ) {
232 printf( "read call failed with error %d - \"%s\" \n", errno
, strerror( errno
) );
235 if ( my_buffer
[0] != 'e' ) {
236 printf( "read call on socket failed to get \"all done\" message \n" );
242 /* parent process - wait for child to spin up */
243 my_count
= read( my_sockets
[0], &my_buffer
[0], sizeof(my_buffer
) );
244 if ( my_count
== -1 ) {
245 printf( "read call failed with error %d - \"%s\" \n", errno
, strerror( errno
) );
246 goto test_failed_exit
;
248 if ( my_buffer
[0] != 'r' ) {
249 printf( "read call on socket failed to get \"ready to go message\" \n" );
250 goto test_failed_exit
;
253 /* set up a kqueue and register for some events */
254 my_kqueue
= kqueue( );
255 if ( my_kqueue
== -1 ) {
256 printf( "kqueue call failed with error %d - \"%s\" \n", errno
, strerror( errno
) );
257 goto test_failed_exit
;
260 /* look for our test file to get unlinked or written to */
261 EV_SET( &my_keventv
[0], my_fd
, EVFILT_VNODE
, (EV_ADD
| EV_CLEAR
), (NOTE_DELETE
| NOTE_WRITE
), 0, 0 );
262 /* also keep an eye on our child process while we're at it */
263 EV_SET( &my_keventv
[1], my_pid
, EVFILT_PROC
, (EV_ADD
| EV_ONESHOT
), NOTE_EXIT
, 0, 0 );
265 my_timeout
.tv_sec
= 0;
266 my_timeout
.tv_nsec
= 0;
267 my_err
= kevent( my_kqueue
, my_keventv
, 2, NULL
, 0, &my_timeout
);
268 if ( my_err
== -1 ) {
269 printf( "kevent call to register events failed with error %d - \"%s\" \n", errno
, strerror( errno
) );
270 goto test_failed_exit
;
273 #if !TARGET_OS_EMBEDDED
274 if (!g_is_under_rosetta
) {
275 /* use kevent64 to test EVFILT_PROC */
276 EV_SET64( &my_kevent64
, my_pid
, EVFILT_PROC
, EV_ADD
, NOTE_EXIT
, 0, 0, 0, 0 );
277 my_err
= kevent64( my_kqueue
, &my_kevent64
, 1, NULL
, 0, 0, 0);
278 if ( my_err
!= -1 && errno
!= EINVAL
) {
279 printf( "kevent64 call should fail with kqueue used for kevent() - %d\n", my_err
);
280 goto test_failed_exit
;
283 my_kqueue64
= kqueue();
284 EV_SET64( &my_kevent64
, my_pid
, EVFILT_PROC
, EV_ADD
, NOTE_EXIT
, 0, 0, 0, 0 );
285 my_err
= kevent64( my_kqueue64
, &my_kevent64
, 1, NULL
, 0, 0, 0);
286 if ( my_err
== -1 ) {
287 printf( "kevent64 call to get proc exit failed with error %d - \"%s\" \n", errno
, strerror( errno
) );
288 goto test_failed_exit
;
293 /* tell child to get to work */
294 my_count
= write( my_sockets
[0], "g", 1 );
295 if ( my_count
== -1 ) {
296 printf( "write call failed. got errno %d - %s. \n", errno
, strerror( errno
) );
297 goto test_failed_exit
;
300 /* go get vnode events */
301 EV_SET( &my_keventv
[0], my_fd
, EVFILT_VNODE
, (EV_CLEAR
), 0, 0, 0 );
302 my_err
= kevent( my_kqueue
, NULL
, 0, my_keventv
, 1, NULL
);
303 if ( my_err
== -1 ) {
304 printf( "kevent call to get vnode events failed with error %d - \"%s\" \n", errno
, strerror( errno
) );
305 goto test_failed_exit
;
308 printf( "kevent call to get vnode events did not return any when it should have \n" );
309 goto test_failed_exit
;
311 if ( (my_keventv
[0].fflags
& (NOTE_DELETE
| NOTE_WRITE
)) == 0 ) {
312 printf( "kevent call to get vnode events did not return NOTE_DELETE or NOTE_WRITE \n" );
313 printf( "fflags 0x%02X \n", my_keventv
[0].fflags
);
314 goto test_failed_exit
;
317 /* tell child to exit */
318 my_count
= write( my_sockets
[0], "e", 1 );
319 if ( my_count
== -1 ) {
320 printf( "write call failed. got errno %d - %s. \n", errno
, strerror( errno
) );
321 goto test_failed_exit
;
324 /* look for child exit notification after unregistering for vnode events */
325 EV_SET( &my_keventv
[0], my_fd
, EVFILT_VNODE
, EV_DELETE
, 0, 0, 0 );
326 my_err
= kevent( my_kqueue
, my_keventv
, 1, my_keventv
, 1, NULL
);
327 if ( my_err
== -1 ) {
328 printf( "kevent call to get proc exit event failed with error %d - \"%s\" \n", errno
, strerror( errno
) );
329 goto test_failed_exit
;
332 printf( "kevent call to get proc exit event did not return any when it should have \n" );
333 goto test_failed_exit
;
335 if ( my_keventv
[0].filter
!= EVFILT_PROC
) {
336 printf( "kevent call to get proc exit event did not return EVFILT_PROC \n" );
337 printf( "filter %i \n", my_keventv
[0].filter
);
338 goto test_failed_exit
;
340 if ( (my_keventv
[0].fflags
& NOTE_EXIT
) == 0 ) {
341 printf( "kevent call to get proc exit event did not return NOTE_EXIT \n" );
342 printf( "fflags 0x%02X \n", my_keventv
[0].fflags
);
343 goto test_failed_exit
;
346 #if !TARGET_OS_EMBEDDED
347 if (!g_is_under_rosetta
) {
348 /* look for child exit notification on the kevent64 kqueue */
349 EV_SET64( &my_kevent64
, my_pid
, EVFILT_PROC
, EV_CLEAR
, NOTE_EXIT
, 0, 0, 0, 0 );
350 my_err
= kevent64( my_kqueue64
, NULL
, 0, &my_kevent64
, 1, 0, 0);
351 if ( my_err
== -1 ) {
352 printf( "kevent64 call to get child exit failed with error %d - \"%s\" \n", errno
, strerror( errno
) );
353 goto test_failed_exit
;
356 printf( "kevent64 call to get proc exit event did not return any when it should have \n" );
357 goto test_failed_exit
;
359 if ( my_kevent64
.filter
!= EVFILT_PROC
) {
360 printf( "kevent64 call to get proc exit event did not return EVFILT_PROC \n" );
361 printf( "filter %i \n", my_kevent64
.filter
);
362 goto test_failed_exit
;
364 if ( (my_kevent64
.fflags
& NOTE_EXIT
) == 0 ) {
365 printf( "kevent64 call to get proc exit event did not return NOTE_EXIT \n" );
366 printf( "fflags 0x%02X \n", my_kevent64
.fflags
);
367 goto test_failed_exit
;
371 my_wait_pid
= wait4( my_pid
, &my_status
, 0, NULL
);
372 if ( my_wait_pid
== -1 ) {
373 printf( "wait4 failed with errno %d - %s \n", errno
, strerror( errno
) );
374 goto test_failed_exit
;
377 /* wait4 should return our child's pid when it exits */
378 if ( my_wait_pid
!= my_pid
) {
379 printf( "wait4 did not return child pid - returned %d should be %d \n", my_wait_pid
, my_pid
);
380 goto test_failed_exit
;
383 if ( WIFEXITED( my_status
) && WEXITSTATUS( my_status
) != 0 ) {
384 printf( "wait4 returned wrong exit status - 0x%02X \n", my_status
);
385 goto test_failed_exit
;
388 /* now try out EVFILT_MACHPORT and EVFILT_USER */
389 mach_port_t my_pset
= MACH_PORT_NULL
;
390 mach_port_t my_port
= MACH_PORT_NULL
;
393 my_kr
= mach_port_allocate( mach_task_self(), MACH_PORT_RIGHT_PORT_SET
, &my_pset
);
394 if ( my_kr
!= KERN_SUCCESS
) {
395 printf( "mach_port_allocate failed with error %d - %s \n", my_kr
, mach_error_string(my_kr
) );
396 goto test_failed_exit
;
399 my_kr
= mach_port_allocate( mach_task_self(), MACH_PORT_RIGHT_RECEIVE
, &my_port
);
400 if ( my_kr
!= KERN_SUCCESS
) {
401 printf( "mach_port_allocate failed with error %d - %s \n", my_kr
, mach_error_string(my_kr
) );
402 goto test_failed_exit
;
405 /* try to register for events on my_port directly -- this should fail */
406 EV_SET( &my_keventv
[0], my_port
, EVFILT_MACHPORT
, (EV_ADD
| EV_DISPATCH
), 0, 0, 0 );
407 my_err
= kevent( my_kqueue
, my_keventv
, 1, NULL
, 0, NULL
);
408 if ( my_err
!= -1 || errno
!= ENOTSUP
) {
409 printf( "kevent call to register my_port should have failed, but got %s \n", strerror(errno
) );
410 goto test_failed_exit
;
413 /* now register for events on my_pset and user 0 */
414 EV_SET( &my_keventv
[0], my_pset
, EVFILT_MACHPORT
, (EV_ADD
| EV_CLEAR
| EV_DISPATCH
), 0, 0, 0 );
415 EV_SET( &my_keventv
[1], 0, EVFILT_USER
, EV_ADD
, 0, 0, 0 );
416 my_err
= kevent( my_kqueue
, my_keventv
, 2, NULL
, 0, NULL
);
417 if ( my_err
== -1 ) {
418 printf( "kevent call to register my_pset and user 0 failed with error %d - %s \n", errno
, strerror( errno
) );
419 goto test_failed_exit
;
422 pthread_t my_threadv
[3];
427 my_err
= pthread_create( &my_threadv
[my_index
], NULL
, kmsg_consumer_thread
, (void *)&my_kqueue
);
429 printf( "pthread_create failed with error %d - %s \n", my_err
, strerror(my_err
) );
430 goto test_failed_exit
;
434 /* insert my_port into my_pset */
435 my_kr
= mach_port_insert_member( mach_task_self(), my_port
, my_pset
);
436 if ( my_kr
!= KERN_SUCCESS
) {
437 printf( "mach_port_insert_member failed with error %d - %s \n", my_kr
, mach_error_string(my_kr
) );
438 goto test_failed_exit
;
441 my_kr
= mach_port_insert_right( mach_task_self(), my_port
, my_port
, MACH_MSG_TYPE_MAKE_SEND
);
442 if ( my_kr
!= KERN_SUCCESS
) {
443 printf( "mach_port_insert_right failed with error %d - %s \n", my_kr
, mach_error_string(my_kr
) );
444 goto test_failed_exit
;
447 /* send some Mach messages */
449 my_index
<= msg_count
;
451 my_kr
= kmsg_send( my_port
, my_index
);
452 if ( my_kr
!= KERN_SUCCESS
) {
453 printf( "kmsg_send failed with error %d - %s \n", my_kr
, mach_error_string(my_kr
) );
454 goto test_failed_exit
;
458 /* make sure the last message eventually gets processed */
459 pthread_mutex_lock(&my_mutex
);
460 while (last_msg_seen
== 0)
461 pthread_cond_wait(&my_cond
, &my_mutex
);
462 pthread_mutex_unlock(&my_mutex
);
464 /* trigger the user 0 event, telling consumer threads to exit */
465 EV_SET( &my_keventv
[0], 0, EVFILT_USER
, 0, NOTE_TRIGGER
, 0, 0 );
466 my_err
= kevent( my_kqueue
, my_keventv
, 1, NULL
, 0, NULL
);
467 if ( my_err
== -1 ) {
468 printf( "kevent call to trigger user 0 failed with error %d - %s \n", errno
, strerror( errno
) );
469 goto test_failed_exit
;
475 my_err
= pthread_join( my_threadv
[my_index
], (void **)&my_status
);
477 printf( "pthread_join failed with error %d - %s \n", my_err
, strerror(my_err
) );
478 goto test_failed_exit
;
480 if ( my_status
!= 0 ) {
481 goto test_failed_exit
;
485 /* clear the user 0 event */
486 EV_SET( &my_keventv
[0], 0, EVFILT_USER
, EV_CLEAR
, 0, 0, 0 );
487 my_err
= kevent( my_kqueue
, my_keventv
, 1, NULL
, 0, NULL
);
488 if ( my_err
== -1 ) {
489 printf( "kevent call to trigger user 0 failed with error %d - %s \n", errno
, strerror( errno
) );
490 goto test_failed_exit
;
493 /* delibrately destroy my_pset while it's still registered for events */
494 my_kr
= mach_port_mod_refs( mach_task_self(), my_pset
, MACH_PORT_RIGHT_PORT_SET
, -1 );
495 if ( my_kr
!= KERN_SUCCESS
) {
496 printf( "mach_port_mod_refs failed with error %d - %s \n", my_kr
, mach_error_string(my_kr
) );
497 goto test_failed_exit
;
500 /* look for the event to trigger with a zero msg_size */
501 my_err
= kevent( my_kqueue
, NULL
, 0, my_keventv
, 1, NULL
);
502 if ( my_err
== -1 ) {
503 printf( "kevent call to get machport event failed with error %d - \"%s\" \n", errno
, strerror( errno
) );
504 goto test_failed_exit
;
507 printf( "kevent call to get machport event did not return any when it should have \n" );
508 goto test_failed_exit
;
510 if ( my_keventv
[0].filter
!= EVFILT_MACHPORT
) {
511 printf( "kevent call to get machport event did not return EVFILT_MACHPORT \n" );
512 printf( "filter %i \n", my_keventv
[0].filter
);
513 goto test_failed_exit
;
515 if ( my_keventv
[0].data
!= 0 ) {
516 printf( "kevent call to get machport event did not return 0 msg_size \n" );
517 printf( "data %ld \n", (long int) my_keventv
[0].data
);
518 goto test_failed_exit
;
523 goto test_passed_exit
;
529 if ( my_sockets
[0] != -1 )
530 close( my_sockets
[0] );
531 if ( my_sockets
[1] != -1 )
532 close( my_sockets
[1] );
533 if ( my_kqueue
!= -1 )
535 if ( my_kqueue64
!= -1 )
539 if ( my_pathp
!= NULL
) {
541 vm_deallocate(mach_task_self(), (vm_address_t
)my_pathp
, PATH_MAX
);