Example #1
0
static void kqueue_set_nsecs(struct kqueue_timer *our_timer, uint64_t nsecs)
{
	struct timespec nowait = { 0, 1 };
#ifdef HAVE_KEVENT64
	struct kevent64_s kev;

	EV_SET64(&kev, our_timer->handle, EVFILT_TIMER, EV_ADD | EV_ENABLE, NOTE_NSECONDS,
		nsecs, 0, 0, 0);
	kevent64(our_timer->handle, &kev, 1, NULL, 0, 0, &nowait);
#else
	struct kevent kev;

	EV_SET(&kev, our_timer->handle, EVFILT_TIMER, EV_ADD | EV_ENABLE,
#ifdef NOTE_NSECONDS
		nsecs <= 0xFFffFFff ? NOTE_NSECONDS :
#endif
#ifdef NOTE_USECONDS
		NOTE_USECONDS
#else /* Milliseconds, if no constants are defined */
		0
#endif
		,
#ifdef NOTE_NSECONDS
		nsecs <= 0xFFffFFff ? nsecs :
#endif
#ifdef NOTE_USECONDS
	nsecs / 1000
#else /* Milliseconds, if nothing else is defined */
	nsecs / 1000000
#endif
	, NULL);
	kevent(our_timer->handle, &kev, 1, NULL, 0, &nowait);
#endif
}
Example #2
0
void
poll_events(reg q, function f)
{
	struct kevent64_s ke[MAX_EVENTS];
	int n = kevent64(q,NULL,0,ke,MAX_EVENTS,0,NULL);
	if (n <= 0) return;
	for (int i = 0; i < n; ++i) 
		f(ke[i].ident,ke[i].filter == EVFILT_PROC ? PROC : NONE);	
}
Example #3
0
reg
add_event(reg q, reg fd, enum event_types t, enum event_flags f)
{
	struct kevent64_s ke;
	EV_SET64(&ke,fd,(t == READ || t == RESP ? EVFILT_READ :
		t == WRITE || t == REQ ? EVFILT_WRITE :
		t == PROC ? EVFILT_PROC :
		t == NODE ? EVFILT_VNODE : 0),
		EV_ADD | (f == ONESHOT ? EV_ONESHOT : 0),
		(f == EXIT ? NOTE_EXIT : 0), 0, 0, 0, 0);
	return kevent64(q,&ke,1,NULL,0,0, &ts);
}
		sleep(1);
		T_LOG("waited %d seconds for sleep...", i+1);
	}
	return -1;
}

