Module Name:    src
Committed By:   pooka
Date:           Thu Jun 10 22:03:43 UTC 2010

Modified Files:
        src/tests/lib: Makefile
Added Files:
        src/tests/lib/semaphore: Atffile Makefile sem.c
        src/tests/lib/semaphore/pthread: Atffile Makefile t_sem_pth.c

Log Message:
Add tests for semaphores.  Note: the "unlink" one fails because our
implementation is broken.  I'll file a PR shortly.


To generate a diff of this commit:
cvs rdiff -u -r1.2 -r1.3 src/tests/lib/Makefile
cvs rdiff -u -r0 -r1.1 src/tests/lib/semaphore/Atffile \
    src/tests/lib/semaphore/Makefile src/tests/lib/semaphore/sem.c
cvs rdiff -u -r0 -r1.1 src/tests/lib/semaphore/pthread/Atffile \
    src/tests/lib/semaphore/pthread/Makefile \
    src/tests/lib/semaphore/pthread/t_sem_pth.c

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/tests/lib/Makefile
diff -u src/tests/lib/Makefile:1.2 src/tests/lib/Makefile:1.3
--- src/tests/lib/Makefile:1.2	Mon Nov  2 10:15:45 2009
+++ src/tests/lib/Makefile	Thu Jun 10 22:03:43 2010
@@ -1,8 +1,8 @@
-# $NetBSD: Makefile,v 1.2 2009/11/02 10:15:45 plunky Exp $
+# $NetBSD: Makefile,v 1.3 2010/06/10 22:03:43 pooka Exp $
 
 .include <bsd.own.mk>
 
-SUBDIR=		libc libevent
+SUBDIR=		libc libevent semaphore
 
 TESTSDIR=	${TESTSBASE}/lib
 

Added files:

