diff --git a/test/testcases/posixipc/Makefile b/test/testcases/posixipc/Makefile
index d975781..8408add 100644
--- a/test/testcases/posixipc/Makefile
+++ b/test/testcases/posixipc/Makefile
@@ -1,3 +1,28 @@
+SUBDIR+= close_unnamed_semaphore
+SUBDIR+= create_excl_existing_sem
+SUBDIR+= create_unnamed_semaphore
+SUBDIR+= destroy_named_semaphore
+SUBDIR+= file_test
+SUBDIR+= init_bad_value
+SUBDIR+= max_value
+SUBDIR+= open_after_unlink
+SUBDIR+= open_bad_value
+SUBDIR+= open_extra_flags
+SUBDIR+= open_invalid_path
+SUBDIR+= open_named_semaphore
+SUBDIR+= open_non_existing
+SUBDIR+= open_path_too_long
+SUBDIR+= post_test
 SUBDIR+= sem
+SUBDIR+= timedwait_expired
+SUBDIR+= timedwait_locked
+SUBDIR+= timedwait_unlocked
+SUBDIR+= trywait_locked
+SUBDIR+= trywait_unlocked
+SUBDIR+= unlink_path_too_long
+SUBDIR+= use_after_unlink
+SUBDIR+= wait_locked
+SUBDIR+= wait_two_proc
+SUBDIR+= wait_unlocked
 
 .include <bsd.subdir.mk>