T_DECL(kevent_continuous_time_periodic_tick, "kevent(EVFILT_TIMER with NOTE_MACH_CONTINUOUS_TIME)", T_META_LTEPHASE(LTE_POSTINIT)){
	mach_timebase_info(&tb_info);
	int kq;
	T_ASSERT_POSIX_SUCCESS((kq = kqueue()), NULL);

	struct kevent64_s change = {0};
	EV_SET64(&change, 1, EVFILT_TIMER, EV_ADD, NOTE_SECONDS | NOTE_MACH_CONTINUOUS_TIME, 4, 0, 0, 0);
	T_LOG("EV_SET(&change, 1, EVFILT_TIMER, EV_ADD, NOTE_SECONDS | NOTE_MACH_CONTINUOUS_TIME, 4, 0, 0, 0);");

	T_ASSERT_POSIX_ZERO(kevent64(kq, &change, 1, NULL, 0, 0, NULL), NULL);

	uint64_t abs_then = mach_absolute_time();
	uint64_t cnt_then = mach_continuous_time();;

	trigger_sleep(1);
	int sleep_secs = wait_for_sleep();

	struct kevent64_s event = {0};
	T_WITH_ERRNO; T_ASSERT_EQ(kevent64(kq, NULL, 0, &event, 1, 0, NULL), 1, "kevent() should have returned one event");
	T_LOG("event = {.ident = %llx, .filter = %d, .flags = %d, .fflags = %d, .data = %lld, .udata = %lld}", event.ident, event.filter, event.flags, event.fflags, event.data, event.udata);
	T_ASSERT_EQ(event.flags & EV_ERROR, 0, "event should not have EV_ERROR set: %s", event.flags & EV_ERROR ? strerror((int)event.data) : "no error");

	uint64_t abs_now = mach_absolute_time();
	uint64_t cnt_now = mach_continuous_time();;
	uint64_t ct_ms_progressed = tick_to_ms(cnt_now - cnt_then);
int main()
{
	kern_return_t kr;
	mach_port_t bport, port, pset;
	struct msg_recv message;
	struct msg_send reply;
	struct kevent64_s kev;
	int kq, r;

	task_get_special_port(mach_task_self(), TASK_BOOTSTRAP_PORT, &bport);
	syslog(LOG_ERR, "bootstrap port: %d", bport);

	kr = bootstrap_check_in(bootstrap_port, "mach.service-test", &port);
	if (kr != KERN_SUCCESS) {
		syslog(LOG_ERR, "bootstrap_check_in: kr=%d", kr);
		exit(1);
	}

	syslog(LOG_ERR, "service port: %d", port);

	kr = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_PORT_SET, &pset);
	if (kr != KERN_SUCCESS) {
		syslog(LOG_ERR, "mach_port_allocate: kr=%d", kr);
		exit(1);
	}

	kr = mach_port_move_member(mach_task_self(), port, pset);
	if (kr != KERN_SUCCESS) {
		syslog(LOG_ERR, "mach_port_move_member: kr=%d", kr);
		exit(1);
	}

	kq = kqueue();
	syslog(LOG_ERR, "kqueue fd: %d", kq);

	memset(&kev, 0, sizeof(struct kevent64_s));
	EV_SET64(&kev, pset, EVFILT_MACHPORT, EV_ADD | EV_ENABLE, 0, 0, 0, 0, 0);
	if (kevent64(kq, &kev, 1, NULL, 0, 0, NULL) < 0) {
		syslog(LOG_ERR, "kevent64: %s (%d)", strerror(errno), errno);
		return 0;
	}

	for (;;) {
		message.hdr.msgh_local_port = port;
		message.hdr.msgh_size = sizeof(struct msg_recv);

		r = kevent64(kq, NULL, 0, &kev, 1, 0, NULL);
		if (r < 0) {
			syslog(LOG_ERR, "kevent64 failed: %s (%d)", strerror(errno), errno);
			continue;
		}

		syslog(LOG_ERR, "kevent64: events=%d", r);

		kr = mach_msg_receive((mach_msg_header_t *)&message);
		if (kr != KERN_SUCCESS)
			syslog(LOG_ERR, "mach_msg_receive failure: kr=%d", kr);
		else
			syslog(LOG_ERR, "received message on port %d: body=%s", message.hdr.msgh_remote_port, message.body);

		memset(&reply, 0, sizeof(struct msg_send));
		sprintf(&reply.body[0], "hello buddy");
		reply.hdr.msgh_local_port = MACH_PORT_NULL;
		reply.hdr.msgh_remote_port = message.hdr.msgh_remote_port;
		reply.hdr.msgh_size = sizeof(struct msg_send);
		reply.hdr.msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, 0);
		kr = mach_msg_send((mach_msg_header_t *)&reply);
		if (kr != KERN_SUCCESS)
			syslog(LOG_ERR, "mach_msg_send failure: kr=%d", kr);
	}
}
Example #6
0
void *
server(void *serverarg) 
{
	int kq;
	struct kevent64_s kev[1];
	int err;
	struct port_args args;
	int idx;
	kern_return_t ret;
	int totalmsg = num_msgs * num_clients;

	args.server_num = (int) (long) serverarg;
	setup_server_ports(&args);

	thread_setup(args.server_num + 1);
	
	kq = kqueue();
	if (kq == -1) {
		perror("kqueue");
		exit(1);
	}
	EV_SET64(&kev[0], args.pset, EVFILT_MACHPORT, (EV_ADD | EV_CLEAR | EV_DISPATCH), 
#if DIRECT_MSG_RCV
		 MACH_RCV_MSG|MACH_RCV_LARGE, 0, 0, (mach_vm_address_t)args.req_msg, args.req_size);
#else
		0, 0, 0, 0, 0);