Index: src/tests/lib/semaphore/Atffile
diff -u /dev/null src/tests/lib/semaphore/Atffile:1.1
--- /dev/null	Thu Jun 10 22:03:44 2010
+++ src/tests/lib/semaphore/Atffile	Thu Jun 10 22:03:43 2010
@@ -0,0 +1,6 @@
+Content-Type: application/X-atf-atffile; version="1"
+X-NetBSD-Id: "$NetBSD: Atffile,v 1.1 2010/06/10 22:03:43 pooka Exp $"
+
+prop: test-suite = "NetBSD"
+
+tp: pthread
Index: src/tests/lib/semaphore/Makefile
diff -u /dev/null src/tests/lib/semaphore/Makefile:1.1
--- /dev/null	Thu Jun 10 22:03:44 2010
+++ src/tests/lib/semaphore/Makefile	Thu Jun 10 22:03:43 2010
@@ -0,0 +1,9 @@
+#	$NetBSD: Makefile,v 1.1 2010/06/10 22:03:43 pooka Exp $
+#
+
+SUBDIR=		pthread
+
+TESTSDIR=	${TESTSBASE}/lib/semaphore
+
+.include <bsd.test.mk>
+.include <bsd.subdir.mk>
Index: src/tests/lib/semaphore/sem.c
diff -u /dev/null src/tests/lib/semaphore/sem.c:1.1
--- /dev/null	Thu Jun 10 22:03:44 2010
+++ src/tests/lib/semaphore/sem.c	Thu Jun 10 22:03:43 2010
@@ -0,0 +1,299 @@
+/*	$NetBSD: sem.c,v 1.1 2010/06/10 22:03:43 pooka Exp $	*/
+
+/*
+ * Common code for semaphore tests.  This can be included both into
+ * programs using librt and libpthread.
+ */
+
+#include <sys/types.h>
+
+#include <rump/rump.h>
+#include <rump/rump_syscalls.h>
+
+#include <atf-c.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <pthread.h>
+#include <semaphore.h>
+#include <sched.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include "../../h_macros.h"
+
+ATF_TC(postwait);
+ATF_TC_HEAD(postwait, tc)
+{
+
+	atf_tc_set_md_var(tc, "descr", "tests post and wait from a "
+	    "single thread (%s)", LIBNAME);
+}
+
+ATF_TC_BODY(postwait, tc)
+{
+	sem_t sem;
+	int rv;
+
+	rump_init();
+
+	ATF_REQUIRE_EQ(sem_init(&sem, 1, 0), 0);
+
+	sem_post(&sem);
+	sem_post(&sem);
+
+	sem_wait(&sem);
+	sem_wait(&sem);
+	rv = sem_trywait(&sem);
+	ATF_REQUIRE(errno == EAGAIN);
+	ATF_REQUIRE(rv == -1);
+}
+
+ATF_TC(initvalue);
+ATF_TC_HEAD(initvalue, tc)
+{
+
+	atf_tc_set_md_var(tc, "descr", "tests initialization with a non-zero "
+	    "value (%s)", LIBNAME);
+}
+
+ATF_TC_BODY(initvalue, tc)
+{
+	sem_t sem;
+
+	rump_init();
+	sem_init(&sem, 1, 4);
+
+	ATF_REQUIRE_EQ(sem_trywait(&sem), 0);
+	ATF_REQUIRE_EQ(sem_trywait(&sem), 0);
+	ATF_REQUIRE_EQ(sem_trywait(&sem), 0);
+	ATF_REQUIRE_EQ(sem_trywait(&sem), 0);
+	ATF_REQUIRE_EQ(sem_trywait(&sem), -1);
+}
+
+ATF_TC(destroy);
+ATF_TC_HEAD(destroy, tc)
+{
+
+	atf_tc_set_md_var(tc, "descr", "tests sem_destroy works (%s)", LIBNAME);
+}
+
+ATF_TC_BODY(destroy, tc)
+{
+	sem_t sem;
+	int rv, i;
+
+	rump_init();
+	for (i = 0; i < 2; i++) {
+		sem_init(&sem, 1, 1);
+
+		ATF_REQUIRE_EQ(sem_trywait(&sem), 0);
+		ATF_REQUIRE_EQ(sem_trywait(&sem), -1);
+		ATF_REQUIRE_EQ(sem_destroy(&sem), 0);
+		rv = sem_trywait(&sem);
+		ATF_REQUIRE_EQ(errno, EINVAL);
+		ATF_REQUIRE_EQ(rv, -1);
+	}
+}
+
+ATF_TC(busydestroy);
+ATF_TC_HEAD(busydestroy, tc)
+{
+
+	atf_tc_set_md_var(tc, "descr", "tests sem_destroy report EBUSY for "
+	    "a busy semaphore (%s)", LIBNAME);
+}
+
+static void *
+hthread(void *arg)
+{
+	sem_t *semmarit = arg;
+
+	for (;;) {
+		sem_post(&semmarit[2]);
+		sem_wait(&semmarit[1]);
+		sem_wait(&semmarit[0]);
+	}
+}
+
+ATF_TC_BODY(busydestroy, tc)
+{
+	sem_t semmarit[3];
+	pthread_t pt;
+	int i;
+
+	/* use a unicpu rump kernel.  this means less chance for race */
+	setenv("RUMP_NCPU", "1", 1);
+
+	rump_init();
+	sem_init(&semmarit[0], 1, 0);
+	sem_init(&semmarit[1], 1, 0);
+	sem_init(&semmarit[2], 1, 0);
+
+	pthread_create(&pt, NULL, hthread, semmarit);
+
+	/*
+	 * Make a best-effort to catch the other thread with its pants down.
+	 * We can't do this for sure, can we?  Although, we could reach
+	 * inside the rump kernel and inquire about the thread's sleep
+	 * status.
+	 */
+	for (i = 0; i < 1000; i++) {
+		sem_wait(&semmarit[2]);
+		usleep(1);
+		if (sem_destroy(&semmarit[1]) == -1)
+			if (errno == EBUSY)
+				break;
+
+		/*
+		 * Didn't catch it?  ok, recreate and post to make the
+		 * other thread run
+		 */
+		sem_init(&semmarit[1], 1, 0);
+		sem_post(&semmarit[0]);
+		sem_post(&semmarit[1]);
+
+	}
+	if (i == 1000)
+		atf_tc_fail("sem destroy not reporting EBUSY");
+}
+
+ATF_TC(blockwait);
+ATF_TC_HEAD(blockwait, tc)
+{
+
+	atf_tc_set_md_var(tc, "descr", "tests sem_wait can handle blocking "
+	    "(%s)", LIBNAME);
+}
+
+ATF_TC_BODY(blockwait, tc)
+{
+	sem_t semmarit[3];
+	pthread_t pt;
+	int i;
+
+	rump_init();
+	sem_init(&semmarit[0], 1, 0);
+	sem_init(&semmarit[1], 1, 0);
+	sem_init(&semmarit[2], 1, 0);
+
+	pthread_create(&pt, NULL, hthread, semmarit);
+
+	/*
+	 * Make a best-effort.  Unless we're extremely unlucky, we should
+	 * at least one blocking wait.
+	 */
+	for (i = 0; i < 10; i++) {
+		sem_wait(&semmarit[2]);
+		usleep(1);
+		sem_post(&semmarit[0]);
+		sem_post(&semmarit[1]);
+
+	}
+	if (i == 1000)
+		atf_tc_fail("sem destroy not reporting EBUSY");
+}
+
+ATF_TC(named);
+ATF_TC_HEAD(named, tc)
+{
+
+	atf_tc_set_md_var(tc, "descr", "tests named semaphores (%s)", LIBNAME);
+}
+
+/*
+ * Wow, easy naming rules.  it's these times i'm really happy i can
+ * single-step into the kernel.
+ */
+#define SEM1 "/my_precious_sem"
+#define SEM2 "/justsem"
+ATF_TC_BODY(named, tc)
+{
+	sem_t *sem1, *sem2;
+	void *rv;
+
+	rump_init();
+	sem1 = sem_open(SEM1, 0);
+	ATF_REQUIRE_EQ(errno, ENOENT);
+	ATF_REQUIRE_EQ(sem1, NULL);
+
+	sem1 = sem_open(SEM1, O_CREAT, 0444, 1);
+	if (sem1 == NULL)
+		atf_tc_fail_errno("sem_open O_CREAT");
+
+	rv = sem_open(SEM1, O_CREAT | O_EXCL);
+	ATF_REQUIRE_EQ(errno, EEXIST);
+	ATF_REQUIRE_EQ(rv, NULL);
+
+	sem2 = sem_open(SEM2, O_CREAT, 0444, 0);
+	if (sem2 == NULL)
+		atf_tc_fail_errno("sem_open O_CREAT");
+
+	/* check that semaphores are independent */
+	ATF_REQUIRE_EQ(sem_trywait(sem2), -1);
+	ATF_REQUIRE_EQ(sem_trywait(sem1), 0);
+	ATF_REQUIRE_EQ(sem_trywait(sem1), -1);
+
+	/* check that unlinked remains valid */
+	sem_unlink(SEM2);
+	ATF_REQUIRE_EQ(sem_post(sem2), 0);
+	ATF_REQUIRE_EQ(sem_trywait(sem2), 0);
+	ATF_REQUIRE_EQ(sem_trywait(sem2), -1);
+	ATF_REQUIRE_EQ(errno, EAGAIN);
+
+#if 0 /* see unlink */
+	/* close it and check that it's gone */
+	if (sem_close(sem2) != 0)
+		atf_tc_fail_errno("sem close");
+	ATF_REQUIRE_EQ(sem_trywait(sem2), -1);
+	ATF_REQUIRE_EQ(errno, EINVAL);
+#endif
+
+	/* check that we still have sem1 */
+	sem_post(sem1);
+	ATF_REQUIRE_EQ(sem_trywait(sem1), 0);
+	ATF_REQUIRE_EQ(sem_trywait(sem1), -1);
+	ATF_REQUIRE_EQ(errno, EAGAIN);
+}
+
+ATF_TC(unlink);
+ATF_TC_HEAD(unlink, tc)
+{
+
+	/* this is currently broken.  i'll append the PR number soon */
+	atf_tc_set_md_var(tc, "descr", "tests unlinked semaphores are valid "
+	    "and can be closed (%s)", LIBNAME);
+}
+
+#define SEM "/thesem"
+ATF_TC_BODY(unlink, tc)
+{
+	sem_t *sem;
+
+	rump_init();
+	sem = sem_open(SEM, O_CREAT, 0444, 0);
+	ATF_REQUIRE(sem);
+
+	if (sem_unlink(SEM) == -1)
+		atf_tc_fail_errno("unlink");
+	if (sem_close(sem) == -1)
+		atf_tc_fail_errno("close unlinked semaphore");
+}
+
+/* use rump calls for libpthread _ksem_foo() calls */
+#define F1(name, a) int _ksem_##name(a); \
+int _ksem_##name(a v1) {return rump_sys__ksem_##name(v1);}
+#define F2(name, a, b) int _ksem_##name(a, b); \
+int _ksem_##name(a v1, b v2) {return rump_sys__ksem_##name(v1, v2);}
+F2(init, unsigned int, intptr_t *);
+F1(close, intptr_t);
+F1(destroy, intptr_t);
+F1(post, intptr_t);
+F1(unlink, const char *);
+F1(trywait, intptr_t);
+F1(wait, intptr_t);
+F2(getvalue, intptr_t, unsigned int *);
+int _ksem_open(const char *, int, mode_t, unsigned int, intptr_t *);
+int _ksem_open(const char *a, int b, mode_t c, unsigned int d, intptr_t *e)
+    {return rump_sys__ksem_open(a,b,c,d,e);}

