xref: /NextBSD/lib/libmach/test/kqueue_tests/kqueue_tests.c (revision 33da5adc555b3bc29986eeadca03829e4ad06b1e)
1 /*
2  *  tests.c
3  *  xnu_quick_test
4  *
5  *  Created by Jerry Cottingham on 3/25/05.
6  *  Copyright 2005 Apple Computer Inc. All rights reserved.
7  *
8  */
9 
10 typedef int boolean_t;
11 #include <sys/types.h>
12 #include "tests.h"
13 #include <pthread.h>
14 #include <assert.h>
15 #include <sys/event.h>		/* for kqueue tests */
16 #include <sys/sysctl.h>		/* for determining hw */
17 #include <mach/mach.h>
18 #include <mach/mach_traps.h>
19 #include <AvailabilityMacros.h>	/* for determination of Mac OS X version (tiger, leopard, etc.) */
20 
21 
22 char		g_target_path[ PATH_MAX ];
23 extern int		g_skip_setuid_tests;
24 
25 int msg_count = 14;
26 int last_msg_seen = 0;
27 pthread_cond_t my_cond = PTHREAD_COND_INITIALIZER;
28 pthread_mutex_t my_mutex = PTHREAD_MUTEX_INITIALIZER;
29 
30 #define VM_MAKE_TAG(tag) ((tag) << 24)
31 #define VM_MEMORY_MACH_MSG 20
32 
33 /*
34  * create_random_name - creates a file with a random / unique name in the given directory.
35  * when do_open is true we create a file else we generaate a name that does not exist in the
36  * given directory (we do not create anything when do_open is 0).
37  * WARNING - caller provides enough space in path buffer for longest possible name.
38  * WARNING - assumes caller has appended a trailing '/' on the path passed to us.
39  * RAND_MAX is currently 2147483647 (ten characters plus one for a slash)
40  */
create_random_name(char * the_pathp,int do_open)41 int create_random_name( char *the_pathp, int do_open ) {
42 	int		i, my_err;
43 	int		my_fd = -1;
44 
45     for ( i = 0; i < 1; i++ ) {
46         int			my_rand;
47         char		*myp;
48         char		my_name[32];
49 
50         my_rand = rand( );
51         sprintf( &my_name[0], "%d", my_rand );
52         if ( (strlen( &my_name[0] ) + strlen( the_pathp ) + 2) > PATH_MAX ) {
53             printf( "%s - path to test file greater than PATH_MAX \n", __FUNCTION__ );
54             return( -1 );
55         }
56 
57         // append generated file name onto our path
58         myp = strrchr( the_pathp, '/' );
59         *(myp + 1) = 0x00;
60         strcat( the_pathp, &my_name[0] );
61 		if ( do_open ) {
62 			/* create a file with this name */
63 			my_fd = open( the_pathp, (O_RDWR | O_CREAT | O_EXCL),
64 							(S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH) );
65 			if ( my_fd == -1 ) {
66 				if ( errno != EEXIST ) {
67 					printf( "%s - open failed with errno %d - %s \n",
68 							__FUNCTION__, errno, strerror( errno ) );
69 					return( -1 );
70 				}
71 				// name already exists, try another
72 				i--;
73 				continue;
74 			}
75 		}
76 		else {
77 			/* make sure the name is unique */
78 			struct stat		my_sb;
79 			my_err = stat( the_pathp, &my_sb );
80 			if ( my_err != 0 ) {
81 				if ( errno == ENOENT ) {
82 					break;
83 				}
84 				else {
85 					printf( "%s - open failed with errno %d - %s \n",
86 							__FUNCTION__, errno, strerror( errno ) );
87 					return( -1 );
88 				}
89 			}
90 			/* name already exists, try another */
91 			i--;
92 			continue;
93 		}
94     }
95 
96 	if ( my_fd != -1 )
97 		close( my_fd );
98 
99 	return( 0 );
100 
101 } /* create_random_name */
102 
103 static kern_return_t
kmsg_send(mach_port_t remote_port,int index)104 kmsg_send(mach_port_t remote_port, int index)
105 {
106 	int msgh_id = 1000 + index;
107         kern_return_t my_kr;
108         mach_msg_header_t * my_kmsg = NULL;
109 	mach_msg_size_t size = sizeof(mach_msg_header_t) + sizeof(int)*index;
110 
111         my_kr = mach_vm_allocate( mach_task_self(),
112                              (vm_address_t *)&my_kmsg,
113                              size,
114                              VM_MAKE_TAG(VM_MEMORY_MACH_MSG) | TRUE );
115         if (my_kr != KERN_SUCCESS)
116                 return my_kr;
117         my_kmsg->msgh_bits =
118 		MACH_MSGH_BITS_SET(MACH_MSG_TYPE_COPY_SEND, 0, 0, 0);
119         my_kmsg->msgh_size = size;
120         my_kmsg->msgh_remote_port = remote_port;
121         my_kmsg->msgh_local_port = MACH_PORT_NULL;
122         my_kmsg->msgh_voucher_port = MACH_PORT_NULL;
123         my_kmsg->msgh_id = msgh_id;
124         my_kr = mach_msg( my_kmsg,
125                           MACH_SEND_MSG | MACH_MSG_OPTION_NONE,
126 			  size,
127                           0, /* receive size */
128                           MACH_PORT_NULL,
129                           MACH_MSG_TIMEOUT_NONE,
130                           MACH_PORT_NULL );
131         mach_vm_deallocate( mach_task_self(), (vm_address_t)my_kmsg, size );
132         return my_kr;
133 }
134 
135 static kern_return_t
kmsg_recv(mach_port_t portset,mach_port_t port,int * msgh_id_return)136 kmsg_recv(mach_port_t portset, mach_port_t port, int * msgh_id_return)
137 {
138         kern_return_t my_kr;
139         mach_msg_header_t * my_kmsg = NULL;
140 
141         my_kr = mach_vm_allocate( mach_task_self(),
142                              (vm_address_t *)&my_kmsg,
143                              PAGE_SIZE,
144                              VM_MAKE_TAG(VM_MEMORY_MACH_MSG) | TRUE );
145         if (my_kr != KERN_SUCCESS)
146                 return my_kr;
147         my_kr = mach_msg( my_kmsg,
148                           MACH_RCV_MSG | MACH_MSG_OPTION_NONE,
149                           0, /* send size */
150                           PAGE_SIZE, /* receive size */
151                           port,
152                           MACH_MSG_TIMEOUT_NONE,
153                           MACH_PORT_NULL );
154         if ( my_kr == KERN_SUCCESS &&
155              msgh_id_return != NULL )
156                 *msgh_id_return = my_kmsg->msgh_id;
157         mach_vm_deallocate( mach_task_self(), (vm_address_t)my_kmsg, PAGE_SIZE );
158         return my_kr;
159 }
160 
161 static void *
kmsg_consumer_thread(void * arg)162 kmsg_consumer_thread(void * arg)
163 {
164 	int		my_kqueue = *(int *)arg;
165 	int             my_err;
166 	kern_return_t   my_kr;
167 	struct kevent	my_keventv[3];
168 	int		msgid;
169 
170 	EV_SET( &my_keventv[0], 0, 0, 0, 0, 0, 0 );
171 	while ( !(my_keventv[0].filter == EVFILT_USER &&
172 	          my_keventv[0].ident == 0)) {
173 	        /* keep getting events */
174 	        my_err = kevent( my_kqueue, NULL, 0, my_keventv, 1, NULL );
175                 if ( my_err == -1 ) {
176                         printf( "kevent call from consumer thread failed with error %d - \"%s\" \n", errno, strerror( errno) );
177                         return (void *)-1;
178                 }
179                 if ( my_err == 0 ) {
180                         printf( "kevent call from consumer thread did not return any events when it should have \n" );
181                         return (void *)-1;
182                 }
183                 if ( my_keventv[0].filter == EVFILT_MACHPORT ) {
184                         if ( my_keventv[0].data == 0 ) {
185                                 printf( "kevent call to get machport event returned 0 msg_size \n" );
186                                 return (void *)-1;
187                         }
188                         my_kr = kmsg_recv( my_keventv[0].ident, my_keventv[0].data, &msgid );
189                         if ( my_kr != KERN_SUCCESS ) {
190                 		printf( "kmsg_recv failed with error %d - %s \n", my_kr, mach_error_string(my_kr) );
191                                 return (void *)-1;
192                         }
193                         my_keventv[0].flags = EV_ENABLE;
194                         my_err = kevent( my_kqueue, my_keventv, 1, NULL, 0, NULL );
195                         if ( my_err == -1 ) {
196                                 printf( "kevent call to re-enable machport events failed with error %d - \"%s\" \n", errno, strerror( errno) );
197                                 return (void *)-1;
198                         }
199 			if (msgid == 1000 + msg_count) {
200 				pthread_mutex_lock(&my_mutex);
201 				last_msg_seen = 1;
202 				pthread_cond_signal(&my_cond);
203 				pthread_mutex_unlock(&my_mutex);
204 			}
205                 }
206 	}
207         return (void *)0;
208 }
209 
210 
211 
212 /*  **************************************************************************************************************
213  *	Test kevent, kqueue system calls.
214  *  **************************************************************************************************************
215  */
kqueue_tests(void * the_argp)216 int kqueue_tests( void * the_argp )
217 {
218 	int				my_err, my_status;
219 	void				*my_pthread_join_status;
220 	int				my_kqueue = -1;
221 	int				my_kqueue64 = -1;
222 	int				my_fd = -1;
223 	char *			my_pathp = NULL;
224     pid_t			my_pid, my_wait_pid;
225 	size_t			my_count, my_index;
226 	int				my_sockets[ 2 ] = {-1, -1};
227 	struct kevent	my_keventv[3];
228 	struct kevent64_s	my_kevent64;
229 	struct timespec	my_timeout;
230 	char			my_buffer[ 16 ];
231 	kern_return_t kr;
232 
233 	kr = mach_vm_allocate((mach_vm_map_t) mach_task_self(), (vm_address_t*)&my_pathp, PATH_MAX, VM_FLAGS_ANYWHERE);
234         if(kr != KERN_SUCCESS){
235                 printf( "vm_allocate failed with error %d - \"%s\" \n", errno, strerror( errno) );
236                 goto test_failed_exit;
237         }
238 
239 	*my_pathp = 0x00;
240 	strcat( my_pathp, &g_target_path[0] );
241 	strcat( my_pathp, "/" );
242 
243 	/* create a test file */
244 	my_err = create_random_name( my_pathp, 1 );
245 	if ( my_err != 0 ) {
246 		goto test_failed_exit;
247 	}
248 
249 	my_fd = open( my_pathp, O_RDWR, 0 );
250 	if ( my_fd == -1 ) {
251 		printf( "open call failed with error %d - \"%s\" \n", errno, strerror( errno) );
252 		goto test_failed_exit;
253 	}
254 
255 	my_err = socketpair( AF_UNIX, SOCK_STREAM, 0, &my_sockets[0] );
256 	if ( my_err == -1 ) {
257 		printf( "socketpair failed with errno %d - %s \n", errno, strerror( errno ) );
258 		goto test_failed_exit;
259 	}
260 
261 	/* fork here and use pipe to communicate */
262 	my_pid = fork( );
263 	if ( my_pid == -1 ) {
264 		printf( "fork failed with errno %d - %s \n", errno, strerror( errno ) );
265 		goto test_failed_exit;
266 	}
267 	else if ( my_pid == 0 ) {
268 		/*
269 		 * child process - tell parent we are ready to go.
270 		 */
271 		my_count = write( my_sockets[1], "r", 1 );
272 		if ( my_count == -1 ) {
273 			printf( "write call failed.  got errno %d - %s. \n", errno, strerror( errno ) );
274 			exit( -1 );
275 		}
276 
277 		my_count = read( my_sockets[1], &my_buffer[0], 1 );
278 		if ( my_count == -1 ) {
279 			printf( "read call failed with error %d - \"%s\" \n", errno, strerror( errno) );
280 			exit( -1 );
281 		}
282 		if ( my_buffer[0] != 'g' ) {
283 			printf( "read call on socket failed to get \"all done\" message \n" );
284 			exit( -1 );
285 		}
286 
287 		/* now do some work that will trigger events our parent will track */
288 		my_count = write( my_fd, "11111111", 8 );
289 		if ( my_count == -1 ) {
290 			printf( "write call failed with error %d - \"%s\" \n", errno, strerror( errno) );
291 			exit( -1 );
292 		}
293 
294 		my_err = unlink( my_pathp );
295 		if ( my_err == -1 ) {
296 			printf( "unlink failed with error %d - \"%s\" \n", errno, strerror( errno) );
297 			exit( -1 );
298 		}
299 
300 		/* wait for parent to tell us to exit */
301 		my_count = read( my_sockets[1], &my_buffer[0], 1 );
302 		if ( my_count == -1 ) {
303 			printf( "read call failed with error %d - \"%s\" \n", errno, strerror( errno) );
304 			exit( -1 );
305 		}
306 		if ( my_buffer[0] != 'e' ) {
307 			printf( "read call on socket failed to get \"all done\" message \n" );
308 			exit( -1 );
309 		}
310 		exit(0);
311 	}
312 
313 	/* parent process - wait for child to spin up */
314 	my_count = read( my_sockets[0], &my_buffer[0], sizeof(my_buffer) );
315 	if ( my_count == -1 ) {
316 		printf( "read call failed with error %d - \"%s\" \n", errno, strerror( errno) );
317 		goto test_failed_exit;
318 	}
319 	if ( my_buffer[0] != 'r' ) {
320 		printf( "read call on socket failed to get \"ready to go message\" \n" );
321 		goto test_failed_exit;
322 	}
323 
324 	/* set up a kqueue and register for some events */
325 	my_kqueue = kqueue( );
326 	if ( my_kqueue == -1 ) {
327 		printf( "kqueue call failed with error %d - \"%s\" \n", errno, strerror( errno) );
328 		goto test_failed_exit;
329 	}
330 
331 	/* look for our test file to get unlinked or written to */
332 	EV_SET( &my_keventv[0], my_fd, EVFILT_VNODE, (EV_ADD | EV_CLEAR), (NOTE_DELETE | NOTE_WRITE), 0, 0 );
333 	/* also keep an eye on our child process while we're at it */
334 	EV_SET( &my_keventv[1], my_pid, EVFILT_PROC, (EV_ADD | EV_ONESHOT), NOTE_EXIT, 0, 0 );
335 
336 	my_timeout.tv_sec = 0;
337 	my_timeout.tv_nsec = 0;
338 	my_err = kevent( my_kqueue, my_keventv, 2, NULL, 0, &my_timeout);
339 	if ( my_err == -1 ) {
340 		printf( "kevent call to register events failed with error %d - \"%s\" \n", errno, strerror( errno) );
341 		goto test_failed_exit;
342 	}
343 
344 	/* use kevent64 to test EVFILT_PROC */
345 	EV_SET64( &my_kevent64, my_pid, EVFILT_PROC, EV_ADD, NOTE_EXIT, 0, 0, 0, 0 );
346 	my_err = kevent64( my_kqueue, &my_kevent64, 1, NULL, 0, 0, 0);
347 	if ( my_err != -1 && errno != EINVAL ) {
348 		printf( "kevent64 call should fail with kqueue used for kevent() - %d\n", my_err);
349 		/* goto test_failed_exit; */
350 	}
351 
352 	my_kqueue64 = kqueue();
353 	EV_SET64( &my_kevent64, my_pid, EVFILT_PROC, EV_ADD, NOTE_EXIT, 0, 0, 0, 0 );
354 	my_err = kevent64( my_kqueue64, &my_kevent64, 1, NULL, 0, 0, 0);
355 	if ( my_err == -1 ) {
356 		printf( "kevent64 call to get proc exit failed with error %d - \"%s\" \n", errno, strerror( errno) );
357 		goto test_failed_exit;
358 	}
359 
360 	/* tell child to get to work */
361 	my_count = write( my_sockets[0], "g", 1 );
362 	if ( my_count == -1 ) {
363 		printf( "write call failed.  got errno %d - %s. \n", errno, strerror( errno ) );
364 		goto test_failed_exit;
365 	}
366 
367 	/* go get vnode events */
368 	EV_SET( &my_keventv[0], my_fd, EVFILT_VNODE, (EV_CLEAR), 0, 0, 0 );
369 	my_err = kevent( my_kqueue, NULL, 0, my_keventv, 1, NULL );
370 	if ( my_err == -1 ) {
371 		printf( "kevent call to get vnode events failed with error %d - \"%s\" \n", errno, strerror( errno) );
372 		goto test_failed_exit;
373 	}
374 	if ( my_err == 0 ) {
375 		printf( "kevent call to get vnode events did not return any when it should have \n" );
376 		goto test_failed_exit;
377 	}
378 	if ( (my_keventv[0].fflags & (NOTE_DELETE | NOTE_WRITE)) == 0 ) {
379 		printf( "kevent call to get vnode events did not return NOTE_DELETE or NOTE_WRITE \n" );
380 		printf( "fflags 0x%02X \n", my_keventv[0].fflags );
381 		goto test_failed_exit;
382 	}
383 
384 	/* tell child to exit */
385 	my_count = write( my_sockets[0], "e", 1 );
386 	if ( my_count == -1 ) {
387 		printf( "write call failed.  got errno %d - %s. \n", errno, strerror( errno ) );
388 		goto test_failed_exit;
389 	}
390 
391 	/* look for child exit notification after unregistering for vnode events */
392 	EV_SET( &my_keventv[0], my_fd, EVFILT_VNODE, EV_DELETE, 0, 0, 0 );
393 	my_err = kevent( my_kqueue, my_keventv, 1, my_keventv, 1, NULL );
394 	if ( my_err == -1 ) {
395 		printf( "kevent call to get proc exit event failed with error %d - \"%s\" \n", errno, strerror( errno) );
396 		goto test_failed_exit;
397 	}
398 	if ( my_err == 0 ) {
399 		printf( "kevent call to get proc exit event did not return any when it should have \n" );
400 		goto test_failed_exit;
401 	}
402 	if ( my_keventv[0].filter != EVFILT_PROC ) {
403 		printf( "kevent call to get proc exit event did not return EVFILT_PROC \n" );
404 		printf( "filter %i \n", my_keventv[0].filter );
405 		goto test_failed_exit;
406 	}
407 	if ( (my_keventv[0].fflags & NOTE_EXIT) == 0 ) {
408 		printf( "kevent call to get proc exit event did not return NOTE_EXIT \n" );
409 		printf( "fflags 0x%02X \n", my_keventv[0].fflags );
410 		goto test_failed_exit;
411 	}
412 
413 	/* look for child exit notification on the kevent64 kqueue */
414 	EV_SET64( &my_kevent64, my_pid, EVFILT_PROC, EV_CLEAR, NOTE_EXIT, 0, 0, 0, 0 );
415 	my_err = kevent64( my_kqueue64, NULL, 0, &my_kevent64, 1, 0, 0);
416 	if ( my_err == -1 ) {
417 		printf( "kevent64 call to get child exit failed with error %d - \"%s\" \n", errno, strerror( errno) );
418 		goto test_failed_exit;
419 	}
420 	if ( my_err == 0 ) {
421 		printf( "kevent64 call to get proc exit event did not return any when it should have \n" );
422 		goto test_failed_exit;
423 	}
424 	if ( my_kevent64.filter != EVFILT_PROC ) {
425 		printf( "kevent64 call to get proc exit event did not return EVFILT_PROC \n" );
426 		printf( "filter %i \n", my_kevent64.filter );
427 		goto test_failed_exit;
428 	}
429 	if ( (my_kevent64.fflags & NOTE_EXIT) == 0 ) {
430 		printf( "kevent64 call to get proc exit event did not return NOTE_EXIT \n" );
431 		printf( "fflags 0x%02X \n", my_kevent64.fflags );
432 		goto test_failed_exit;
433 	}
434 
435 	my_wait_pid = wait4( my_pid, &my_status, 0, NULL );
436 	if ( my_wait_pid == -1 ) {
437 		printf( "wait4 failed with errno %d - %s \n", errno, strerror( errno ) );
438 		goto test_failed_exit;
439 	}
440 
441 	/* wait4 should return our child's pid when it exits */
442 	if ( my_wait_pid != my_pid ) {
443 		printf( "wait4 did not return child pid - returned %d should be %d \n", my_wait_pid, my_pid );
444 		goto test_failed_exit;
445 	}
446 
447 	if ( WIFEXITED( my_status ) && WEXITSTATUS( my_status ) != 0 ) {
448 		printf( "wait4 returned wrong exit status - 0x%02X \n", my_status );
449 		goto test_failed_exit;
450 	}
451 
452 	/* now try out EVFILT_MACHPORT and EVFILT_USER */
453 	mach_port_t my_pset = MACH_PORT_NULL;
454 	mach_port_t my_port = MACH_PORT_NULL;
455 	kern_return_t my_kr;
456 
457 	my_kr = mach_port_allocate( mach_task_self(), MACH_PORT_RIGHT_PORT_SET, &my_pset );
458 	if ( my_kr != KERN_SUCCESS ) {
459 		printf( "mach_port_allocate failed with error %d - %s \n", my_kr, mach_error_string(my_kr) );
460 		goto test_failed_exit;
461 	}
462 
463 	my_kr = mach_port_allocate( mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &my_port );
464 	if ( my_kr != KERN_SUCCESS ) {
465 		printf( "mach_port_allocate failed with error %d - %s \n", my_kr, mach_error_string(my_kr) );
466 		goto test_failed_exit;
467 	}
468 
469 	/* try to register for events on my_port directly -- this should fail */
470 	EV_SET( &my_keventv[0], my_port, EVFILT_MACHPORT, (EV_ADD | EV_DISPATCH), 0, 0, 0 );
471 	my_err = kevent( my_kqueue, my_keventv, 1, NULL, 0, NULL );
472 	if ( my_err != -1 || (errno != ENOTCAPABLE && errno != ENOTSUP) ) {
473 		printf( "kevent call to register my_port should have failed, but got %s \n", strerror(errno) );
474 		goto test_failed_exit;
475 	}
476 
477 	/* now register for events on my_pset and user 0 */
478 	EV_SET( &my_keventv[0], my_pset, EVFILT_MACHPORT, (EV_ADD | EV_CLEAR | EV_DISPATCH), 0, 0, 0 );
479 	EV_SET( &my_keventv[1], 0, EVFILT_USER, EV_ADD, 0, 0, 0 );
480 	my_err = kevent( my_kqueue, my_keventv, 2, NULL, 0, NULL );
481 	if ( my_err == -1 ) {
482 	        printf( "kevent call to register my_pset and user 0 failed with error %d - %s \n", errno, strerror( errno) );
483 		goto test_failed_exit;
484 	}
485 
486 	pthread_t my_threadv[3];
487 
488 	for (my_index = 0;
489 	     my_index < 3;
490 	     my_index++) {
491 	  my_err = pthread_create( &my_threadv[my_index], NULL, kmsg_consumer_thread, (void *)&my_kqueue );
492                 if ( my_err != 0 ) {
493                         printf( "pthread_create failed with error %d - %s \n", my_err, strerror(my_err) );
494                         goto test_failed_exit;
495                 }
496         }
497 
498 	/* insert my_port into my_pset */
499 	my_kr = mach_port_insert_member( mach_task_self(), my_port, my_pset );
500 	if ( my_kr != KERN_SUCCESS ) {
501 		printf( "mach_port_insert_member failed with error %d - %s \n", my_kr, mach_error_string(my_kr) );
502 		goto test_failed_exit;
503 	}
504 
505 	my_kr = mach_port_insert_right( mach_task_self(), my_port, my_port, MACH_MSG_TYPE_MAKE_SEND );
506 	if ( my_kr != KERN_SUCCESS ) {
507 		printf( "mach_port_insert_right failed with error %d - %s \n", my_kr, mach_error_string(my_kr) );
508 		goto test_failed_exit;
509 	}
510 
511 	/* send some Mach messages */
512 	for (my_index = 1;
513 	     my_index <= msg_count;
514 	     my_index++) {
515 	  my_kr = kmsg_send( my_port, my_index );
516                 if ( my_kr != KERN_SUCCESS ) {
517                         printf( "kmsg_send failed with error %d - %s \n", my_kr, mach_error_string(my_kr) );
518                         goto test_failed_exit;
519                 }
520         }
521 
522 	/* make sure the last message eventually gets processed */
523 	pthread_mutex_lock(&my_mutex);
524 	while (last_msg_seen == 0)
525 	  pthread_cond_wait(&my_cond, &my_mutex);
526 	pthread_mutex_unlock(&my_mutex);
527 
528 	/* trigger the user 0 event, telling consumer threads to exit */
529 	EV_SET( &my_keventv[0], 0, EVFILT_USER, 0, NOTE_TRIGGER, 0, 0 );
530 	my_err = kevent( my_kqueue, my_keventv, 1, NULL, 0, NULL );
531 	if ( my_err == -1 ) {
532 	        printf( "kevent call to trigger user 0 failed with error %d - %s \n", errno, strerror( errno) );
533 		goto test_failed_exit;
534 	}
535 
536 	for (my_index = 0;
537 	     my_index < 3;
538 	     my_index++) {
539 	  my_err = pthread_join( my_threadv[my_index], &my_pthread_join_status );
540                 if ( my_err != 0 ) {
541                         printf( "pthread_join failed with error %d - %s \n", my_err, strerror(my_err) );
542                         goto test_failed_exit;
543                 }
544                 if ( my_pthread_join_status != 0 ) {
545                         goto test_failed_exit;
546                 }
547         }
548 
549 	/* clear the user 0 event */
550 	EV_SET( &my_keventv[0], 0, EVFILT_USER, EV_CLEAR, 0, 0, 0 );
551 	my_err = kevent( my_kqueue, my_keventv, 1, NULL, 0, NULL );
552 	if ( my_err == -1 ) {
553 	        printf( "kevent call to trigger user 0 failed with error %d - %s \n", errno, strerror( errno) );
554 		goto test_failed_exit;
555 	}
556 
557 	/* delibrately destroy my_pset while it's still registered for events */
558 	my_kr = mach_port_mod_refs( mach_task_self(), my_pset, MACH_PORT_RIGHT_PORT_SET, -1 );
559 	if ( my_kr != KERN_SUCCESS ) {
560 		printf( "mach_port_mod_refs failed with error %d - %s \n", my_kr, mach_error_string(my_kr) );
561 		goto test_failed_exit;
562 	}
563 
564 	/* look for the event to trigger with a zero msg_size */
565 	my_err = kevent( my_kqueue, NULL, 0, my_keventv, 1, NULL );
566 	if ( my_err == -1 ) {
567 		printf( "kevent call to get machport event failed with error %d - \"%s\" \n", errno, strerror( errno) );
568 		goto test_failed_exit;
569 	}
570 	if ( my_err == 0 ) {
571 		printf( "kevent call to get machport event did not return any when it should have \n" );
572 		goto test_failed_exit;
573 	}
574 	if ( my_keventv[0].filter != EVFILT_MACHPORT ) {
575 		printf( "kevent call to get machport event did not return EVFILT_MACHPORT \n" );
576 		printf( "filter %i \n", my_keventv[0].filter );
577 		goto test_failed_exit;
578 	}
579 	if ( my_keventv[0].data != 0 ) {
580 		printf( "kevent call to get machport event did not return 0 msg_size \n" );
581 		printf( "data %ld \n", (long int) my_keventv[0].data );
582 		goto test_failed_exit;
583 	}
584 
585 	my_err = 0;
586 	goto test_passed_exit;
587 
588 test_failed_exit:
589 	my_err = -1;
590 
591 test_passed_exit:
592 	if ( my_sockets[0] != -1 )
593 		close( my_sockets[0] );
594 	if ( my_sockets[1] != -1 )
595 		close( my_sockets[1] );
596 	if ( my_kqueue != -1 )
597 		close( my_kqueue );
598 	if ( my_kqueue64 != -1 )
599 		close( my_kqueue );
600 	if ( my_fd != -1 )
601 		close( my_fd );
602 	if ( my_pathp != NULL ) {
603 		remove( my_pathp );
604 		mach_vm_deallocate(mach_task_self(), (vm_address_t)my_pathp, PATH_MAX);
605 	 }
606 	return( my_err );
607 }
608 
609 
610 int
main(int argc,char * argv[])611 main(int argc, char *argv[]) {
612 
613 	return (kqueue_tests(NULL));
614 }
615 
616