#endif
	err = kevent64(kq, kev, 1, NULL, 0, 0, NULL);
	if (err == -1) {
		perror("kevent");
		exit(1);
	}
	for (idx = 0; idx < totalmsg; idx++) {

		if (verbose) 
			printf("server awaiting message %d\n", idx);
	retry:
		EV_SET64(&kev[0], args.pset, EVFILT_MACHPORT, EV_ENABLE, 
#if DIRECT_MSG_RCV
			 MACH_RCV_MSG|MACH_RCV_LARGE, 0, 0, (mach_vm_address_t)args.req_msg, args.req_size);
#else
			0, 0, 0, 0, 0);
#endif
		err = kevent64(kq, kev, 1, kev, 1, 0, NULL);
		if (err == -1) {
			perror("kevent64");
			exit(1);
		}		
		if (err == 0) {
		  // printf("kevent64: returned zero\n");
			goto retry;
		}

#if DIRECT_MSG_RCV
		ret = kev[0].fflags;
		if (MACH_MSG_SUCCESS != ret) {
			if (verbose)
				printf("kevent64() mach_msg_return=%d", ret);
			mach_error("kevent64 (msg receive): ", ret);
			exit(1);
		} 
#else
		if (kev[0].data != args.port)
			printf("kevent64(MACH_PORT_NULL) port name (0x%x) != expected (0x%x)\n", kev[0].data, args.port);

		args.req_msg->msgh_bits = 0;
		args.req_msg->msgh_size = args.req_size;
		args.req_msg->msgh_local_port = args.port;
		ret = mach_msg(args.req_msg,  
				MACH_RCV_MSG|MACH_RCV_INTERRUPT|MACH_RCV_LARGE, 
				0, 
				args.req_size,  
				args.pset, 
				MACH_MSG_TIMEOUT_NONE, 
				MACH_PORT_NULL);
		if (MACH_RCV_INTERRUPTED == ret)
			break;
		if (MACH_MSG_SUCCESS != ret) {
			if (verbose)
				printf("mach_msg() ret=%d", ret);
			mach_error("mach_msg (receive): ", ret);
			exit(1);
		}
#endif
		if (verbose)
			printf("server received message %d\n", idx);
		if (args.req_msg->msgh_bits & MACH_MSGH_BITS_COMPLEX) {
			ret = vm_deallocate(mach_task_self(),  
					(vm_address_t)((ipc_complex_message *)args.req_msg)->descriptor.address,  
					((ipc_complex_message *)args.req_msg)->descriptor.size);
		}

		if (1 == args.req_msg->msgh_id) {
			if (verbose) 
				printf("server sending reply %d\n", idx);
			args.reply_msg->msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND,  
					MACH_MSG_TYPE_MAKE_SEND);
			args.reply_msg->msgh_size = args.reply_size;
			args.reply_msg->msgh_remote_port = args.req_msg->msgh_remote_port;
			args.reply_msg->msgh_local_port = args.req_msg->msgh_local_port;
			args.reply_msg->msgh_id = 2;
			ret = mach_msg(args.reply_msg, 
					MACH_SEND_MSG, 
					args.reply_size, 
					0, 
					MACH_PORT_NULL, 
					MACH_MSG_TIMEOUT_NONE,  
					MACH_PORT_NULL);
			if (MACH_MSG_SUCCESS != ret) {
				mach_error("mach_msg (send): ", ret);
				exit(1);
			}
		}
	}
}
Example #7
0
/*
 * debugger will register kevents, attach+kill child, wait for quorum on events,
 * then exit.
 */
