 11be35a165
			
		
	
	
		11be35a165
		
	
	
	
	
		
			
			To do so, a few dependencies have been imported: * external/bsd/lutok * external/mit/lua * external/public-domain/sqlite * external/public-domain/xz The Kyua framework is the new generation of ATF (Automated Test Framework), it is composed of: * external/bsd/atf * external/bsd/kyua-atf-compat * external/bsd/kyua-cli * external/bsd/kyua-tester * tests Kyua/ATF being written in C++, it depends on libstdc++ which is provided by GCC. As this is not part of the sources, Kyua is only compiled when the native GCC utils are installed. To install Kyua do the following: * In a cross-build enviromnent, add the following to the build.sh commandline: -V MKBINUTILS=yes -V MKGCCCMDS=yes WARNING: At this point the import is still experimental, and not supported on native builds (a.k.a make build). Change-Id: I26aee23c5bbd2d64adcb7c1beb98fe0d479d7ada
		
			
				
	
	
		
			333 lines
		
	
	
		
			6.9 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			333 lines
		
	
	
		
			6.9 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /*	$NetBSD: sem.c,v 1.10 2012/03/09 14:25:34 joerg 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]);
 | |
| 	}
 | |
| 
 | |
| 	return NULL;
 | |
| }
 | |
| 
 | |
| 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");
 | |
| 
 | |
| 	pthread_cancel(pt);
 | |
| 	pthread_join(pt, NULL);
 | |
| }
 | |
| 
 | |
| 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_set_md_var(tc, "timeout", "2");
 | |
| }
 | |
| 
 | |
| 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]);
 | |
| 
 | |
| 	}
 | |
| 
 | |
| 	pthread_cancel(pt);
 | |
| 	pthread_join(pt, NULL);
 | |
| }
 | |
| 
 | |
| ATF_TC(blocktimedwait);
 | |
| ATF_TC_HEAD(blocktimedwait, tc)
 | |
| {
 | |
| 
 | |
| 	atf_tc_set_md_var(tc, "descr", "tests sem_timedwait can handle blocking"
 | |
| 	    " (%s)", LIBNAME);
 | |
| 	atf_tc_set_md_var(tc, "timeout", "2");
 | |
| }
 | |
| 
 | |
| ATF_TC_BODY(blocktimedwait, tc)
 | |
| {
 | |
| 	sem_t semid;
 | |
| 	struct timespec tp;
 | |
| 
 | |
| 	rump_init();
 | |
| 
 | |
| 	clock_gettime(CLOCK_REALTIME, &tp);
 | |
| 	tp.tv_nsec += 50000000;
 | |
| 	tp.tv_sec += tp.tv_nsec / 1000000000;
 | |
| 	tp.tv_nsec %= 1000000000;
 | |
| 
 | |
| 	ATF_REQUIRE_EQ(sem_init(&semid, 1, 0), 0);
 | |
| 	ATF_REQUIRE_ERRNO(ETIMEDOUT, sem_timedwait(&semid, &tp) == -1);
 | |
| }
 | |
| 
 | |
| 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 "/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 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 *);
 | |
| F2(timedwait, intptr_t, const struct timespec *);
 | |
| 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);}
 |