Index: src/tests/lib/semaphore/pthread/Atffile
diff -u /dev/null src/tests/lib/semaphore/pthread/Atffile:1.1
--- /dev/null	Thu Jun 10 22:03:44 2010
+++ src/tests/lib/semaphore/pthread/Atffile	Thu Jun 10 22:03:43 2010
@@ -0,0 +1,6 @@
+Content-Type: application/X-atf-atffile; version="1"
+X-NetBSD-Id: "$NetBSD: Atffile,v 1.1 2010/06/10 22:03:43 pooka Exp $"
+
+prop: test-suite = "NetBSD"
+
+tp-glob: t_*
Index: src/tests/lib/semaphore/pthread/Makefile
diff -u /dev/null src/tests/lib/semaphore/pthread/Makefile:1.1
--- /dev/null	Thu Jun 10 22:03:44 2010
+++ src/tests/lib/semaphore/pthread/Makefile	Thu Jun 10 22:03:43 2010
@@ -0,0 +1,15 @@
+# $NetBSD: Makefile,v 1.1 2010/06/10 22:03:43 pooka Exp $
+
+.include <bsd.own.mk>
+
+TESTSDIR=	${TESTSBASE}/lib/semaphore/pthread
+
+TESTS_C=	t_sem_pth
+
+CPPFLAGS+=	-I${.CURDIR}/..
+
+LDADD+=		-lrumpkern_ksem -lrump -lrumpuser -lpthread
+
+WARNS=	4
+
+.include <bsd.test.mk>
Index: src/tests/lib/semaphore/pthread/t_sem_pth.c
diff -u /dev/null src/tests/lib/semaphore/pthread/t_sem_pth.c:1.1
--- /dev/null	Thu Jun 10 22:03:44 2010
+++ src/tests/lib/semaphore/pthread/t_sem_pth.c	Thu Jun 10 22:03:43 2010
@@ -0,0 +1,16 @@
+#define LIBNAME "pthread"
+#include "sem.c"
+
+ATF_TP_ADD_TCS(tp)
+{
+
+	ATF_TP_ADD_TC(tp, postwait);
+	ATF_TP_ADD_TC(tp, initvalue);
+	ATF_TP_ADD_TC(tp, destroy);
+	ATF_TP_ADD_TC(tp, busydestroy);
+	ATF_TP_ADD_TC(tp, blockwait);
+	ATF_TP_ADD_TC(tp, named);
+	ATF_TP_ADD_TC(tp, unlink);
+
+	return atf_no_error();
+}

Reply via email to