void do_debugger(pid_t child, debugger_exit_t debugger_exit_time)
{
    int kq;
    int ret;
    struct kevent64_s kev;
    int deathcount = 0;
    int stat_loc;

    setprogname("DEBUGGER");

    logline("debugger pid %d has child pid %d. waiting for process exit...", getpid(), child);

    sleep(1);
    fprintf(stderr, "\n");
    ret = ptrace(PT_ATTACH, child, 0, 0);
    if (ret == -1)
        err(1, "ptrace(PT_ATTACH)");

    ret = waitpid(child, &stat_loc, WUNTRACED);
    if (ret == -1)
        err(1, "waitpid(child, WUNTRACED)");

    logline("child process stopped: %s", print_exit(child, stat_loc));

    if (debugger_exit_time == eDebuggerExitWithoutDetach) {
        logline("exiting because of eDebuggerExitWithoutDetach");
        exit(0);
    } else if (debugger_exit_time == eDebuggerExitAfterDetach) {
        ret = ptrace(PT_DETACH, child, 0, 0);
        if (ret == -1)
            err(1, "ptrace(PT_DETACH)");

        ret = kill(child, SIGKILL);
        if (ret == -1)
            err(1, "kill(SIGKILL)");

        logline("exiting because of eDebuggerExitAfterDetach");
        exit(0);
    }

    kq = kqueue();
    if (kq < 0)
        err(1, "kqueue");

    EV_SET64(&kev, child, EVFILT_PROC, EV_ADD|EV_ENABLE,
             NOTE_EXIT|NOTE_EXITSTATUS|NOTE_EXIT_DETAIL|NOTE_FORK|NOTE_EXEC|NOTE_SIGNAL,
             0, child, 0, 0);
    ret = kevent64(kq, &kev, 1, NULL, 0, 0, NULL);
    if (ret == -1)
        err(1, "kevent64 EVFILT_PROC");

    EV_SET64(&kev, SIGCHLD, EVFILT_SIGNAL, EV_ADD|EV_ENABLE,
             0, 0, child, 0, 0);
    ret = kevent64(kq, &kev, 1, NULL, 0, 0, NULL);
    if (ret == -1)
        err(1, "kevent64 EVFILT_SIGNAL");

    sleep(1);
    fprintf(stderr, "\n");
    ret = ptrace(PT_KILL, child, 0, 0);
    if (ret == -1)
        err(1, "ptrace(PT_KILL)");

    while(1) {
        ret = kevent64(kq, NULL, 0, &kev, 1, 0, NULL);
        if (ret == -1) {
            if (errno == EINTR)
                continue;
            err(1, "kevent64");
        } else if (ret == 0) {
            continue;
        }

        logline("kevent64 returned ident %llu filter %s fflags %s data %s",
                kev.ident, str_kev_filter(kev.filter),
                str_kev_fflags(kev.filter, kev.fflags),
                str_kev_data(kev.filter, kev.fflags, kev.data, kev.udata));
        if (kev.filter == EVFILT_SIGNAL) {
            /* must be SIGCHLD */
            deathcount++;
        } else if (kev.filter == EVFILT_PROC) {
            if ((kev.fflags & (NOTE_EXIT|NOTE_EXITSTATUS)) == (NOTE_EXIT|NOTE_EXITSTATUS)) {
                deathcount++;
            }
        }

        if (deathcount >= 2) {
            break;
        }
    }

    if (debugger_exit_time == eDebuggerExitAfterKillWithoutWaitpid) {
        logline("exiting because of eDebuggerExitAfterKillWithoutWaitpid");
        exit(0);
    }

    sleep(1);
    fprintf(stderr, "\n");
    ret = waitpid(child, &stat_loc, 0);
    if (ret == -1)
        err(1, "waitpid(%d) by debugger failed", child);

    logline("child process: %s", print_exit(child, stat_loc));

    /* Received both SIGCHLD and NOTE_EXIT */
    exit(0);
}
Example #8
0
/*
 * debugger will register kevents, wait for quorum on events, then exit
 */