diff --git a/test/testcases/posixipc/close_unnamed_semaphore/Makefile b/test/testcases/posixipc/close_unnamed_semaphore/Makefile
new file mode 100644
index 0000000..75dd9f9
--- /dev/null
+++ b/test/testcases/posixipc/close_unnamed_semaphore/Makefile
@@ -0,0 +1,10 @@
+PROG=	close_unnamed_semaphore
+SRCS=	close_unnamed_semaphore.c common.c
+NO_MAN=
+LDADD=  -lpthread
+
+CFLAGS= -I ${.CURDIR}/../common
+WARNS?=	3
+
+.include <bsd.prog.mk>
+.PATH: ${.CURDIR}/../common
diff --git a/test/testcases/posixipc/close_unnamed_semaphore/close_unnamed_semaphore.c b/test/testcases/posixipc/close_unnamed_semaphore/close_unnamed_semaphore.c
new file mode 100644
index 0000000..67f1d19
--- /dev/null
+++ b/test/testcases/posixipc/close_unnamed_semaphore/close_unnamed_semaphore.c
@@ -0,0 +1,18 @@
+#include <common.h>
+
+int
+main(void) {
+	int retval = 0;
+	sem_t id;
+
+	if (sem_init(&id, 0, 1) < 0) {
+		perror("sem_init");
+		return 1;
+	}
+
+	retval = sem_close_should_fail(&id, EINVAL);
+
+	sem_destroy(&id);
+
+	return retval;
+}
diff --git a/test/testcases/posixipc/common/common.c b/test/testcases/posixipc/common/common.c
new file mode 100644
index 0000000..fc97e6b
--- /dev/null
+++ b/test/testcases/posixipc/common/common.c
@@ -0,0 +1,385 @@
+/*-
+ * Copyright (c) 2008 Yahoo!, Inc.
+ * All rights reserved.
+ * Written by: John Baldwin <jhb@FreeBSD.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the author nor the names of any co-contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+#include <sys/mman.h>
+#include <sys/queue.h>
+#include <sys/sysctl.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/user.h>
+#include <sys/wait.h>
+
+#include <errno.h>
+#include <kvm.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
+#include <time.h>
+
+#include <common.h>
+
+/*
+ * Use a timer to post a specific semaphore after a timeout.  A timer
+ * is scheduled via schedule_post().  check_alarm() must be called
+ * afterwards to clean up and check for errors.
+ */
+sem_t *alarm_id = SEM_FAILED;
+int alarm_errno;
+int alarm_handler_installed;
+
+int
+checkvalue(sem_t *id, int expected)
+{
+	int val;
+
+	if (sem_getvalue(id, &val) < 0) {
+		perror("sem_getvalue");
+		return (-1);
+	}
+	if (val != expected) {
+		fprintf(stderr, "sem value should be %d instead of %d",
+		    expected, val);
+		return (-1);
+	}
+	return (0);
+}
+
+sem_t *
+construct_shared_unnamed_sem(unsigned int count)
+{
+	sem_t *id = mmap(NULL, sizeof(sem_t), PROT_READ|PROT_WRITE,
+			 MAP_SHARED|MAP_ANON, -1, 0);
+	if (id == MAP_FAILED) {
+		perror("mmap");
+		return SEM_FAILED;
+	}
+
+	if (sem_init(id, 1, count) < 0) {
+		perror("sem_init");
+		munmap(id, sizeof(sem_t));
+		return SEM_FAILED;
+	}
+
+	return id;
+}
+
+void
+destruct_shared_unnamed_sem(sem_t *id)
+{
+	if (sem_destroy(id) < 0)
+		perror("sem_destroy");
+
+	if (munmap(id, sizeof(sem_t)) < 0)
+		perror("munmap");
+}
+
+int
+testwait(sem_t *id, u_int *delta)
+{
+	struct timespec start, end;
+
+	if (clock_gettime(CLOCK_REALTIME, &start) < 0) {
+		perror("clock_gettime(CLOCK_REALTIME)");
+		return (-1);
+	}
+	if (sem_wait(id) < 0) {
+		perror("sem_wait");
+		return (-1);
+	}
+	if (clock_gettime(CLOCK_REALTIME, &end) < 0) {
+		perror("clock_gettime(CLOCK_REALTIME)");
+		return (-1);
+	}
+	timespecsub(&end, &start);
+	*delta = end.tv_nsec / 1000000;
+	*delta += end.tv_sec * 1000;
+	return (0);
+}
+
+static void
+alarm_handler(int signo)
+{
+
+	if (sem_post(alarm_id) < 0)
+		alarm_errno = errno;
+}
+
+int
+schedule_post(sem_t *id, u_int msec)
+{
+	struct itimerval it;
+
+	if (!alarm_handler_installed) {
+		if (signal(SIGALRM, alarm_handler) == SIG_ERR) {
+			perror("signal(SIGALRM)");
+			return (-1);
+		}
+		alarm_handler_installed = 1;
+	}
+	if (alarm_id != SEM_FAILED) {
+		fprintf(stderr, "sem_post() already scheduled");
+		return (-1);
+	}
+	alarm_id = id;
+	bzero(&it, sizeof(it));
+	it.it_value.tv_sec = msec / 1000;
+	it.it_value.tv_usec = (msec % 1000) * 1000;
+	if (setitimer(ITIMER_REAL, &it, NULL) < 0) {
+		perror("setitimer");
+		return (-1);
+	}
+	return (0);
+}
+
+int
+check_alarm(int just_clear)
+{
+	struct itimerval it;
+
+	bzero(&it, sizeof(it));
+	if (just_clear) {
+		setitimer(ITIMER_REAL, &it, NULL);
+		alarm_errno = 0;
+		alarm_id = SEM_FAILED;
+		return (0);
+	}
+	if (setitimer(ITIMER_REAL, &it, NULL) < 0) {
+		perror("setitimer");
+		return (-1);
+	}
+	if (alarm_errno != 0 && !just_clear) {
+		errno = alarm_errno;
+		perror("sem_post() (via timeout)");
+		alarm_errno = 0;
+		return (-1);
+	}
+	alarm_id = SEM_FAILED;
+
+	return (0);
+}
+
+/*
+ * Helper routine for tests that use a child process.  This routine
+ * creates a pipe and forks a child process.  The child process runs
+ * the 'func' routine which returns a status integer.  The status
+ * integer gets written over the pipe to the parent and returned in
+ * '*stat'.  If there is an error in pipe(), fork(), or wait() this
+ * returns -1 and fails the test.
+ */
+int
+child_worker(int (*func)(void *arg), void *arg, int *stat)
+{
+	pid_t pid;
+	int pfd[2], cstat;
+
+	if (pipe(pfd) < 0) {
+		perror("pipe");
+		return (-1);
+	}
+
+	pid = fork();
+	switch (pid) {
+	case -1:
+		/* Error. */
+		perror("fork");
+		close(pfd[0]);
+		close(pfd[1]);
+		return (-1);
+	case 0:
+		/* Child. */
+		cstat = func(arg);
+		write(pfd[1], &cstat, sizeof(cstat));
+		exit(0);
+	}
+
+	if (read(pfd[0], stat, sizeof(*stat)) < 0) {
+		perror("read(pipe)");
+		close(pfd[0]);
+		close(pfd[1]);
+		return (-1);
+	}
+	if (waitpid(pid, NULL, 0) < 0) {
+		perror("wait");
+		close(pfd[0]);
+		close(pfd[1]);
+		return (-1);
+	}
+	close(pfd[0]);
+	close(pfd[1]);
+	return (0);
+}
+
+/*
+ * Fork off a child process.  The child will open the semaphore via
+ * the same name.  The child will then block on the semaphore waiting
+ * for the parent to post it.
+ */
+int
+wait_twoproc_child(void *arg)
+{
+	sem_t *id;
+
+	id = sem_open(TEST_PATH, 0, 0, 0);
+	if (id == SEM_FAILED)
+		return (CSTAT(1, errno));
+	if (sem_wait(id) < 0)
+		return (CSTAT(2, errno));
+	if (sem_close(id) < 0)
+		return (CSTAT(3, errno));
+	return (CSTAT(0, 0));
+}
+
+int
+timedwait(sem_t *id, u_int msec, u_int *delta, int error)
+{
+	struct timespec start, end;
+
+	if (clock_gettime(CLOCK_REALTIME, &start) < 0) {
+		perror("clock_gettime(CLOCK_REALTIME)");
+		return (-1);
+	}
+	end.tv_sec = msec / 1000;
+	end.tv_nsec = msec % 1000 * 1000000;
+	timespecadd(&end, &start);
+	if (sem_timedwait(id, &end) < 0) {
+		if (errno != error) {
+			perror("sem_timedwait");
+			return (-1);
+		}
+	} else if (error != 0) {
+		return (-1);
+	}
+	if (clock_gettime(CLOCK_REALTIME, &end) < 0) {
+		perror("clock_gettime(CLOCK_REALTIME)");
+		return (-1);
+	}
+	timespecsub(&end, &start);
+	*delta = end.tv_nsec / 1000000;
+	*delta += end.tv_sec * 1000;
+	return (0);
+}
+
+/*
+ * Attempt a sem_open() that should fail with an expected error of
+ * 'error'.
+ */
+int
+sem_open_should_fail(const char *path, int flags, mode_t mode,
+		     unsigned int value, int error)
+{
+	int retval = 0;
+	sem_t *id;
+
+	id = sem_open(path, flags, mode, value);
+	if (id != SEM_FAILED) {
+		sem_close(id);
+		retval = 1;
+	}
+	if (errno != error) {
+		fprintf(stderr, "sem_open: %s\n", strerror(errno));
+		retval = 1;
+	}
+	return retval;
+}
+
+/*
+ * Attempt a sem_init() that should fail with an expected error of
+ * 'error'.
+ */
+int
+sem_init_should_fail(unsigned int value, int error)
+{
+	sem_t id;
+
+	if (sem_init(&id, 0, value) >= 0) {
+		sem_destroy(&id);
+		return 1;
+	}
+	if (errno != error) {
+		perror("sem_init");
+		return 1;
+	}
+
+	return 0;
+}
+
+/*
+ * Attempt a sem_unlink() that should fail with an expected error of
+ * 'error'.
+ */
+int
+sem_unlink_should_fail(const char *path, int error)
+{
+
+	if (sem_unlink(path) >= 0) {
+		return 1;
+	}
+	if (errno != error) {
+		perror("sem_unlink");
+		return 1;
+	}
+	return 0;
+}
+
+/*
+ * Attempt a sem_destroy() that should fail with an expected error of
+ * 'error'.
+ */
+int
+sem_destroy_should_fail(sem_t *id, int error)
+{
+	if (sem_destroy(id) >= 0) {
+		return 1;
+	}
+	if (errno != error) {
+		perror("sem_destroy");
+		return 1;
+	}
+	return 0;
+}
+
+/*
+ * Attempt a sem_close() that should fail with an expected error of
+ * 'error'.
+ */
+int
+sem_close_should_fail(sem_t *id, int error)
+{
+
+	if (sem_close(id) >= 0) {
+		return 1;
+	}
+	if (errno != error) {
+		perror("sem_close");
+		return 1;
+	}
+	return 0;
+}
diff --git a/test/testcases/posixipc/common/common.h b/test/testcases/posixipc/common/common.h
new file mode 100644
index 0000000..e5c3d37
--- /dev/null
+++ b/test/testcases/posixipc/common/common.h
@@ -0,0 +1,103 @@
+/*-
+ * Copyright (c) 2008 Yahoo!, Inc.
+ * All rights reserved.
+ * Written by: John Baldwin <jhb@FreeBSD.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the author nor the names of any co-contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef _COMMON_H_
+#define _COMMON_H_
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <semaphore.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#define	ELAPSED(elapsed, limit)		(abs((elapsed) - (limit)) < 100)
+
+#define	TEST_PATH	"/posixsem_regression_test"
+
+extern sem_t *alarm_id;
+extern int alarm_errno;
+extern int alarm_handler_installed;
+
+/* Cut and pasted from kernel header, bah! */
+
+/* Operations on timespecs */
+#define	timespecclear(tvp)	((tvp)->tv_sec = (tvp)->tv_nsec = 0)
+#define	timespecisset(tvp)	((tvp)->tv_sec || (tvp)->tv_nsec)
+#define	timespeccmp(tvp, uvp, cmp)					\
+	(((tvp)->tv_sec == (uvp)->tv_sec) ?				\
+	    ((tvp)->tv_nsec cmp (uvp)->tv_nsec) :			\
+	    ((tvp)->tv_sec cmp (uvp)->tv_sec))
+#define timespecadd(vvp, uvp)						\
+	do {								\
+		(vvp)->tv_sec += (uvp)->tv_sec;				\
+		(vvp)->tv_nsec += (uvp)->tv_nsec;			\
+		if ((vvp)->tv_nsec >= 1000000000) {			\
+			(vvp)->tv_sec++;				\
+			(vvp)->tv_nsec -= 1000000000;			\
+		}							\
+	} while (0)
+#define timespecsub(vvp, uvp)						\
+	do {								\
+		(vvp)->tv_sec -= (uvp)->tv_sec;				\
+		(vvp)->tv_nsec -= (uvp)->tv_nsec;			\
+		if ((vvp)->tv_nsec < 0) {				\
+			(vvp)->tv_sec--;				\
+			(vvp)->tv_nsec += 1000000000;			\
+		}							\
+	} while (0)
+
+
+/* Macros for passing child status to parent over a pipe. */
+#define	CSTAT(class, error)		((class) << 16 | (error))
+#define	CSTAT_CLASS(stat)		((stat) >> 16)
+#define	CSTAT_ERROR(stat)		((stat) & 0xffff)
+
+int checkvalue(sem_t *, int);
+sem_t *construct_shared_unnamed_sem(unsigned int);
+void destruct_shared_unnamed_sem(sem_t *);
+int testwait(sem_t *, u_int *);
+int timedwait(sem_t *, u_int, u_int *, int);
+int schedule_post(sem_t *, u_int);
+int check_alarm(int);
+int child_worker(int (*)(void *), void *, int *);
+int wait_twoproc_child(void *);
+int sem_open_should_fail(const char *, int, mode_t, unsigned int, int);
+int sem_init_should_fail(unsigned int, int);
+int sem_unlink_should_fail(const char *, int);
+int sem_destroy_should_fail(sem_t *, int);
+int sem_close_should_fail(sem_t *, int);
+
+#endif
diff --git a/test/testcases/posixipc/create_excl_existing_sem/Makefile b/test/testcases/posixipc/create_excl_existing_sem/Makefile
new file mode 100644
index 0000000..ebe9e17
--- /dev/null
+++ b/test/testcases/posixipc/create_excl_existing_sem/Makefile
@@ -0,0 +1,10 @@
+PROG=	create_excl_existing_sem
+SRCS=	create_excl_existing_sem.c common.c
+NO_MAN=
+LDADD=  -lpthread
+
+CFLAGS= -I ${.CURDIR}/../common
+WARNS?=	3
+
+.include <bsd.prog.mk>
+.PATH: ${.CURDIR}/../common
diff --git a/test/testcases/posixipc/create_excl_existing_sem/create_excl_existing_sem.c b/test/testcases/posixipc/create_excl_existing_sem/create_excl_existing_sem.c
new file mode 100644
index 0000000..2fb69e5
--- /dev/null
+++ b/test/testcases/posixipc/create_excl_existing_sem/create_excl_existing_sem.c
@@ -0,0 +1,20 @@
+#include <common.h>
+
+int
+main(void) {
+	int retval = 0;
+	sem_t *id;
+
+	id = sem_open(TEST_PATH, O_CREAT, 0777, 1);
+	if (id == SEM_FAILED) {
+		perror("sem_open(O_CREAT)");
+		return 1;
+	}
+	sem_close(id);
+
+	retval = sem_open_should_fail(TEST_PATH, O_CREAT | O_EXCL, 0777, 1, EEXIST);
+
+	sem_unlink(TEST_PATH);
+
+	return retval;
+}
diff --git a/test/testcases/posixipc/create_unnamed_semaphore/Makefile b/test/testcases/posixipc/create_unnamed_semaphore/Makefile
new file mode 100644
index 0000000..85564b9
--- /dev/null
+++ b/test/testcases/posixipc/create_unnamed_semaphore/Makefile
@@ -0,0 +1,10 @@
+PROG=	create_unnamed_semaphore
+SRCS=	create_unnamed_semaphore.c common.c
+NO_MAN=
+LDADD=  -lpthread
+
+CFLAGS= -I ${.CURDIR}/../common
+WARNS?=	3
+
+.include <bsd.prog.mk>
+.PATH: ${.CURDIR}/../common
diff --git a/test/testcases/posixipc/create_unnamed_semaphore/create_unnamed_semaphore.c b/test/testcases/posixipc/create_unnamed_semaphore/create_unnamed_semaphore.c
new file mode 100644
index 0000000..a666dac
--- /dev/null
+++ b/test/testcases/posixipc/create_unnamed_semaphore/create_unnamed_semaphore.c
@@ -0,0 +1,16 @@
+#include <common.h>
+
+int
+main(void) {
+	sem_t id;
+
+	if (sem_init(&id, 0, 1) < 0) {
+		return 1;
+	}
+
+	if (sem_destroy(&id) < 0) {
+		perror("sem_destroy");
+		return 1;
+	}
+	return 0;
+}
diff --git a/test/testcases/posixipc/destroy_named_semaphore/Makefile b/test/testcases/posixipc/destroy_named_semaphore/Makefile
new file mode 100644
index 0000000..c814181
--- /dev/null
+++ b/test/testcases/posixipc/destroy_named_semaphore/Makefile
@@ -0,0 +1,10 @@
+PROG=	destroy_named_semaphore
+SRCS=	destroy_named_semaphore.c common.c
+NO_MAN=
+LDADD=  -lpthread
+
+CFLAGS= -I ${.CURDIR}/../common
+WARNS?=	3
+
+.include <bsd.prog.mk>
+.PATH: ${.CURDIR}/../common
diff --git a/test/testcases/posixipc/destroy_named_semaphore/destroy_named_semaphore.c b/test/testcases/posixipc/destroy_named_semaphore/destroy_named_semaphore.c
new file mode 100644
index 0000000..7fe320a
--- /dev/null
+++ b/test/testcases/posixipc/destroy_named_semaphore/destroy_named_semaphore.c
@@ -0,0 +1,19 @@
+#include <common.h>
+
+int
+main(void) {
+	int retval = 0;
+	sem_t *id;
+
+	id = sem_open(TEST_PATH, O_CREAT, 0777, 1);
+	if (id == SEM_FAILED) {
+		return 1;
+	}
+
+	retval = sem_destroy_should_fail(id, EINVAL);
+
+	sem_close(id);
+	sem_unlink(TEST_PATH);
+
+	return retval;
+}
diff --git a/test/testcases/posixipc/file_test/Makefile b/test/testcases/posixipc/file_test/Makefile
new file mode 100644
index 0000000..5c26776
--- /dev/null
+++ b/test/testcases/posixipc/file_test/Makefile
@@ -0,0 +1,10 @@
+PROG=	file_test
+SRCS=	file_test.c common.c
+NO_MAN=
+LDADD=  -lpthread
+
+CFLAGS= -I ${.CURDIR}/../common
+WARNS?=	3
+
+.include <bsd.prog.mk>
+.PATH: ${.CURDIR}/../common
diff --git a/test/testcases/posixipc/file_test/file_test.c b/test/testcases/posixipc/file_test/file_test.c
new file mode 100644
index 0000000..98e63c2
--- /dev/null
+++ b/test/testcases/posixipc/file_test/file_test.c
@@ -0,0 +1,28 @@
+#include <common.h>
+
+int
+main(void) {
+	struct stat sb;
+	sem_t *id;
+	int error;
+
+	id = sem_open(TEST_PATH, O_CREAT, 0777, 0);
+	if (id == SEM_FAILED) {
+		perror("sem_open");
+		return 1;
+	}
+
+	error = stat("/var/run/sem", &sb);
+	if (error) {
+		perror("stat");
+		return 1;
+	}
+	if ((sb.st_mode & ALLPERMS) != (S_IRWXU|S_IRWXG|S_IRWXO|S_ISTXT)) {
+		fprintf(stderr, "semaphore dir has incorrect mode: 0%o\n",
+			 (sb.st_mode & ALLPERMS));
+		return 1;
+	}
+
+	sem_close(id);
+	return 0;
+}
diff --git a/test/testcases/posixipc/init_bad_value/Makefile b/test/testcases/posixipc/init_bad_value/Makefile
new file mode 100644
index 0000000..23017ad
--- /dev/null
+++ b/test/testcases/posixipc/init_bad_value/Makefile
@@ -0,0 +1,10 @@
+PROG=	init_bad_value
+SRCS=	init_bad_value.c common.c
+NO_MAN=
+LDADD=  -lpthread
+
+CFLAGS= -I ${.CURDIR}/../common
+WARNS?=	3
+
+.include <bsd.prog.mk>
+.PATH: ${.CURDIR}/../common
diff --git a/test/testcases/posixipc/init_bad_value/init_bad_value.c b/test/testcases/posixipc/init_bad_value/init_bad_value.c
new file mode 100644
index 0000000..ea82e5d
--- /dev/null
+++ b/test/testcases/posixipc/init_bad_value/init_bad_value.c
@@ -0,0 +1,10 @@
+#include <common.h>
+
+int
+main(void) {
+	int retval = 0;
+
+	retval = sem_init_should_fail(SEM_VALUE_MAX+1U, EINVAL);
+
+	return retval;
+}
diff --git a/test/testcases/posixipc/max_value/Makefile b/test/testcases/posixipc/max_value/Makefile
new file mode 100644
index 0000000..b65e6e0
--- /dev/null
+++ b/test/testcases/posixipc/max_value/Makefile
@@ -0,0 +1,10 @@
+PROG=	max_value
+SRCS=	max_value.c common.c
+NO_MAN=
+LDADD=  -lpthread
+
+CFLAGS= -I ${.CURDIR}/../common
+WARNS?=	3
+
+.include <bsd.prog.mk>
+.PATH: ${.CURDIR}/../common
diff --git a/test/testcases/posixipc/max_value/max_value.c b/test/testcases/posixipc/max_value/max_value.c
new file mode 100644
index 0000000..a94a4d1
--- /dev/null
+++ b/test/testcases/posixipc/max_value/max_value.c
@@ -0,0 +1,32 @@
+#include <common.h>
+
+int
+main(void) {
+	sem_t id;
+	int val;
+
+	if (sem_init(&id, 0, SEM_VALUE_MAX) < 0) {
+		perror("sem_init");
+		return 1;
+	}
+	if (sem_getvalue(&id, &val) < 0) {
+		perror("sem_getvalue");
+		sem_destroy(&id);
+		return 1;
+	}
+	if (val != SEM_VALUE_MAX) {
+		fprintf(stderr, "value %d != SEM_VALUE_MAX", val);
+		sem_destroy(&id);
+		return 1;
+	}
+	if (val < 0) {
+		fprintf(stderr, "value < 0");
+		sem_destroy(&id);
+		return 1;
+	}
+	if (sem_destroy(&id) < 0) {
+		perror("sem_destroy");
+		return 1;
+	}
+	return 0;
+}
diff --git a/test/testcases/posixipc/open_after_unlink/Makefile b/test/testcases/posixipc/open_after_unlink/Makefile
new file mode 100644
index 0000000..78e999d
--- /dev/null
+++ b/test/testcases/posixipc/open_after_unlink/Makefile
@@ -0,0 +1,10 @@
+PROG=	open_after_unlink
+SRCS=	open_after_unlink.c common.c
+NO_MAN=
+LDADD=  -lpthread
+
+CFLAGS= -I ${.CURDIR}/../common
+WARNS?=	3
+
+.include <bsd.prog.mk>
+.PATH: ${.CURDIR}/../common
diff --git a/test/testcases/posixipc/open_after_unlink/open_after_unlink.c b/test/testcases/posixipc/open_after_unlink/open_after_unlink.c
new file mode 100644
index 0000000..3352b2a
--- /dev/null
+++ b/test/testcases/posixipc/open_after_unlink/open_after_unlink.c
@@ -0,0 +1,23 @@
+#include <common.h>
+
+int
+main(void) {
+	int retval = 0;
+	sem_t *id;
+
+	id = sem_open(TEST_PATH, O_CREAT, 0777, 1);
+	if (id == SEM_FAILED) {
+		perror("sem_open");
+		return 1;
+	}
+	sem_close(id);
+
+	if (sem_unlink(TEST_PATH) < 0) {
+		perror("sem_unlink");
+		return 1;
+	}
+
+	retval = sem_open_should_fail(TEST_PATH, O_RDONLY, 0777, 1, ENOENT);
+
+	return retval;
+}
diff --git a/test/testcases/posixipc/open_bad_value/Makefile b/test/testcases/posixipc/open_bad_value/Makefile
new file mode 100644
index 0000000..2ee9b94
--- /dev/null
+++ b/test/testcases/posixipc/open_bad_value/Makefile
@@ -0,0 +1,10 @@
+PROG=	open_bad_value
+SRCS=	open_bad_value.c common.c
+NO_MAN=
+LDADD=  -lpthread
+
+CFLAGS= -I ${.CURDIR}/../common
+WARNS?=	3
+
+.include <bsd.prog.mk>
+.PATH: ${.CURDIR}/../common
diff --git a/test/testcases/posixipc/open_bad_value/open_bad_value.c b/test/testcases/posixipc/open_bad_value/open_bad_value.c
new file mode 100644
index 0000000..a683516
--- /dev/null
+++ b/test/testcases/posixipc/open_bad_value/open_bad_value.c
@@ -0,0 +1,12 @@
+#include <common.h>
+
+int
+main(void) {
+	int retval = 0;
+
+	(void)sem_unlink(TEST_PATH);
+	retval = sem_open_should_fail(TEST_PATH, O_CREAT, 0777,
+	    SEM_VALUE_MAX+1U, EINVAL);
+
+	return retval;
+}
diff --git a/test/testcases/posixipc/open_extra_flags/Makefile b/test/testcases/posixipc/open_extra_flags/Makefile
new file mode 100644
index 0000000..2693d22
--- /dev/null
+++ b/test/testcases/posixipc/open_extra_flags/Makefile
@@ -0,0 +1,10 @@
+PROG=	open_extra_flags
+SRCS=	open_extra_flags.c common.c
+NO_MAN=
+LDADD=  -lpthread
+
+CFLAGS= -I ${.CURDIR}/../common
+WARNS?=	3
+
+.include <bsd.prog.mk>
+.PATH: ${.CURDIR}/../common
diff --git a/test/testcases/posixipc/open_extra_flags/open_extra_flags.c b/test/testcases/posixipc/open_extra_flags/open_extra_flags.c
new file mode 100644
index 0000000..acc3ba9
--- /dev/null
+++ b/test/testcases/posixipc/open_extra_flags/open_extra_flags.c
@@ -0,0 +1,11 @@
+#include <stdio.h>
+#include <common.h>
+
+int
+main(void) {
+	int retval = 0;
+
+	retval = sem_open_should_fail(TEST_PATH, O_RDONLY | O_DIRECT, 0777, 1, EINVAL);
+
+	return retval;
+}
diff --git a/test/testcases/posixipc/open_invalid_path/Makefile b/test/testcases/posixipc/open_invalid_path/Makefile
new file mode 100644
index 0000000..497e4df
--- /dev/null
+++ b/test/testcases/posixipc/open_invalid_path/Makefile
@@ -0,0 +1,10 @@
+PROG=	open_invalid_path
+SRCS=	open_invalid_path.c common.c
+NO_MAN=
+LDADD=  -lpthread
+
+CFLAGS= -I ${.CURDIR}/../common
+WARNS?=	3
+
+.include <bsd.prog.mk>
+.PATH: ${.CURDIR}/../common
diff --git a/test/testcases/posixipc/open_invalid_path/open_invalid_path.c b/test/testcases/posixipc/open_invalid_path/open_invalid_path.c
new file mode 100644
index 0000000..6a73c24
--- /dev/null
+++ b/test/testcases/posixipc/open_invalid_path/open_invalid_path.c
@@ -0,0 +1,11 @@
+#include <stdio.h>
+#include <common.h>
+
+int
+main(void) {
+	int retval = 0;
+
+	retval = sem_open_should_fail("blah", 0, 0777, 1, ENOENT);
+
+	return retval;
+}
diff --git a/test/testcases/posixipc/open_named_semaphore/Makefile b/test/testcases/posixipc/open_named_semaphore/Makefile
new file mode 100644
index 0000000..ef11f8d
--- /dev/null
+++ b/test/testcases/posixipc/open_named_semaphore/Makefile
@@ -0,0 +1,10 @@
+PROG=	open_named_semaphore
+SRCS=	open_named_semaphore.c common.c
+NO_MAN=
+LDADD=  -lpthread
+
+CFLAGS= -I ${.CURDIR}/../common
+WARNS?=	3
+
+.include <bsd.prog.mk>
+.PATH: ${.CURDIR}/../common
diff --git a/test/testcases/posixipc/open_named_semaphore/open_named_semaphore.c b/test/testcases/posixipc/open_named_semaphore/open_named_semaphore.c
new file mode 100644
index 0000000..8932e07
--- /dev/null
+++ b/test/testcases/posixipc/open_named_semaphore/open_named_semaphore.c
@@ -0,0 +1,23 @@
+#include <common.h>
+
+int
+main(void) {
+	sem_t *id;
+
+	id = sem_open(TEST_PATH, O_CREAT, 0777, 1);
+	if (id == SEM_FAILED) {
+		perror("sem_open(O_CREAT)");
+		return 1;
+	}
+
+	if (sem_close(id) < 0) {
+		perror("sem_close");
+		return 1;
+	}
+
+	if (sem_unlink(TEST_PATH) < 0) {
+		perror("sem_unlink");
+		return 1;
+	}
+	return 0;
+}
diff --git a/test/testcases/posixipc/open_non_existing/Makefile b/test/testcases/posixipc/open_non_existing/Makefile
new file mode 100644
index 0000000..4d55b20
--- /dev/null
+++ b/test/testcases/posixipc/open_non_existing/Makefile
@@ -0,0 +1,10 @@
+PROG=	open_non_existing
+SRCS=	open_non_existing.c common.c
+NO_MAN=
+LDADD=  -lpthread
+
+CFLAGS= -I ${.CURDIR}/../common
+WARNS?=	3
+
+.include <bsd.prog.mk>
+.PATH: ${.CURDIR}/../common
diff --git a/test/testcases/posixipc/open_non_existing/open_non_existing.c b/test/testcases/posixipc/open_non_existing/open_non_existing.c
new file mode 100644
index 0000000..3e5af6a
--- /dev/null
+++ b/test/testcases/posixipc/open_non_existing/open_non_existing.c
@@ -0,0 +1,10 @@
+#include <common.h>
+
+int
+main(void) {
+	int retval = 0;
+
+	sem_open_should_fail("/notreallythere", 0, 0777, 1, ENOENT);
+
+	return retval;
+}
diff --git a/test/testcases/posixipc/open_path_too_long/Makefile b/test/testcases/posixipc/open_path_too_long/Makefile
new file mode 100644
index 0000000..1f3feda
--- /dev/null
+++ b/test/testcases/posixipc/open_path_too_long/Makefile
@@ -0,0 +1,10 @@
+PROG=	open_path_too_long
+SRCS=	open_path_too_long.c common.c
+NO_MAN=
+LDADD=  -lpthread
+
+CFLAGS= -I ${.CURDIR}/../common
+WARNS?=	3
+
+.include <bsd.prog.mk>
+.PATH: ${.CURDIR}/../common
diff --git a/test/testcases/posixipc/open_path_too_long/open_path_too_long.c b/test/testcases/posixipc/open_path_too_long/open_path_too_long.c
new file mode 100644
index 0000000..0dc3f8a
--- /dev/null
+++ b/test/testcases/posixipc/open_path_too_long/open_path_too_long.c
@@ -0,0 +1,16 @@
+#include <common.h>
+
+int
+main(void) {
+	int retval = 0;
+	char *page;
+
+	page = malloc(MAXPATHLEN + 1);
+	memset(page, 'a', MAXPATHLEN);
+	page[0] = '/';
+	page[MAXPATHLEN] = '\0';
+	sem_open_should_fail(page, O_RDONLY, 0777, 1, ENAMETOOLONG);
+	free(page);
+
+	return retval;
+}
diff --git a/test/testcases/posixipc/post_test/Makefile b/test/testcases/posixipc/post_test/Makefile
new file mode 100644
index 0000000..335ae66
--- /dev/null
+++ b/test/testcases/posixipc/post_test/Makefile
@@ -0,0 +1,10 @@
+PROG=	post_test
+SRCS=	post_test.c common.c
+NO_MAN=
+LDADD=  -lpthread
+
+CFLAGS= -I ${.CURDIR}/../common
+WARNS?=	3
+
+.include <bsd.prog.mk>
+.PATH: ${.CURDIR}/../common
diff --git a/test/testcases/posixipc/post_test/post_test.c b/test/testcases/posixipc/post_test/post_test.c
new file mode 100644
index 0000000..af40b78
--- /dev/null
+++ b/test/testcases/posixipc/post_test/post_test.c
@@ -0,0 +1,29 @@
+#include <common.h>
+
+int
+main(void) {
+	sem_t id;
+
+	if (sem_init(&id, 0, 1) < 0) {
+		perror("sem_init");
+		return 1;
+	}
+	if (checkvalue(&id, 1) < 0) {
+		sem_destroy(&id);
+		return 1;
+	}
+	if (sem_post(&id) < 0) {
+		perror("sem_post");
+		sem_destroy(&id);
+		return 1;
+	}
+	if (checkvalue(&id, 2) < 0) {
+		sem_destroy(&id);
+		return 1;
+	}
+	if (sem_destroy(&id) < 0) {
+		perror("sem_destroy");
+		return 1;
+	}
+	return 0;
+}
diff --git a/test/testcases/posixipc/timedwait_expired/Makefile b/test/testcases/posixipc/timedwait_expired/Makefile
new file mode 100644
index 0000000..5966d33
--- /dev/null
+++ b/test/testcases/posixipc/timedwait_expired/Makefile
@@ -0,0 +1,10 @@
+PROG=	timedwait_expired
+SRCS=	timedwait_expired.c common.c
+NO_MAN=
+LDADD=  -lpthread
+
+CFLAGS= -I ${.CURDIR}/../common
+WARNS?=	3
+
+.include <bsd.prog.mk>
+.PATH: ${.CURDIR}/../common
diff --git a/test/testcases/posixipc/timedwait_expired/timedwait_expired.c b/test/testcases/posixipc/timedwait_expired/timedwait_expired.c
new file mode 100644
index 0000000..1a5b968
--- /dev/null
+++ b/test/testcases/posixipc/timedwait_expired/timedwait_expired.c
@@ -0,0 +1,34 @@
+#include <common.h>
+
+int
+main(void) {
+	sem_t id;
+	u_int elapsed;
+
+	if (sem_init(&id, 0, 0) < 0) {
+		perror("sem_init");
+		return 1;
+	}
+
+	/* This should fail with a timeout and leave the value at 0. */
+	if (timedwait(&id, 2500, &elapsed, ETIMEDOUT) < 0) {
+		sem_destroy(&id);
+		return 1;
+	}
+	if (!ELAPSED(elapsed, 2500)) {
+		fprintf(stderr, "sem_timedwait() of locked sem took %ums "
+		    "instead of 2500ms", elapsed);
+		sem_destroy(&id);
+		return 1;
+	}
+	if (checkvalue(&id, 0) < 0) {
+		sem_destroy(&id);
+		return 1;
+	}
+
+	if (sem_destroy(&id) < 0) {
+		perror("sem_destroy");
+		return 1;
+	}
+	return 0;
+}
diff --git a/test/testcases/posixipc/timedwait_locked/Makefile b/test/testcases/posixipc/timedwait_locked/Makefile
new file mode 100644
index 0000000..40399e4
--- /dev/null
+++ b/test/testcases/posixipc/timedwait_locked/Makefile
@@ -0,0 +1,10 @@
+PROG=	timedwait_locked
+SRCS=	timedwait_locked.c common.c
+NO_MAN=
+LDADD=  -lpthread
+
+CFLAGS= -I ${.CURDIR}/../common
+WARNS?=	3
+
+.include <bsd.prog.mk>
+.PATH: ${.CURDIR}/../common
diff --git a/test/testcases/posixipc/timedwait_locked/timedwait_locked.c b/test/testcases/posixipc/timedwait_locked/timedwait_locked.c
new file mode 100644
index 0000000..a3ea5e7
--- /dev/null
+++ b/test/testcases/posixipc/timedwait_locked/timedwait_locked.c
@@ -0,0 +1,43 @@
+#include <common.h>
+
+int
+main(void) {
+	sem_t *id;
+	u_int elapsed;
+	pid_t pid;
+
+	id = construct_shared_unnamed_sem(0);
+	if (id == SEM_FAILED) {
+		fprintf(stderr, "construct sem\n");
+		return 1;
+	}
+
+	pid = fork();
+	switch (pid) {
+	case -1:
+		/* Error. */
+		perror("fork");
+		destruct_shared_unnamed_sem(id);
+		return 1;
+	case 0:
+		/* Child. */
+		sleep(1);
+		sem_post(id);
+		exit(0);
+	}
+
+	if (timedwait(id, 2000, &elapsed, 0) < 0) {
+		destruct_shared_unnamed_sem(id);
+		return 1;
+	}
+	if (!ELAPSED(elapsed, 1000)) {
+		fprintf(stderr, "sem_timedwait() with delayed post took %ums "
+		    "instead of 1000ms", elapsed);
+		destruct_shared_unnamed_sem(id);
+		return 1;
+	}
+
+	destruct_shared_unnamed_sem(id);
+
+	return 0;
+}
diff --git a/test/testcases/posixipc/timedwait_unlocked/Makefile b/test/testcases/posixipc/timedwait_unlocked/Makefile
new file mode 100644
index 0000000..74d3b4a
--- /dev/null
+++ b/test/testcases/posixipc/timedwait_unlocked/Makefile
@@ -0,0 +1,10 @@
+PROG=	timedwait_unlocked
+SRCS=	timedwait_unlocked.c common.c
+NO_MAN=
+LDADD=  -lpthread
+
+CFLAGS= -I ${.CURDIR}/../common
+WARNS?=	3
+
+.include <bsd.prog.mk>
+.PATH: ${.CURDIR}/../common
diff --git a/test/testcases/posixipc/timedwait_unlocked/timedwait_unlocked.c b/test/testcases/posixipc/timedwait_unlocked/timedwait_unlocked.c
new file mode 100644
index 0000000..ea29495
--- /dev/null
+++ b/test/testcases/posixipc/timedwait_unlocked/timedwait_unlocked.c
@@ -0,0 +1,34 @@
+#include <common.h>
+
+int
+main(void) {
+	sem_t id;
+	u_int elapsed;
+
+	if (sem_init(&id, 0, 1) < 0) {
+		perror("sem_init");
+		return 1;
+	}
+
+	/* This should succeed right away and set the value to 0. */
+	if (timedwait(&id, 5000, &elapsed, 0) < 0) {
+		sem_destroy(&id);
+		return 1;
+	}
+	if (!ELAPSED(elapsed, 0)) {
+		fprintf(stderr, "sem_timedwait() of unlocked sem took %ums",
+		    elapsed);
+		sem_destroy(&id);
+		return 1;
+	}
+	if (checkvalue(&id, 0) < 0) {
+		sem_destroy(&id);
+		return 1;
+	}
+
+	if (sem_destroy(&id) < 0) {
+		perror("sem_destroy");
+		return 1;
+	}
+	return 0;
+}
diff --git a/test/testcases/posixipc/trywait_locked/Makefile b/test/testcases/posixipc/trywait_locked/Makefile
new file mode 100644
index 0000000..a978c2a
--- /dev/null
+++ b/test/testcases/posixipc/trywait_locked/Makefile
@@ -0,0 +1,10 @@
+PROG=	trywait_locked
+SRCS=	trywait_locked.c common.c
+NO_MAN=
+LDADD=  -lpthread
+
+CFLAGS= -I ${.CURDIR}/../common
+WARNS?=	3
+
+.include <bsd.prog.mk>
+.PATH: ${.CURDIR}/../common
diff --git a/test/testcases/posixipc/trywait_locked/trywait_locked.c b/test/testcases/posixipc/trywait_locked/trywait_locked.c
new file mode 100644
index 0000000..a5c4f6e
--- /dev/null
+++ b/test/testcases/posixipc/trywait_locked/trywait_locked.c
@@ -0,0 +1,32 @@
+#include <common.h>
+
+int
+main(void) {
+	sem_t id;
+
+	if (sem_init(&id, 0, 0) < 0) {
+		perror("sem_init");
+		return 1;
+	}
+
+	/* This should fail with EAGAIN and leave the value at 0. */
+	if (sem_trywait(&id) >= 0) {
+		sem_destroy(&id);
+		return 1;
+	}
+	if (errno != EAGAIN) {
+		perror("wrong error from sem_trywait()");
+		sem_destroy(&id);
+		return 1;
+	}
+	if (checkvalue(&id, 0) < 0) {
+		sem_destroy(&id);
+		return 1;
+	}
+
+	if (sem_destroy(&id) < 0) {
+		perror("sem_destroy");
+		return 1;
+	}
+	return 0;
+}
diff --git a/test/testcases/posixipc/trywait_unlocked/Makefile b/test/testcases/posixipc/trywait_unlocked/Makefile
new file mode 100644
index 0000000..1481133
--- /dev/null
+++ b/test/testcases/posixipc/trywait_unlocked/Makefile
@@ -0,0 +1,10 @@
+PROG=	trywait_unlocked
+SRCS=	trywait_unlocked.c common.c
+NO_MAN=
+LDADD=  -lpthread
+
+CFLAGS= -I ${.CURDIR}/../common
+WARNS?=	3
+
+.include <bsd.prog.mk>
+.PATH: ${.CURDIR}/../common
diff --git a/test/testcases/posixipc/trywait_unlocked/trywait_unlocked.c b/test/testcases/posixipc/trywait_unlocked/trywait_unlocked.c
new file mode 100644
index 0000000..9c71dd6
--- /dev/null
+++ b/test/testcases/posixipc/trywait_unlocked/trywait_unlocked.c
@@ -0,0 +1,28 @@
+#include <common.h>
+
+int
+main(void) {
+	sem_t id;
+
+	if (sem_init(&id, 0, 1) < 0) {
+		perror("sem_init");
+		return 1;
+	}
+
+	/* This should succeed and decrement the value to 0. */
+	if (sem_trywait(&id) < 0) {
+		perror("sem_trywait()");
+		sem_destroy(&id);
+		return 1;
+	}
+	if (checkvalue(&id, 0) < 0) {
+		sem_destroy(&id);
+		return 1;
+	}
+
+	if (sem_destroy(&id) < 0) {
+		perror("sem_destroy");
+		return 1;
+	}
+	return 0;
+}
diff --git a/test/testcases/posixipc/unlink_path_too_long/Makefile b/test/testcases/posixipc/unlink_path_too_long/Makefile
new file mode 100644
index 0000000..a9500db
--- /dev/null
+++ b/test/testcases/posixipc/unlink_path_too_long/Makefile
@@ -0,0 +1,10 @@
+PROG=	unlink_path_too_long
+SRCS=	unlink_path_too_long.c common.c
+NO_MAN=
+LDADD=  -lpthread
+
+CFLAGS= -I ${.CURDIR}/../common
+WARNS?=	3
+
+.include <bsd.prog.mk>
+.PATH: ${.CURDIR}/../common
diff --git a/test/testcases/posixipc/unlink_path_too_long/unlink_path_too_long.c b/test/testcases/posixipc/unlink_path_too_long/unlink_path_too_long.c
new file mode 100644
index 0000000..cfac61f
--- /dev/null
+++ b/test/testcases/posixipc/unlink_path_too_long/unlink_path_too_long.c
@@ -0,0 +1,15 @@
+#include <common.h>
+
+int
+main(void) {
+	int retval = 0;
+	char *page;
+
+	page = malloc(MAXPATHLEN + 1);
+	memset(page, 'a', MAXPATHLEN);
+	page[MAXPATHLEN] = '\0';
+	retval = sem_unlink_should_fail(page, ENAMETOOLONG);
+	free(page);
+
+	return retval;
+}
diff --git a/test/testcases/posixipc/use_after_unlink/Makefile b/test/testcases/posixipc/use_after_unlink/Makefile
new file mode 100644
index 0000000..7422e8c
--- /dev/null
+++ b/test/testcases/posixipc/use_after_unlink/Makefile
@@ -0,0 +1,10 @@
+PROG=	use_after_unlink
+SRCS=	use_after_unlink.c common.c
+NO_MAN=
+LDADD=  -lpthread
+
+CFLAGS= -I ${.CURDIR}/../common
+WARNS?=	3
+
+.include <bsd.prog.mk>
+.PATH: ${.CURDIR}/../common
diff --git a/test/testcases/posixipc/use_after_unlink/use_after_unlink.c b/test/testcases/posixipc/use_after_unlink/use_after_unlink.c
new file mode 100644
index 0000000..1152d20
--- /dev/null
+++ b/test/testcases/posixipc/use_after_unlink/use_after_unlink.c
@@ -0,0 +1,53 @@
+#include <common.h>
+
+int
+main(void) {
+	sem_t *id;
+
+	/*
+	 * Create named semaphore with value of 1 and then unlink it
+	 * while still retaining the initial reference.
+	 */
+	id = sem_open(TEST_PATH, O_CREAT | O_EXCL, 0777, 1);
+	if (id == SEM_FAILED) {
+		perror("sem_open(O_CREAT | O_EXCL)");
+		return 1;
+	}
+	if (sem_unlink(TEST_PATH) < 0) {
+		perror("sem_unlink");
+		sem_close(id);
+		return 1;
+	}
+	if (checkvalue(id, 1) < 0) {
+		sem_close(id);
+		return 1;
+	}
+
+	/* Post the semaphore to set its value to 2. */
+	if (sem_post(id) < 0) {
+		perror("sem_post");
+		sem_close(id);
+		return 1;
+	}
+	if (checkvalue(id, 2) < 0) {
+		sem_close(id);
+		return 1;
+	}
+
+	/* Wait on the semaphore which should set its value to 1. */
+	if (sem_wait(id) < 0) {
+		perror("sem_wait");
+		sem_close(id);
+		return 1;
+	}
+	if (checkvalue(id, 1) < 0) {
+		sem_close(id);
+		return 1;
+	}
+
+	if (sem_close(id) < 0) {
+		perror("sem_close");
+		return 1;
+	}
+	return 0;
+}
diff --git a/test/testcases/posixipc/wait_locked/Makefile b/test/testcases/posixipc/wait_locked/Makefile
new file mode 100644
index 0000000..88c7b90
--- /dev/null
+++ b/test/testcases/posixipc/wait_locked/Makefile
@@ -0,0 +1,10 @@
+PROG=	wait_locked
+SRCS=	wait_locked.c common.c
+NO_MAN=
+LDADD=  -lpthread
+
+CFLAGS= -I ${.CURDIR}/../common
+WARNS?=	3
+
+.include <bsd.prog.mk>
+.PATH: ${.CURDIR}/../common
diff --git a/test/testcases/posixipc/wait_locked/wait_locked.c b/test/testcases/posixipc/wait_locked/wait_locked.c
new file mode 100644
index 0000000..46239ce
--- /dev/null
+++ b/test/testcases/posixipc/wait_locked/wait_locked.c
@@ -0,0 +1,39 @@
+#include <common.h>
+
+int
+main(void) {
+	sem_t *id;
+	u_int elapsed;
+	pid_t pid;
+
+	id = construct_shared_unnamed_sem(0);
+
+	pid = fork();
+	switch (pid) {
+	case -1:
+		/* Error. */
+		perror("fork");
+		destruct_shared_unnamed_sem(id);
+		return 1;
+	case 0:
+		/* Child. */
+		sleep(1);
+		sem_post(id);
+		exit(0);
+	}
+
+	if (testwait(id, &elapsed) < 0) {
+		destruct_shared_unnamed_sem(id);
+		return 1;
+	}
+	if (!ELAPSED(elapsed, 1000)) {
+		fprintf(stderr, "sem_wait() with delayed post took %ums "
+		    "instead of 1000ms", elapsed);
+		destruct_shared_unnamed_sem(id);
+		return 1;
+	}
+
+	destruct_shared_unnamed_sem(id);
+
+	return 0;
+}
diff --git a/test/testcases/posixipc/wait_two_proc/Makefile b/test/testcases/posixipc/wait_two_proc/Makefile
new file mode 100644
index 0000000..3f9546a
--- /dev/null
+++ b/test/testcases/posixipc/wait_two_proc/Makefile
@@ -0,0 +1,10 @@
+PROG=	wait_two_proc
+SRCS=	wait_two_proc.c common.c
+NO_MAN=
+LDADD=  -lpthread
+
+CFLAGS= -I ${.CURDIR}/../common
+WARNS?=	3
+
+.include <bsd.prog.mk>
+.PATH: ${.CURDIR}/../common
diff --git a/test/testcases/posixipc/wait_two_proc/wait_two_proc.c b/test/testcases/posixipc/wait_two_proc/wait_two_proc.c
new file mode 100644
index 0000000..c0bb191
--- /dev/null
+++ b/test/testcases/posixipc/wait_two_proc/wait_two_proc.c
@@ -0,0 +1,57 @@
+#include <common.h>
+
+int
+main(void) {
+	sem_t *id;
+	int retval = 0;
+	int stat;
+
+	id = sem_open(TEST_PATH, O_CREAT, 0777, 0);
+	if (id == SEM_FAILED) {
+		perror("sem_open");
+		return 1;
+	}
+
+	if (schedule_post(id, 500) < 0) {
+		sem_close(id);
+		sem_unlink(TEST_PATH);
+		return 1;
+	}
+
+	if (child_worker(wait_twoproc_child, NULL, &stat) < 0) {
+		check_alarm(1);
+		sem_close(id);
+		sem_unlink(TEST_PATH);
+		return 1;
+	}
+
+	errno = CSTAT_ERROR(stat);
+	switch (CSTAT_CLASS(stat)) {
+	case 0:
+		/* Pass! */
+		retval = 0;
+		break;
+	case 1:
+		perror("child sem_open()");
+		retval = 1;
+		break;
+	case 2:
+		perror("child sem_wait()");
+		retval = 1;
+		break;
+	case 3:
+		perror("child sem_close()");
+		retval = 1;
+		break;
+	default:
+		fprintf(stderr, "bad child state %#x", stat);
+		retval = 1;
+		break;
+	}
+
+	check_alarm(1);
+	sem_close(id);
+	sem_unlink(TEST_PATH);
+
+	return retval;
+}
diff --git a/test/testcases/posixipc/wait_unlocked/Makefile b/test/testcases/posixipc/wait_unlocked/Makefile
new file mode 100644
index 0000000..efe9120
--- /dev/null
+++ b/test/testcases/posixipc/wait_unlocked/Makefile
@@ -0,0 +1,10 @@
+PROG=	wait_unlocked
+SRCS=	wait_unlocked.c common.c
+NO_MAN=
+LDADD=  -lpthread
+
+CFLAGS= -I ${.CURDIR}/../common
+WARNS?=	3
+
+.include <bsd.prog.mk>
+.PATH: ${.CURDIR}/../common
diff --git a/test/testcases/posixipc/wait_unlocked/wait_unlocked.c b/test/testcases/posixipc/wait_unlocked/wait_unlocked.c
new file mode 100644
index 0000000..fe844ed
--- /dev/null
+++ b/test/testcases/posixipc/wait_unlocked/wait_unlocked.c
@@ -0,0 +1,34 @@
+#include <common.h>
+
+int
+main(void) {
+	sem_t id;
+	u_int elapsed;
+
+	if (sem_init(&id, 0, 1) < 0) {
+		perror("sem_init");
+		return 1;
+	}
+
+	/* This should succeed right away and set the value to 0. */
+	if (testwait(&id, &elapsed) < 0) {
+		sem_destroy(&id);
+		return 1;
+	}
+	if (!ELAPSED(elapsed, 0)) {
+		fprintf(stderr, "sem_wait() of unlocked sem took %ums",
+		    elapsed);
+		sem_destroy(&id);
+		return 1;
+	}
+	if (checkvalue(&id, 0) < 0) {
+		sem_destroy(&id);
+		return 1;
+	}
+
+	if (sem_destroy(&id) < 0) {
+		perror("sem_destroy");
+		return 1;
+	}
+	return 0;
+}
diff --git a/test/testcases/sample.run b/test/testcases/sample.run
index 9336fa0..4df4167 100644
--- a/test/testcases/sample.run
+++ b/test/testcases/sample.run
@@ -42,6 +42,33 @@ crypto/serpent/serpent_test		userland	defaults		serpentecb_vt.txt
 crypto/twofish/twofish_test		userland	defaults		twofishecb_vk.txt
 crypto/twofish/twofish_test		userland	defaults		twofishecb_vt.txt
 
