Beispiel #1
2
/*
 * Parameterized test function bodies
 */
void
test_eagain(size_t sndbufsize, size_t rcvbufsize)
{
	int i;
	int sv[2];
	const size_t totalsize = (sndbufsize + rcvbufsize) * 2;
	const size_t pktsize = MIN(sndbufsize, rcvbufsize) / 4;
	char sndbuf[pktsize];
	char recv_buf[pktsize];
	ssize_t ssize, rsize;

	/* setup the socket pair */
	do_socketpair_nonblocking(sv);
	/* Setup the buffers */
	ATF_REQUIRE_EQ(0, setsockopt(sv[0], SOL_SOCKET, SO_SNDBUF, &sndbufsize,
	    sizeof(sndbufsize)));
	ATF_REQUIRE_EQ(0, setsockopt(sv[1], SOL_SOCKET, SO_RCVBUF, &rcvbufsize,
	    sizeof(rcvbufsize)));

	bzero(sndbuf, pktsize);
	/* Send data until we get EAGAIN */
	for(i=0; i < totalsize / pktsize; i++) {
		ssize = send(sv[0], sndbuf, pktsize, MSG_EOR);
		if (ssize == -1) {
			if (errno == EAGAIN)
				atf_tc_pass();
			else {
				perror("send");
				atf_tc_fail("send returned < 0 but not EAGAIN");
			}
		}
	}
	atf_tc_fail("Never got EAGAIN");
}
Beispiel #2
2
static void
h_check(int test)
{
	struct sigaction sa;
	jmp_buf jb;
	sigjmp_buf sjb;
	sigset_t ss;
	int i, x;

	myself = pthread_self();
	i = getpid();

	if (test == TEST_SETJMP || test == TEST_SIGSETJMP_SAVE)
		expectsignal = 0;
	else if (test == TEST_U_SETJMP || test == TEST_SIGSETJMP_NOSAVE)
		expectsignal = 1;
	else
		atf_tc_fail("unknown test");

	sa.sa_handler = aborthandler;
	sigemptyset(&sa.sa_mask);
	sa.sa_flags = 0;
	REQUIRE_ERRNO(sigaction(SIGABRT, &sa, NULL) != -1);
	REQUIRE_ERRNO(sigemptyset(&ss) != -1);
	REQUIRE_ERRNO(sigaddset(&ss, SIGABRT) != -1);
	REQUIRE_ERRNO(sigprocmask(SIG_BLOCK, &ss, NULL) != -1);
	ATF_REQUIRE(myself == pthread_self());

	if (test == TEST_SETJMP)
		x = setjmp(jb);
	else if (test == TEST_U_SETJMP)
		x = _setjmp(jb);
	else 
		x = sigsetjmp(sjb, !expectsignal);

	if (x != 0) {
		ATF_REQUIRE(myself == pthread_self());
		ATF_REQUIRE_MSG(x == i, "setjmp returned wrong value");
		kill(i, SIGABRT);
		ATF_REQUIRE_MSG(!expectsignal, "kill(SIGABRT) failed");
		ATF_REQUIRE(myself == pthread_self());
		atf_tc_pass();
	}

	ATF_REQUIRE(myself == pthread_self());
	REQUIRE_ERRNO(sigprocmask(SIG_UNBLOCK, &ss, NULL) != -1);

	if (test == TEST_SETJMP)
		longjmp(jb, i);
	else if (test == TEST_U_SETJMP)
		_longjmp(jb, i);
	else 
		siglongjmp(sjb, i);

	atf_tc_fail("jmp failed");
}
Beispiel #3
1
static void
aborthandler(int signo __unused)
{
	ATF_REQUIRE(myself == pthread_self());
	ATF_REQUIRE_MSG(expectsignal, "kill(SIGABRT) succeeded");
	atf_tc_pass();
}
Beispiel #4
0
static void
callback(const char *file, int line, isc_assertiontype_t type,
	 const char *cond)
{
	UNUSED(file); UNUSED(line); UNUSED(type); UNUSED(cond);
	if (strcmp(tempname, "dtXXXXXXXX"))
		unlink(tempname);
	atf_tc_pass();
	exit(0);
}
Beispiel #5
0
static void
sigalrm_action(int signo, siginfo_t *info, void *ptr)
{

	sig_debug(signo, info, (ucontext_t *)ptr);

	ATF_REQUIRE_EQ(info->si_signo, SIGALRM);
	ATF_REQUIRE_EQ(info->si_code, SI_TIMER);
	ATF_REQUIRE_EQ(info->si_value.sival_int, ITIMER_REAL);

	atf_tc_pass();
	/* NOTREACHED */
}
Beispiel #6
0
static void
sigsegv_action(int signo, siginfo_t *info, void *ptr)
{

	sig_debug(signo, info, (ucontext_t *)ptr);

	ATF_REQUIRE_EQ(info->si_signo, SIGSEGV);
	ATF_REQUIRE_EQ(info->si_errno, 0);
	ATF_REQUIRE_EQ(info->si_code, SEGV_MAPERR);
	ATF_REQUIRE_EQ(info->si_addr, (void *)0);

	atf_tc_pass();
	/* NOTREACHED */
}
Beispiel #7
0
static void
sigbus_action(int signo, siginfo_t *info, void *ptr)
{

	printf("si_addr = %p\n", info->si_addr);
	sig_debug(signo, info, (ucontext_t *)ptr);

	ATF_REQUIRE_EQ(info->si_signo, SIGBUS);
	ATF_REQUIRE_EQ(info->si_errno, 0);
	ATF_REQUIRE_EQ(info->si_code, BUS_ADRALN);

	if (strcmp(atf_config_get("atf_arch"), "i386") == 0 ||
	    strcmp(atf_config_get("atf_arch"), "x86_64") == 0) {
		atf_tc_expect_fail("x86 architecture does not correctly "
		    "report the address where the unaligned access occured");
	}
	ATF_REQUIRE_EQ(info->si_addr, (volatile void *)addr);

	atf_tc_pass();
	/* NOTREACHED */
}
Beispiel #8
0
ATF_TC_BODY(deadlock, tc)
{
	int fd;
	int error;
	int ret;
	pid_t pid;

	(void)unlink(lockfile);

	fd = open (lockfile, O_RDWR|O_CREAT|O_EXCL|O_TRUNC, 0666);
	ATF_REQUIRE_MSG(fd >= 0, "open(%s): %s", lockfile, strerror(errno));

	ATF_REQUIRE_MSG(ftruncate(fd, filesize) >= 0,
	    "ftruncate(%s): %s", lockfile, strerror(errno));

	fsync(fd);

	error = dolock(fd, F_LOCK, 0, 1);
	ATF_REQUIRE_MSG(error == 0, "initial dolock: %s", strerror(errno));

	pid = fork();
	ATF_REQUIRE_MSG(pid != -1, "fork failed: %s", strerror(errno));
	if (pid == 0) {
		error = dolock(fd, F_LOCK, 1, 1);
		ATF_REQUIRE_MSG(error == 0, "child dolock: %s",
		    strerror(errno));
		dolock(fd, F_LOCK, 0, 1);	/* will block */
		atf_tc_fail("child did not block");
	}
	sleep(1);	/* give child time to grab its lock then block */

	error = dolock(fd, F_LOCK, 1, 1);
	ATF_REQUIRE_MSG(error == EDEADLK, "parent did not detect deadlock: %s",
	    strerror(errno));
	ret = kill(pid, SIGKILL);
	ATF_REQUIRE_MSG(ret != -1, "failed to kill child: %s", strerror(errno));

	atf_tc_pass();
}
Beispiel #9
0
ATF_TC_BODY(buffer_allocate, tc) {
    struct buffer *buf = 0;

    /*
     * Check a 0-length buffer.
     */
    buf = NULL;
    if (!buffer_allocate(&buf, 0, MDL)) {
        atf_tc_fail("failed on 0-len buffer");
    }
    if (!buffer_dereference(&buf, MDL)) {
        atf_tc_fail("buffer_dereference() failed");
    }
    if (buf != NULL) {
        atf_tc_fail("buffer_dereference() did not NULL-out buffer");
    }

    /*
     * Check an actual buffer.
     */
    buf = NULL;
    if (!buffer_allocate(&buf, 100, MDL)) {
        atf_tc_fail("failed on allocate 100 bytes\n");
    }
    if (!buffer_dereference(&buf, MDL)) {
        atf_tc_fail("buffer_dereference() failed");
    }
    if (buf != NULL) {
        atf_tc_fail("buffer_dereference() did not NULL-out buffer");
    }

    /*
     * Okay, we're happy.
     */
    atf_tc_pass();
}
Beispiel #10
0
ATF_TC_BODY(randlock, tc)
{
	int i, j, fd;
	int pipe_fd[2];
	pid_t *pid;
	int status;
	char pipe_in, pipe_out;
	const char pipe_errmsg[] = "child: pipe write failed\n";

	(void)unlink(lockfile);

	fd = open (lockfile, O_RDWR|O_CREAT|O_EXCL|O_TRUNC, 0666);
	ATF_REQUIRE_MSG(fd >= 0, "open(%s): %s", lockfile, strerror(errno));

	ATF_REQUIRE_MSG(ftruncate(fd, filesize) >= 0,
	    "ftruncate(%s): %s", lockfile, strerror(errno));

	ATF_REQUIRE_MSG(pipe(pipe_fd) == 0, "pipe: %s", strerror(errno));

	fsync(fd);
	close(fd);

	pid = malloc(nprocs * sizeof(pid_t));
	
	for (i = 0; i < nprocs; i++) {
		pipe_out = (char)('A' + i);
		pid[i] = fork();
		switch (pid[i]) {
		case 0:
			if (write(pipe_fd[1], &pipe_out, 1) != 1)
				write(STDERR_FILENO, pipe_errmsg,
				    __arraycount(pipe_errmsg) - 1);
			else
				trylocks(i);
			_exit(0);
			break;
		case -1:
			atf_tc_fail("fork %d failed", i);
			break;
		default:
			ATF_REQUIRE_MSG(read(pipe_fd[0], &pipe_in, 1) == 1,
			    "parent: read_pipe(%i): %s", i, strerror(errno));
			ATF_REQUIRE_MSG(pipe_in == pipe_out,
			    "parent: pipe does not match");
			break;
		}
	}
	for (j = 0; j < npasses; j++) {
		printf("parent: run %i\n", j+1);
		for (i = 0; i < nprocs; i++) {
			ATF_REQUIRE_MSG(ptrace(PT_ATTACH, pid[i], 0, 0) >= 0,
			    "ptrace attach %d", pid[i]);
			ATF_REQUIRE_MSG(waitpid(pid[i], &status, WUNTRACED) >= 0,
			    "waitpid(ptrace)");
			usleep(sleeptime / 3);
			ATF_REQUIRE_MSG(ptrace(PT_DETACH, pid[i], (caddr_t)1,
					       0) >= 0,
			    "ptrace detach %d", pid[i]);
			usleep(sleeptime / 3);
		}
	}
	for (i = 0; i < nprocs; i++) {
		printf("reap %d: ", i);
		fflush(stdout);
		kill(pid[i], SIGINT);
		waitpid(pid[i], &status, 0);
		printf(" status %d\n", status);
	}
	atf_tc_pass();
}
Beispiel #11
0
ATF_TC_BODY(pass, tc)
{
    atf_tc_pass();
}
Beispiel #12
0
ATF_TC_BODY(msg, tc)
{
    struct sigaction sa;
    struct msqid_ds m_ds;
    struct mymsg m;
    sigset_t sigmask;
    int loop;
    int c_status;

    /*
     * Install a SIGSYS handler so that we can exit gracefully if
     * System V Message Queue support isn't in the kernel.
     */
    did_sigsys = 0;
    sa.sa_handler = sigsys_handler;
    sigemptyset(&sa.sa_mask);
    sa.sa_flags = 0;
    ATF_REQUIRE_MSG(sigaction(SIGSYS, &sa, NULL) != -1,
                    "sigaction SIGSYS: %d", errno);

    /*
     * Install a SIGCHLD handler to deal with all possible exit
     * conditions of the receiver.
     */
    did_sigchild = 0;
    child_count = 0;
    sa.sa_handler = sigchld_handler;
    sigemptyset(&sa.sa_mask);
    sa.sa_flags = 0;
    ATF_REQUIRE_MSG(sigaction(SIGCHLD, &sa, NULL) != -1,
                    "sigaction SIGCHLD: %d", errno);

    msgkey = get_ftok(4160);
    ATF_REQUIRE_MSG(msgkey != (key_t)-1, "get_ftok failed");

    sender_msqid = msgget(msgkey, IPC_CREAT | 0640);
    ATF_REQUIRE_MSG(sender_msqid != -1, "msgget: %d", errno);

    if (did_sigsys) {
        atf_tc_skip("SYSV Message Queue not supported");
        return;
    }

    ATF_REQUIRE_MSG(msgctl(sender_msqid, IPC_STAT, &m_ds) != -1,
                    "msgctl IPC_STAT 1: %d", errno);

    print_msqid_ds(&m_ds, 0640);

    m_ds.msg_perm.mode = (m_ds.msg_perm.mode & ~0777) | 0600;

    ATF_REQUIRE_MSG(msgctl(sender_msqid, IPC_SET, &m_ds) != -1,
                    "msgctl IPC_SET: %d", errno);

    memset(&m_ds, 0, sizeof(m_ds));

    ATF_REQUIRE_MSG(msgctl(sender_msqid, IPC_STAT, &m_ds) != -1,
                    "msgctl IPC_STAT 2: %d", errno);

    ATF_REQUIRE_MSG((m_ds.msg_perm.mode & 0777) == 0600,
                    "IPC_SET of mode didn't hold");

    print_msqid_ds(&m_ds, 0600);

    switch ((child_pid = fork())) {
    case -1:
        atf_tc_fail("fork: %d", errno);
        return;

    case 0:
        child_count++;
        receiver();
        break;

    default:
        break;
    }

    for (loop = 0; loop < maxloop; loop++) {
        /*
         * Send the first message to the receiver and wait for the ACK.
         */
        m.mtype = MTYPE_1;
        strcpy(m.mtext, m1_str);
        ATF_REQUIRE_MSG(msgsnd(sender_msqid, &m, sizeof(m), 0) != -1,
                        "sender: msgsnd 1: %d", errno);

        ATF_REQUIRE_MSG(msgrcv(sender_msqid, &m, sizeof(m),
                               MTYPE_1_ACK, 0) == sizeof(m),
                        "sender: msgrcv 1 ack: %d", errno);

        print_msqid_ds(&m_ds, 0600);

        /*
         * Send the second message to the receiver and wait for the ACK.
         */
        m.mtype = MTYPE_2;
        strcpy(m.mtext, m2_str);
        ATF_REQUIRE_MSG(msgsnd(sender_msqid, &m, sizeof(m), 0) != -1,
                        "sender: msgsnd 2: %d", errno);

        ATF_REQUIRE_MSG(msgrcv(sender_msqid, &m, sizeof(m),
                               MTYPE_2_ACK, 0) == sizeof(m),
                        "sender: msgrcv 2 ack: %d", errno);
    }

    /*
     * Wait for child to finish
     */
    sigemptyset(&sigmask);
    (void) sigsuspend(&sigmask);

    /*
     * ...and any other signal is an unexpected error.
     */
    if (did_sigchild) {
        c_status = child_status;
        if (c_status < 0)
            atf_tc_fail("waitpid: %d", -c_status);
        else if (WIFEXITED(c_status) == 0)
            atf_tc_fail("child abnormal exit: %d", c_status);
        else if (WEXITSTATUS(c_status) != 0)
            atf_tc_fail("c status: %d", WEXITSTATUS(c_status));
        else {
            ATF_REQUIRE_MSG(msgctl(sender_msqid, IPC_STAT, &m_ds)
                            != -1, "msgctl IPC_STAT: %d", errno);

            print_msqid_ds(&m_ds, 0600);
            atf_tc_pass();
        }
    } else
        atf_tc_fail("sender: received unexpected signal");
}
Beispiel #13
0
int
sleeptest(int (*test)(struct timespec *, struct timespec *),
	   bool subsec, bool sim_remain)
{
	struct timespec tsa, tsb, tslp, tremain;
	int64_t delta1, delta2, delta3, round;

	sig = 0;
	signal(SIGALRM, sigalrm);

	if (subsec) {
		round = 1;
		delta3 = FUZZ;
	} else {
		round = 1000000000;
		delta3 = round;
	}

	tslp.tv_sec = delta3 / 1000000000;
	tslp.tv_nsec = delta3 % 1000000000;

	while (tslp.tv_sec <= MAXSLEEP) {
		/*
		 * disturb sleep by signal on purpose
		 */ 
		if (tslp.tv_sec > ALARM && sig == 0)
			alarm(ALARM);

		clock_gettime(CLOCK_REALTIME, &tsa);
		(*test)(&tslp, &tremain);
		clock_gettime(CLOCK_REALTIME, &tsb);

		if (sim_remain) {
			timespecsub(&tsb, &tsa, &tremain);
			timespecsub(&tslp, &tremain, &tremain);
		}

		delta1 = (int64_t)tsb.tv_sec - (int64_t)tsa.tv_sec;
		delta1 *= BILLION;
		delta1 += (int64_t)tsb.tv_nsec - (int64_t)tsa.tv_nsec;

		delta2 = (int64_t)tremain.tv_sec * BILLION;
		delta2 += (int64_t)tremain.tv_nsec;

		delta3 = (int64_t)tslp.tv_sec * BILLION;
		delta3 += (int64_t)tslp.tv_nsec - delta1 - delta2;

		delta3 /= round;
		delta3 *= round;

		if (delta3 > FUZZ || delta3 < -FUZZ) {
			if (!sim_remain)
				atf_tc_expect_fail("Long reschedule latency "
				    "due to PR kern/43997");

			atf_tc_fail("Reschedule latency %"PRId64" exceeds "
			    "allowable fuzz %lld", delta3, FUZZ);
		}
		delta3 = (int64_t)tslp.tv_sec * 2 * BILLION;
		delta3 += (int64_t)tslp.tv_nsec * 2;

		delta3 /= round;
		delta3 *= round;
		if (delta3 < FUZZ)
			break;
		tslp.tv_sec = delta3 / BILLION;
		tslp.tv_nsec = delta3 % BILLION;
	}
	ATF_REQUIRE_MSG(sig == 1, "Alarm did not fire!");

	atf_tc_pass();
}
Beispiel #14
0
ATF_TC_BODY(shm, tc)
{
	struct sigaction sa;
	struct shmid_ds s_ds;
	sigset_t sigmask;
	char *shm_buf;
	int sender_shmid;
	int c_status;

	/*
	 * Install a SIGSYS handler so that we can exit gracefully if
	 * System V Shared Memory support isn't in the kernel.
	 */
	did_sigsys = 0;
	sa.sa_handler = sigsys_handler;
	sigemptyset(&sa.sa_mask);
	sa.sa_flags = 0;
	ATF_REQUIRE_MSG(sigaction(SIGSYS, &sa, NULL) != -1,
	    "sigaction SIGSYS: %d", errno);

	/*
	 * Install a SIGCHLD handler to deal with all possible exit
	 * conditions of the sharer.
	 */
	did_sigchild = 0;
	child_count = 0;
	sa.sa_handler = sigchld_handler;
	sigemptyset(&sa.sa_mask);
	sa.sa_flags = 0;
	ATF_REQUIRE_MSG(sigaction(SIGCHLD, &sa, NULL) != -1,
	    "sigaction SIGCHLD: %d", errno);

	pgsize = sysconf(_SC_PAGESIZE);

	shmkey = get_ftok(4160);
	ATF_REQUIRE_MSG(shmkey != (key_t)-1, "get_ftok failed");

	ATF_REQUIRE_MSG((sender_shmid = shmget(shmkey, pgsize,
					       IPC_CREAT | 0640)) != -1,
	    "shmget: %d", errno);
	write_int("sender_shmid", sender_shmid);

	ATF_REQUIRE_MSG(shmctl(sender_shmid, IPC_STAT, &s_ds) != -1,
	    "shmctl IPC_STAT: %d", errno);

	print_shmid_ds(&s_ds, 0640);

	s_ds.shm_perm.mode = (s_ds.shm_perm.mode & ~0777) | 0600;

	ATF_REQUIRE_MSG(shmctl(sender_shmid, IPC_SET, &s_ds) != -1,
	    "shmctl IPC_SET: %d", errno);

	memset(&s_ds, 0, sizeof(s_ds));

	ATF_REQUIRE_MSG(shmctl(sender_shmid, IPC_STAT, &s_ds) != -1,
	    "shmctl IPC_STAT: %d", errno);

	ATF_REQUIRE_MSG((s_ds.shm_perm.mode & 0777) == 0600,
	    "IPC_SET of mode didn't hold");

	print_shmid_ds(&s_ds, 0600);

	shm_buf = shmat(sender_shmid, NULL, 0);
	ATF_REQUIRE_MSG(shm_buf != (void *) -1, "sender: shmat: %d", errno);

	/*
	 * Write the test pattern into the shared memory buffer.
	 */
	strcpy(shm_buf, m2_str);

	switch ((child_pid = fork())) {
	case -1:
		atf_tc_fail("fork: %d", errno);
		return;

	case 0:
		sharer();
		break;

	default:
		break;
	}

	/*
	 * Wait for child to finish
	 */
	sigemptyset(&sigmask);
	(void) sigsuspend(&sigmask);

	if (did_sigchild) {
		c_status = child_status;
		if (c_status < 0)
			atf_tc_fail("waitpid: %d", -c_status);
		else if (WIFEXITED(c_status) == 0)
			atf_tc_fail("c abnormal exit: %d", c_status);
		else if (WEXITSTATUS(c_status) != 0)
			atf_tc_fail("c status: %d", WEXITSTATUS(c_status));
		else {
			ATF_REQUIRE_MSG(shmctl(sender_shmid, IPC_STAT,
					       &s_ds) != -1,
			    "shmctl IPC_STAT: %d", errno);

			print_shmid_ds(&s_ds, 0600);
			atf_tc_pass();
		}
	} else
		atf_tc_fail("sender: received unexpected signal");
}
Beispiel #15
0
ATF_TC_BODY(sem, tc)
{
	struct sigaction sa;
	union semun sun;
	struct semid_ds s_ds;
	sigset_t sigmask;
	int sender_semid;
	int i;
	int c_status;

	/*
	 * Install a SIGSYS handler so that we can exit gracefully if
	 * System V Semaphore support isn't in the kernel.
	 */
	did_sigsys = 0;
	sa.sa_handler = sigsys_handler;
	sigemptyset(&sa.sa_mask);
	sa.sa_flags = 0;
	ATF_REQUIRE_MSG(sigaction(SIGSYS, &sa, NULL) != -1,
	    "sigaction SIGSYS: %d", errno);

	/*
	 * Install a SIGCHLD handler to deal with all possible exit
	 * conditions of the receiver.
	 */
	did_sigchild = 0;
	child_count = 0;
	sa.sa_handler = sigchld_handler;
	sigemptyset(&sa.sa_mask);
	sa.sa_flags = 0;
	ATF_REQUIRE_MSG(sigaction(SIGCHLD, &sa, NULL) != -1,
	    "sigaction SIGCHLD: %d", errno);

	semkey = get_ftok(4160);
	ATF_REQUIRE_MSG(semkey != (key_t)-1, "get_ftok failed");

	sender_semid = semget(semkey, 1, IPC_CREAT | 0640);
	ATF_REQUIRE_MSG(sender_semid != -1, "semget: %d", errno);
	write_int("sender_semid", sender_semid);

	if (did_sigsys) {
		atf_tc_skip("SYSV Semaphore not supported");
		return;
	}
	
	sun.buf = &s_ds;
	ATF_REQUIRE_MSG(semctl(sender_semid, 0, IPC_STAT, sun) != -1,
	    "semctl IPC_STAT: %d", errno);

	print_semid_ds(&s_ds, 0640);

	s_ds.sem_perm.mode = (s_ds.sem_perm.mode & ~0777) | 0600;

	sun.buf = &s_ds;
	ATF_REQUIRE_MSG(semctl(sender_semid, 0, IPC_SET, sun) != -1,
	    "semctl IPC_SET: %d", errno);

	memset(&s_ds, 0, sizeof(s_ds));

	sun.buf = &s_ds;
	ATF_REQUIRE_MSG(semctl(sender_semid, 0, IPC_STAT, sun) != -1,
	    "semctl IPC_STAT: %d", errno);

	ATF_REQUIRE_MSG((s_ds.sem_perm.mode & 0777) == 0600,
	    "IPC_SET of mode didn't hold");

	print_semid_ds(&s_ds, 0600);

	for (child_count = 0; child_count < 5; child_count++) {
		switch ((child_pid = fork())) {
		case -1:
			atf_tc_fail("fork: %d", errno);
			return;

		case 0:
			waiter();
			break;

		default:
			break;
		}
	}

	/*
	 * Wait for all of the waiters to be attempting to acquire the
	 * semaphore.
	 */
	for (;;) {
		i = semctl(sender_semid, 0, GETNCNT);
		if (i == -1)
			atf_tc_fail("semctl GETNCNT: %d", i);
		if (i == 5)
			break;
	}

	/*
	 * Now set the thundering herd in motion by initializing the
	 * semaphore to the value 1.
	 */
	sun.val = 1;
	ATF_REQUIRE_MSG(semctl(sender_semid, 0, SETVAL, sun) != -1,
	    "sender: semctl SETVAL to 1: %d", errno);

	/*
	 * Wait for all children to finish
	 */
	sigemptyset(&sigmask);
	for (;;) {
		(void) sigsuspend(&sigmask);
		if (did_sigchild) {
			c_status = child_status;
			if (c_status < 0)
				atf_tc_fail("waitpid: %d", -c_status);
			else if (WIFEXITED(c_status) == 0)
				atf_tc_fail("c abnormal exit: %d", c_status);
			else if (WEXITSTATUS(c_status) != 0)
				atf_tc_fail("c status: %d",
				    WEXITSTATUS(c_status));
			else {
				sun.buf = &s_ds;
				ATF_REQUIRE_MSG(semctl(sender_semid, 0,
						    IPC_STAT, sun) != -1,
				    "semctl IPC_STAT: %d", errno);

				print_semid_ds(&s_ds, 0600);
				atf_tc_pass();
			}
			if (child_count <= 0)
				break;
			did_sigchild = 0;
		} else {
			atf_tc_fail("sender: received unexpected signal");
			break;
		}
	}
}