void do_parent(pid_t child, pid_t debugger, parent_exit_t parent_exit_time, debugger_exit_t debugger_exit_time)
{
    int kq;
    int ret;
    struct kevent64_s kev;
    int deathcount = 0;
    int childsignalcount = 0;
    int stat_loc;

    setprogname("PARENT");

    logline("parent pid %d has child pid %d and debugger pid %d. waiting for processes to exit...", getpid(), child, debugger);

    kq = kqueue();
    if (kq < 0)
        err(1, "kqueue");

    EV_SET64(&kev, child, EVFILT_PROC, EV_ADD|EV_ENABLE,
             NOTE_EXIT|NOTE_EXITSTATUS|NOTE_EXIT_DETAIL|NOTE_FORK|NOTE_EXEC|NOTE_SIGNAL,
             0, child, 0, 0);
    ret = kevent64(kq, &kev, 1, NULL, 0, 0, NULL);
    if (ret == -1)
        err(1, "kevent64 EVFILT_PROC");

    EV_SET64(&kev, SIGCHLD, EVFILT_SIGNAL, EV_ADD|EV_ENABLE,
             0, 0, child, 0, 0);
    ret = kevent64(kq, &kev, 1, NULL, 0, 0, NULL);
    if (ret == -1)
        err(1, "kevent64 EVFILT_SIGNAL");

    EV_SET64(&kev, 7, EVFILT_TIMER, EV_ADD|EV_ENABLE|EV_ONESHOT,
             NOTE_SECONDS, 7, 0, 0, 0);
    ret = kevent64(kq, &kev, 1, NULL, 0, 0, NULL);
    if (ret == -1)
        err(1, "kevent64 EVFILT_TIMER");

    while(1) {
        ret = kevent64(kq, NULL, 0, &kev, 1, 0, NULL);
        if (ret == -1) {
            if (errno == EINTR)
                continue;
            err(1, "kevent64");
        } else if (ret == 0) {
            break;
        }

        logline("kevent64 returned ident %llu filter %s fflags %s data %s",
                kev.ident, str_kev_filter(kev.filter),
                str_kev_fflags(kev.filter, kev.fflags),
                str_kev_data(kev.filter, kev.fflags, kev.data, kev.udata));
        if (kev.filter == EVFILT_SIGNAL) {
            /* must be SIGCHLD */
            deathcount++;
        } else if (kev.filter == EVFILT_PROC) {
            if (child == kev.udata) {
                if ((kev.fflags & (NOTE_EXIT|NOTE_EXITSTATUS)) == (NOTE_EXIT|NOTE_EXITSTATUS)) {
                    deathcount++;
                } else if (kev.fflags & NOTE_SIGNAL) {
                    childsignalcount++;
                    if ((parent_exit_time == eParentExitAfterDebuggerAttach) && (childsignalcount >= 2)) {
                        /* second signal is attach */
                        logline("exiting because of eParentExitAfterDebuggerAttach");
                        exit(0);
                    }
                } else if (kev.fflags & NOTE_FORK) {
                    if (parent_exit_time == eParentExitBeforeDebuggerAttach) {
                        logline("exiting because of eParentExitBeforeDebuggerAttach");
                        exit(0);
                    }
                }
            }
        } else if (kev.filter == EVFILT_TIMER) {
            errx(1, "timed out waiting for NOTE_EXIT");
        }

        if (deathcount >= (parent_exit_time == eParentExitAfterWaitpidAndSIGCHLD ? 2 : 1)) {
            break;
        }
    }

    if (parent_exit_time == eParentExitBeforeWaitpid) {
        logline("exiting because of eParentExitBeforeWaitpid");
        exit(0);
    }

    ret = waitpid(child, &stat_loc, 0);
    if (ret == -1)
        err(1, "waitpid(%d) by parent failed", child);

    logline("child process: %s", print_exit(child, stat_loc));
    if (!WIFSIGNALED(stat_loc) || (SIGKILL != WTERMSIG(stat_loc)))
        errx(1, "child did not exit as expected");

    ret = waitpid(debugger, &stat_loc, 0);
    if (ret == -1)
        err(1, "waitpid(%d) by parent failed", debugger);

    logline("debugger process: %s", print_exit(debugger, stat_loc));
    if (!WIFEXITED(stat_loc) || (0 != WEXITSTATUS(stat_loc)))
        errx(1, "debugger did not exit as expected");

    /* Received both SIGCHLD and NOTE_EXIT, as needed */
    logline("exiting beacuse of eParentExitAfterWaitpid/eParentExitAfterWaitpidAndSIGCHLD");
    exit(0);
}
Example #9
0
void do_grandparent(pid_t parent, pid_t child, pid_t debugger, debugger_exit_t debugger_exit_time)
{
    pid_t result;
    int stat_loc;
    int exit_code = 0;
    int kq;
    int ret;
    struct kevent64_s kev;
    int neededdeathcount = (debugger != -1) ? 3 : 2;

    setprogname("GRANDPARENT");

    logline("grandparent pid %d has parent pid %d and child pid %d. waiting for parent process exit...", getpid(), parent, child);

    /* make sure we can at least observe real child's exit */
    kq = kqueue();
    if (kq < 0)
        err(1, "kqueue");

    EV_SET64(&kev, child, EVFILT_PROC, EV_ADD|EV_ENABLE,
             NOTE_EXIT, 0, child, 0, 0);
    ret = kevent64(kq, &kev, 1, NULL, 0, 0, NULL);
    if (ret == -1)
        err(1, "kevent64 EVFILT_PROC");

    EV_SET64(&kev, parent, EVFILT_PROC, EV_ADD|EV_ENABLE,
             NOTE_EXIT, 0, parent, 0, 0);
    ret = kevent64(kq, &kev, 1, NULL, 0, 0, NULL);
    if (ret == -1)
        err(1, "kevent64 EVFILT_PROC");

    if (debugger != -1) {
        EV_SET64(&kev, debugger, EVFILT_PROC, EV_ADD|EV_ENABLE,
                 NOTE_EXIT, 0, debugger, 0, 0);
        ret = kevent64(kq, &kev, 1, NULL, 0, 0, NULL);
        if (ret == -1)
            err(1, "kevent64 EVFILT_PROC");
    }

    EV_SET64(&kev, 5, EVFILT_TIMER, EV_ADD|EV_ENABLE|EV_ONESHOT,
             NOTE_SECONDS, 5, 0, 0, 0);
    ret = kevent64(kq, &kev, 1, NULL, 0, 0, NULL);
    if (ret == -1)
        err(1, "kevent64 EVFILT_TIMER");

    while(1) {

        ret = kevent64(kq, NULL, 0, &kev, 1, 0, NULL);
        if (ret == -1) {
            if (errno == EINTR)
                continue;
            err(1, "kevent64");
        } else if (ret == 0) {
            break;
        }

        logline("kevent64 returned ident %llu filter %s fflags %s data %s",
                kev.ident, str_kev_filter(kev.filter),
                str_kev_fflags(kev.filter, kev.fflags),
                str_kev_data(kev.filter, kev.fflags, kev.data, kev.udata));
        if (kev.filter == EVFILT_PROC) {
            if (child == kev.udata) {
                neededdeathcount--;
            } else if (parent == kev.udata) {
                neededdeathcount--;
            } else if ((debugger != -1) && (debugger == kev.udata)) {
                neededdeathcount--;
            }
        } else if (kev.filter == EVFILT_TIMER) {
            logline("timed out waiting for NOTE_EXIT");
            exit_code = 1;
            break;
        }

        if (neededdeathcount == 0) {
            break;
        }
    }

    result = waitpid(parent, &stat_loc, 0);
    if (result == -1)
        err(1, "waitpid(%d) by grandparent failed", parent);


    logline("parent process: %s", print_exit(parent, stat_loc));
    if (!WIFEXITED(stat_loc) || (0 != WEXITSTATUS(stat_loc))) {
        exit_code = 1;
    }

    if (iszombie(parent)) {
        logline("parent %d is now a zombie", parent);
        exit_code = 1;
    }

    if (iszombie(child)) {
        logline("child %d is now a zombie", child);
        exit_code = 1;
    }

    if ((debugger != -1) && iszombie(debugger)) {
        logline("debugger %d is now a zombie", debugger);
        exit_code = 1;
    }

    exit(exit_code);
}