+# POSIX IPC tests
+posixipc/close_unnamed_semaphore/close_unnamed_semaphore        userland        defaults
+posixipc/create_excl_existing_sem/create_excl_existing_sem      userland        defaults
+posixipc/create_unnamed_semaphore/create_unnamed_semaphore      userland        defaults
+posixipc/destroy_named_semaphore/destroy_named_semaphore        userland        defaults
+posixipc/file_test/file_test                                    userland        defaults
+posixipc/init_bad_value/init_bad_value                          userland        defaults
+posixipc/max_value/max_value                                    userland        defaults
+posixipc/open_after_unlink/open_after_unlink                    userland        defaults
+posixipc/open_bad_value/open_bad_value                          userland        defaults
+posixipc/open_extra_flags/open_extra_flags                      userland        defaults
+posixipc/open_invalid_path/open_invalid_path                    userland        defaults
+posixipc/open_named_semaphore/open_named_semaphore              userland        defaults
+posixipc/open_non_existing/open_non_existing                    userland        defaults
+posixipc/open_path_too_long/open_path_too_long                  userland        defaults
+posixipc/post_test/post_test                                    userland        defaults
+posixipc/timedwait_expired/timedwait_expired                    userland        defaults
+posixipc/timedwait_locked/timedwait_locked                      userland        defaults
+posixipc/timedwait_unlocked/timedwait_unlocked                  userland        defaults
+posixipc/trywait_locked/trywait_locked                          userland        defaults
+posixipc/trywait_unlocked/trywait_unlocked                      userland        defaults
+posixipc/unlink_path_too_long/unlink_path_too_long              userland        defaults
+posixipc/use_after_unlink/use_after_unlink                      userland        defaults
+posixipc/wait_locked/wait_locked                                userland        defaults
+posixipc/wait_two_proc/wait_two_proc                            userland        defaults
+posixipc/wait_unlocked/wait_unlocked                            userland        defaults
+
 #openat_1		userland	intpre,intpost,timeout=100
 #openat_1		userland	intpre,intpost,timeout=100
 #openat_1		userland	intpre,intpost,timeout=100
