diff options
| author | Sam Varshavchik | 2013-08-19 16:39:41 -0400 | 
|---|---|---|
| committer | Sam Varshavchik | 2013-08-25 14:43:51 -0400 | 
| commit | 9c45d9ad13fdf439d44d7443ae75da15ea0223ed (patch) | |
| tree | 7a81a04cb51efb078ee350859a64be2ebc6b8813 /threadlib | |
| parent | a9520698b770168d1f33d6301463bb70a19655ec (diff) | |
| download | courier-libs-9c45d9ad13fdf439d44d7443ae75da15ea0223ed.tar.bz2 | |
Initial checkin
Imported from subversion report, converted to git. Updated all paths in
scripts and makefiles, reflecting the new directory hierarchy.
Diffstat (limited to 'threadlib')
| -rw-r--r-- | threadlib/.gitignore | 2 | ||||
| -rw-r--r-- | threadlib/Makefile.am | 33 | ||||
| -rw-r--r-- | threadlib/configure.in | 84 | ||||
| -rw-r--r-- | threadlib/havepthread.h | 126 | ||||
| -rw-r--r-- | threadlib/nopthread.c | 48 | ||||
| -rw-r--r-- | threadlib/nopthread.h | 43 | ||||
| -rw-r--r-- | threadlib/pthread.c | 431 | ||||
| -rw-r--r-- | threadlib/test.c | 94 | ||||
| -rw-r--r-- | threadlib/testsuite | 4 | ||||
| -rw-r--r-- | threadlib/testsuite.txt | 40 | ||||
| -rw-r--r-- | threadlib/threadlib.h | 21 | 
11 files changed, 926 insertions, 0 deletions
| diff --git a/threadlib/.gitignore b/threadlib/.gitignore new file mode 100644 index 0000000..197552a --- /dev/null +++ b/threadlib/.gitignore @@ -0,0 +1,2 @@ +/libthread.dep +/threadtest diff --git a/threadlib/Makefile.am b/threadlib/Makefile.am new file mode 100644 index 0000000..1ff4301 --- /dev/null +++ b/threadlib/Makefile.am @@ -0,0 +1,33 @@ +# +# Copyright 2000-2002 Double Precision, Inc. +# See COPYING for distribution information. +# + + +noinst_LIBRARIES=libthreadlib.a +noinst_DATA=libthread.dep +noinst_PROGRAMS=threadtest + +CLEANFILES=libthread.dep + +if HAVE_PTHREADS +threadc=pthread.c +else +threadc=nopthread.c +endif + +libthreadlib_a_SOURCES=$(threadc) threadlib.h havepthread.h nopthread.h +EXTRA_DIST=pthread.c nopthread.c testsuite testsuite.txt + +libthread.dep: config.status +	echo @THREADLIB@ >libthread.dep + +threadtest_SOURCES=test.c +threadtest_DEPENDENCIES=libthreadlib.a libthread.dep +threadtest_LDADD=libthreadlib.a `cat libthread.dep` + +check-am: threadtest +	@echo '------------- Testing threadlib ---------------' +	@sh $(srcdir)/testsuite | tee t +	@cmp -s t $(srcdir)/testsuite.txt +	@rm -f t diff --git a/threadlib/configure.in b/threadlib/configure.in new file mode 100644 index 0000000..6962099 --- /dev/null +++ b/threadlib/configure.in @@ -0,0 +1,84 @@ +dnl Process this file with autoconf to produce a configure script. +AC_INIT(threadlib, 0.10, [courier-users@lists.sourceforge.net]) + +>confdefs.h  # Kill PACKAGE_ macros + +AC_CONFIG_SRCDIR(pthread.c) +AC_CONFIG_AUX_DIR(../..) +AM_INIT_AUTOMAKE([foreign no-define]) + +AM_CONFIG_HEADER(config.h) + +dnl Checks for programs. +AC_USE_SYSTEM_EXTENSIONS +AC_PROG_AWK +AC_PROG_INSTALL +AC_PROG_LN_S +AC_PROG_RANLIB +AC_PROG_CC + +dnl Checks for libraries. + +dnl Checks for header files. +AC_HEADER_STDC +AC_CHECK_HEADERS(unistd.h pthread.h) + +dnl Checks for typedefs, structures, and compiler characteristics. +AC_C_CONST + +dnl Checks for library functions. + +THREADLIB="" +save_LIBS="$LIBS" + +AC_CHECK_LIB(pthread, pthread_cond_wait, [ +	THREADLIB="-lpthread" ; LIBS="-lpthread $LIBS" ], [ + +LIBS="-pthread $save_LIBS" +AC_TRY_LINK([ +void pthread_cond_wait(); +],[ +	pthread_cond_wait(); +], +	THREADLIB="-pthread" +) +] +) + +LIBS="$THREADLIB $save_LIBS" + +have_pthreads=no + +AC_CHECK_HEADER(pthread.h, [ +	AC_CHECK_FUNC(pthread_cond_wait, have_pthreads=yes) +] +) + +LIBS="$save_LIBS" + +AC_ARG_WITH(pthreads, [--without-pthreads        - do not use Posix threads ], +	if test "$withval" = "no" +	then +		have_pthreads=no +	fi +	) + +if test "$have_pthreads" = "no" +then +	THREADLIB="" +else +	AC_DEFINE_UNQUOTED(HAVE_PTHREADS,1, +		[ Whether pthreads are available ]) +fi + +AM_CONDITIONAL(HAVE_PTHREADS, test "$have_pthreads" != "no") + +AC_SUBST(THREADLIB) + +AC_CHECK_LIB(m, sqrt) + +if test "$GCC" = "yes" +then +	CFLAGS="-Wall $CFLAGS" +fi +AC_OUTPUT(Makefile) diff --git a/threadlib/havepthread.h b/threadlib/havepthread.h new file mode 100644 index 0000000..74e7baa --- /dev/null +++ b/threadlib/havepthread.h @@ -0,0 +1,126 @@ +#ifndef	havepthread_h +#define	havepthread_h + +/* +** Copyright 2000 Double Precision, Inc.  See COPYING for +** distribution information. +*/ + + +#if	HAVE_CONFIG_H +#include	"config.h" +#endif + +/* + +This library encapsulates Posix threads in such a fashion as to be +able to transparently emulate the encapsulation if Posix threads are +not available. + +That is, the caller simply implements the documented interface, and if Posix +threads are not available, this library will provide stub functions that will +implement a functional equivalent (although probably a far less efficient +one). + +The interface implement by this library is as follows: + +* A function is defined which will be executed by multiple threads in parallel. + +* When this function returns, another 'cleanup' function will be called, except +  that this cleanup function will be single-threaded. + +  In fact, the cleanup function may be executed by any thread.  All this is +  is when the main function, the work function, completes, a mutex is locked +  for the duration of the cleanup function call. + +* The work function, and the cleanup function, can make use of some amount of +  metadata that can be initialized before starting the threaded function. + +The general concept is that you have some section of code that can benefit +from being threaded.  So, it is threaded, and the execution resumes in +single-step function once the threaded section of the code completes. + +*/ + +struct cthreadinfo *cthread_init( +	unsigned,		/* Number of threads */ +	unsigned,		/* Size of per-thread metadata */ +	void (*)(void *),	/* The work function */ +	void (*)(void *));	/* The cleanup function */ + +/* + +cthread_init is used to initialize and start all threads.  cthread_init returns +NULL if there was an error in setting up threading.  The first argument +specifies the number of threads to start.  The second argument specifies how +many bytes are there in per-thread metadata.  cthread_init will automatically +allocate nthreads*metasize bytes internally.  The third argument is a pointer +to the threaded function.  The fourth argument is a pointer to the cleanup +function. + +cthread_init returns a handle pointer if threading has been succesfully +set up. + +*/ + +void cthread_wait(struct cthreadinfo *); + +/* + +cthread_wait pauses until all current active threads have finished.  If there +are any threads which are currently busy executed the work function or the +cleanup function, cthread_wait pauses until they're done.  Then, cthread_wait +kills all the threads, and deallocates all allocated resources for the +handle + +*/ + +int cthread_go( struct cthreadinfo *,		/* Handle */ + +	void (*)(void *, void *),	/* Initialization function */ +	void *);	/* Second arg to the initialization func */ + +/* + +cthread_go finds an unused thread, and has it execute the work function, then +the cleanup function. + +Both the work function and the cleanup function receive a pointer to the +thread-specific metadata.  The second argument to cthread_go points to a +function that will be used to initialize the thread-specific metadata before +running the work function.  The first argument to this initialization function +will be a pointer to the thread-specific metadata, which is stored internally +by this library (associated with the handle).  When the initialization +function returns, the work/cleanup functions are called with the same pointer. +The third argument to cthread_go is passed as the second argument to the +initialization function. + +If there are no available threads, cthread_go pauses until one becomes +available.  cthread_go returns immediately after starting the thread, so +upon return from cthread_go the work and cleanup functions are NOT guaranteed +to have been called already.  cthread_go merely starts the thread, which will +execute the work and the cleanup functions concurrently. + +When Posix threads are not available, cthread_go is a stub.  It calls the +initialization function, then the work function, then the cleanup function, +and then returns to the caller.  Hopefully, these semantics will be sufficient +to carry out the necessary deed if threading is not available. +*/ + +/* + +cthreadlock structure is used to implement locks.  Create a lock by calling +cthread_lockcreate.  Destroy a lock by calling cthread_lockdelete. + +Calling cthread_lock obtains the lock specified by the first argument, calls +the function specified by the second argument.  When the function returns, +the lock is released.  The third argument is passed as the argument to the +function. + +*/ + +struct cthreadlock *cthread_lockcreate(void); +void cthread_lockdestroy(struct cthreadlock *); +int cthread_lock(struct cthreadlock *, int (*)(void *), void *); + +#endif diff --git a/threadlib/nopthread.c b/threadlib/nopthread.c new file mode 100644 index 0000000..59cea13 --- /dev/null +++ b/threadlib/nopthread.c @@ -0,0 +1,48 @@ +/* +** Copyright 2000-2001 Double Precision, Inc.  See COPYING for +** distribution information. +*/ + + +#include	"threadlib.h" + +#include	<stdio.h> +#include	<errno.h> +#include	<stdlib.h> +#include	<unistd.h> + +typedef struct cthreadinfo cthreadinfo_t; + + +cthreadinfo_t *cthread_init(unsigned nthreads_, unsigned metasize, +	void (*workfunc_)(void *), +	void (*cleanupfunc_)(void *)) +{ +cthreadinfo_t *cit; + +	if ((cit=(cthreadinfo_t *)malloc(sizeof(cthreadinfo_t))) == 0) +		return (0); + +	cit->cleanupfunc=cleanupfunc_; +	cit->workfunc=workfunc_; + +	if ( (cit->metadata_buf=malloc(metasize)) == 0) +	{ +		free( (char *)cit ); +		return (0); +	} +	return (cit); +} + +void cthread_wait(cthreadinfo_t *cit) +{ +	free(cit->metadata_buf); +	free( (char *)cit); +} + + +struct cthreadlock { +	int dummy; +	} ; + +struct cthreadlock cthread_dummy; diff --git a/threadlib/nopthread.h b/threadlib/nopthread.h new file mode 100644 index 0000000..e3c8680 --- /dev/null +++ b/threadlib/nopthread.h @@ -0,0 +1,43 @@ +#ifndef	nopthread_h +#define	nopthread_h + +/* +** Copyright 2000 Double Precision, Inc.  See COPYING for +** distribution information. +*/ + + +#if	HAVE_CONFIG_H +#include	"config.h" +#endif + +struct cthreadinfo { +	void (*workfunc)(void *); +	void (*cleanupfunc)(void *); +	char *metadata_buf; +	} ; + +struct cthreadinfo *cthread_init( +	unsigned,		/* Number of threads */ +	unsigned,		/* Size of per-thread metadata */ +	void (*)(void *),	/* The work function */ +	void (*)(void *));	/* The cleanup function */ + +void cthread_wait(struct cthreadinfo *); + +#define	cthread_go(cit, gofunc, arg)	\ +	( (*gofunc)(cit->metadata_buf, arg),	\ +		(*cit->workfunc)(cit->metadata_buf), \ +		(*cit->cleanupfunc)(cit->metadata_buf), 0) + +struct cthreadlock *cthread_lockcreate(void); +void cthread_lockdestroy(struct cthreadlock *); +int cthread_lock(struct cthreadlock *, int (*)(void *), void *); + +extern struct cthreadlock cthread_dummy; + +#define	cthread_lockcreate()	( &cthread_dummy ) +#define	cthread_lockdestroy(p) +#define	cthread_lock(p,func,arg)	( (*func)(arg)) + +#endif diff --git a/threadlib/pthread.c b/threadlib/pthread.c new file mode 100644 index 0000000..c0d414c --- /dev/null +++ b/threadlib/pthread.c @@ -0,0 +1,431 @@ +/* +** Copyright 2000-2007 Double Precision, Inc.  See COPYING for +** distribution information. +*/ + + +#include	"threadlib.h" + +#include	<pthread.h> +#include	<stdio.h> +#include	<errno.h> +#include	<stdlib.h> +#include	<unistd.h> + +typedef struct { +	unsigned	me; +	pthread_t	pt; + +	pthread_cond_t	gocond; +	pthread_mutex_t	gomutex; +	int		goflag; + +	struct		cthreadinfo *myinfo; + +	void		*metadata; +	} cthread_t; + +struct cthreadinfo { +	unsigned nthreads; +	void (*workfunc)(void *); +	void (*cleanupfunc)(void *); +	cthread_t *threads; +	char *metadata_buf; +	int *newbuf; +	int newcnt; + +	pthread_cond_t	newtask_cond; +	pthread_mutex_t	newtask_mutex; + +	pthread_mutex_t	cleanup_mutex; +	} ; + +typedef struct cthreadinfo cthreadinfo_t; + +static void mutexcleanup(void *vp) +{ +pthread_mutex_t *mp=(pthread_mutex_t *)vp; + +	pthread_mutex_unlock( mp ); +} + +#define PTHREAD_CHK(x) (errno=(x)) + +/* +**  This is the thread function wrapper.  It waits for its conditional +**  signal, runs the workhorse function, then puts its task id onto the ready +**  queue, then goes back to waiting for another go signal. +*/ + +static void *threadfunc(void *p) +{ +cthread_t	*c= (cthread_t *)p; +cthreadinfo_t	*i= c->myinfo; + +	for (;;) +	{ +		while (PTHREAD_CHK(pthread_mutex_lock(&c->gomutex))) +		{ +			perror("pthread_mutex_lock"); +			sleep(3); +		} + +		pthread_cleanup_push(&mutexcleanup, (void *)&c->gomutex); + +		while (!c->goflag) +		{ +			if (PTHREAD_CHK(pthread_cond_wait(&c->gocond, +							  &c->gomutex))) +			{ +				perror("pthread_cond_wait"); +				sleep(3); +			} +		} +		c->goflag=0; +		if (PTHREAD_CHK(pthread_mutex_unlock( &c->gomutex ))) +			perror("pthread_mutex_unlock"); + +		pthread_cleanup_pop(0); + +		(*i->workfunc)(c->metadata); + +		while (PTHREAD_CHK(pthread_mutex_lock(&i->cleanup_mutex))) +		{ +			perror("pthread_mutex_lock"); +			sleep(3); +		} + +		pthread_cleanup_push(&mutexcleanup, (void *)&i->cleanup_mutex); + +		(*i->cleanupfunc)(c->metadata); + +		if (PTHREAD_CHK(pthread_mutex_unlock( &i->cleanup_mutex ))) +			perror("pthread_mutex_unlock"); + +		pthread_cleanup_pop(0); + +		while (PTHREAD_CHK(pthread_mutex_lock(&i->newtask_mutex))) +		{ +			perror("pthread_mutex_lock"); +			sleep(3); +		} + +		i->newbuf[i->newcnt++] = c->me; + +		if (PTHREAD_CHK(pthread_mutex_unlock( &i->newtask_mutex ))) +			perror("pthread_mutex_unlock"); + +		if (PTHREAD_CHK(pthread_cond_signal( &i->newtask_cond ))) +			perror("pthread_cond_signal"); +	} +} + +static int initcondmutex(pthread_cond_t *c, pthread_mutex_t *m) +{ +pthread_condattr_t cattr; +pthread_mutexattr_t mattr; + +	if (c) +	{ +		if ( PTHREAD_CHK(pthread_condattr_init(&cattr))) return (-1); +		if ( PTHREAD_CHK(pthread_cond_init(c, &cattr))) +		{ +			pthread_condattr_destroy(&cattr); +			return (-1); +		} +		pthread_condattr_destroy(&cattr); +	} + +	if ( PTHREAD_CHK(pthread_mutexattr_init(&mattr))) +	{ +		if (c) pthread_cond_destroy(c); +		return (-1); +	} + +	if ( PTHREAD_CHK(pthread_mutex_init(m, &mattr))) +	{ +		pthread_mutexattr_destroy(&mattr); + +		if (c) pthread_cond_destroy(c); +		return (-1); +	} +	pthread_mutexattr_destroy(&mattr); +	return (0); +} + +cthreadinfo_t *cthread_init(unsigned nthreads_, unsigned metasize, +	void (*workfunc_)(void *), +	void (*cleanupfunc_)(void *)) +{ +unsigned i; +pthread_attr_t	pat; +cthreadinfo_t *cit; + +	if ((cit=(cthreadinfo_t *)malloc(sizeof(cthreadinfo_t))) == 0) +		return (0); + +	cit->nthreads=nthreads_; +	cit->cleanupfunc=cleanupfunc_; +	cit->workfunc=workfunc_; +	if ( (cit->threads=(cthread_t *)malloc(cit->nthreads * sizeof(cthread_t))) == 0) +	{ +		free((char *)cit); +		return (0); +	} +	if ( (cit->metadata_buf=malloc(metasize * cit->nthreads)) == 0) +	{ +		free( (char *)cit->threads); +		free( (char *)cit ); +		return (0); +	} + +	cit->newcnt=cit->nthreads; +	if ( (cit->newbuf=(int *)malloc(cit->nthreads * sizeof(int))) == 0) +	{ +		free(cit->metadata_buf); +		free( (char *)cit->threads); +		free( (char *)cit ); +		return (0); +	} +	for (i=0; i<cit->nthreads; i++) +	{ +		cit->newbuf[i]=i; +	} + +	if (initcondmutex(&cit->newtask_cond, &cit->newtask_mutex)) +	{ +		free(cit->newbuf); +		free(cit->metadata_buf); +		free( (char *)cit->threads); +		free( (char *)cit ); +		return (0); +	} + +	if (initcondmutex(0, &cit->cleanup_mutex)) +	{ +		pthread_cond_destroy(&cit->newtask_cond); +		pthread_mutex_destroy(&cit->newtask_mutex); + +		free(cit->newbuf); +		free(cit->metadata_buf); +		free( (char *)cit->threads); +		free( (char *)cit ); +		return (0); +	} + +	if (PTHREAD_CHK(pthread_attr_init(&pat))) +	{ +		pthread_mutex_destroy(&cit->cleanup_mutex); +		pthread_cond_destroy(&cit->newtask_cond); +		pthread_mutex_destroy(&cit->newtask_mutex); +		free(cit->newbuf); +		free(cit->metadata_buf); +		free( (char *)cit->threads); +		free( (char *)cit ); +		return (0); +	} + +	for (i=0; i<cit->nthreads; i++) +	{ +		cit->threads[i].me=i; +		cit->threads[i].metadata=(void *) (cit->metadata_buf+i*metasize); +		cit->threads[i].myinfo=cit; + +		if (initcondmutex(&cit->threads[i].gocond, +			&cit->threads[i].gomutex)) +			break; + +		cit->threads[i].goflag=0; + +		if (PTHREAD_CHK(pthread_create(&cit->threads[i].pt, &pat, +					       &threadfunc, +					       (void *)&cit->threads[i]))) +		{ +			pthread_cond_destroy(&cit->threads[i].gocond); +			pthread_mutex_destroy(&cit->threads[i].gomutex); +			break; +		} +	} + +	if ( i >= cit->nthreads) +	{ +		pthread_attr_destroy(&pat); +		return (cit); +	} + +	while (i) +	{ +		--i; +		if (PTHREAD_CHK(pthread_cancel(cit->threads[i].pt))) +			perror("pthread_cancel"); +		 +		if (PTHREAD_CHK(pthread_join(cit->threads[i].pt, NULL))) +			perror("pthread_join"); + +		pthread_cond_destroy(&cit->threads[i].gocond); +		pthread_mutex_destroy(&cit->threads[i].gomutex); +	} + +	pthread_attr_destroy(&pat); +	pthread_mutex_destroy(&cit->cleanup_mutex); +	pthread_cond_destroy(&cit->newtask_cond); +	pthread_mutex_destroy(&cit->newtask_mutex); +	free(cit->newbuf); +	free(cit->metadata_buf); +	free( (char *)cit->threads); +	free( (char *)cit ); +	return (0); +} + +void cthread_wait(cthreadinfo_t *cit) +{ +	unsigned i; + +	if (PTHREAD_CHK(pthread_mutex_lock(&cit->newtask_mutex))) +	{ +		perror("pthread_mutex_lock"); +		return; +	} + +	pthread_cleanup_push(&mutexcleanup, (void *)&cit->newtask_mutex); + +	while (cit->newcnt < cit->nthreads) +	{ +		if (PTHREAD_CHK(pthread_cond_wait(&cit->newtask_cond, +						  &cit->newtask_mutex))) +		{ +			perror("pthread_cond_wait"); +			sleep(3); +		} +	} + +	if (PTHREAD_CHK(pthread_mutex_unlock(&cit->newtask_mutex))) +		perror("pthread_mutex_unlock"); + +	pthread_cleanup_pop(0); + +	for (i=0; i<cit->nthreads; i++) +	{ +		if (PTHREAD_CHK(pthread_cancel(cit->threads[i].pt) )) +			perror("pthread_cancel"); + +		if (PTHREAD_CHK(pthread_join(cit->threads[i].pt, NULL))) +			perror("pthread_join"); + +		if (PTHREAD_CHK(pthread_cond_destroy(&cit->threads[i].gocond))) +			perror("pthread_cond_destroy(gocond)"); + +		if (PTHREAD_CHK(pthread_mutex_destroy(&cit->threads[i] +						      .gomutex))) +			perror("pthread_mutex_destroy"); +	} + +	if (PTHREAD_CHK(pthread_mutex_destroy(&cit->cleanup_mutex))) +		perror("pthread_mutex_destroy"); + +	if (PTHREAD_CHK(pthread_cond_destroy(&cit->newtask_cond))) +		perror("pthread_cond_destroy(newtask_cond)"); + +	if (PTHREAD_CHK(pthread_mutex_destroy(&cit->newtask_mutex))) +		perror("pthread_mutex_destroy"); +	free(cit->newbuf); +	free(cit->metadata_buf); +	free( (char *)cit->threads); +	free( (char *)cit); +} + +int cthread_go( cthreadinfo_t *cit, void (*gofunc)(void *, void *), void *arg) +{ +	int	n=0; +	int	err=0; + +	if (PTHREAD_CHK(pthread_mutex_lock(&cit->newtask_mutex))) +		return (-1); + +	pthread_cleanup_push(&mutexcleanup, (void *)&cit->newtask_mutex); + +	while (cit->newcnt == 0) +	{ +		if (PTHREAD_CHK(pthread_cond_wait(&cit->newtask_cond, +						  &cit->newtask_mutex))) +		{ +			err=1; +			break; +		} +	} + +	if (!err) +		n=cit->newbuf[ --cit->newcnt ]; + +	if (PTHREAD_CHK(pthread_mutex_unlock(&cit->newtask_mutex))) +		err=1; + +	pthread_cleanup_pop(0); +	if (err)	return (-1); + +	(*gofunc)( cit->threads[n].metadata, arg); + +	if (PTHREAD_CHK(pthread_mutex_lock(&cit->threads[n].gomutex))) +		return (-1); +	cit->threads[n].goflag=1; +	if (PTHREAD_CHK(pthread_mutex_unlock(&cit->threads[n].gomutex))) +		return (-1); +	if (PTHREAD_CHK(pthread_cond_signal( &cit->threads[n].gocond ))) +		return (-1); +	return (0); +} + +struct cthreadlock { +	pthread_mutex_t	mutex; +	} ; + +struct cthreadlock *cthread_lockcreate(void) +{ +struct cthreadlock *p= (struct cthreadlock *)malloc(sizeof(struct cthreadlock)); +pthread_mutexattr_t mattr; + +	if (!p)	return (0); + +	if (PTHREAD_CHK(pthread_mutexattr_init(&mattr))) +	{ +		errno=EIO; +		free( (char *)p ); +		return (0); +	} + +	if (PTHREAD_CHK(pthread_mutex_init(&p->mutex, &mattr))) +	{ +		pthread_mutexattr_destroy(&mattr); +		errno=EIO; +		free( (char *)p ); +		return (0); +	} +	pthread_mutexattr_destroy(&mattr); +	return (p); +} + +void cthread_lockdestroy(struct cthreadlock *p) +{ +	pthread_mutex_destroy(&p->mutex); +	free( (char *)p ); +} + +int cthread_lock(struct cthreadlock *p, int (*func)(void *), void *arg) +{ +int	rc; + +	while (pthread_mutex_lock(&p->mutex)) +	{ +		perror("pthread_mutex_lock"); +		sleep(3); +	} + +	pthread_cleanup_push(&mutexcleanup, (void *)&p->mutex); + +	rc= (*func)(arg); + +	if (PTHREAD_CHK(pthread_mutex_unlock( &p->mutex ))) +		perror("pthread_mutex_unlock"); +	pthread_cleanup_pop(0); +	return (rc); +} diff --git a/threadlib/test.c b/threadlib/test.c new file mode 100644 index 0000000..9857832 --- /dev/null +++ b/threadlib/test.c @@ -0,0 +1,94 @@ +/* +** Copyright 2000 Double Precision, Inc.  See COPYING for +** distribution information. +*/ + + +#include	"config.h" +#include	<stdio.h> +#include	<stdlib.h> +#include	<math.h> +#include	<errno.h> +#include	<time.h> +#include	"threadlib.h" + +static double buf[100]; +static int bufcnt=0; +static unsigned ndelay=0; + +static void workfunc(void *p) +{ +double *dp= (double *)p; +time_t	t1, t2; + +	*dp=sqrt( *dp ); + +	time(&t1); +	while ( time(&t2) < t1 + ndelay) +		; +} + +static void cleanupfunc(void *p) +{ +double *dp= (double *)p; + +	buf[bufcnt++]= *dp; +} + +static void getwork(void *p, void *q) +{ +double *dp= (double *)p; +double *qp= (double *)q; + +	*dp= *qp; +} + +static int cmpdbl (const void *a, const void *b) +{ +const double *pa=(const double *)a; +const double *pb=(const double *)b; + +	return (*pa < *pb ? -1: *pa > *pb ? 1:0); +} + +int main(int argc, char **argv) +{ +double n; +struct cthreadinfo *cit; +int	i, j; + +	if (argc < 2)	return (1); + +	j=atoi(argv[1]); +	if (argc > 2) +		ndelay=atoi(argv[2]); + +	if (j <= 0 || j > sizeof(buf)/sizeof(buf[0]))	return (1); + +	if ( (cit=cthread_init(2, sizeof(double), workfunc, cleanupfunc)) == 0) +	{ +		perror("cthread_init"); +		return (1); +	} + +	for (i=0; i<j; i++) +	{ +		n= i+1; + +		if (cthread_go(cit, getwork, &n)) +		{ +			perror("cthread_go"); +			return (1); +		} +		printf ("Started %d\n", i+1); +	} +	cthread_wait(cit); + +	qsort(buf, bufcnt, sizeof(buf[0]), &cmpdbl); + +	for (i=0; i<bufcnt; i++) +	{ +		printf("%6.2f\n", buf[i]); +	} +	return (0); +} diff --git a/threadlib/testsuite b/threadlib/testsuite new file mode 100644 index 0000000..fd9a413 --- /dev/null +++ b/threadlib/testsuite @@ -0,0 +1,4 @@ +#!/bin/sh + +./threadtest 16 2>&1 +./threadtest 4 2 2>&1 diff --git a/threadlib/testsuite.txt b/threadlib/testsuite.txt new file mode 100644 index 0000000..59ea021 --- /dev/null +++ b/threadlib/testsuite.txt @@ -0,0 +1,40 @@ +Started 1 +Started 2 +Started 3 +Started 4 +Started 5 +Started 6 +Started 7 +Started 8 +Started 9 +Started 10 +Started 11 +Started 12 +Started 13 +Started 14 +Started 15 +Started 16 +  1.00 +  1.41 +  1.73 +  2.00 +  2.24 +  2.45 +  2.65 +  2.83 +  3.00 +  3.16 +  3.32 +  3.46 +  3.61 +  3.74 +  3.87 +  4.00 +Started 1 +Started 2 +Started 3 +Started 4 +  1.00 +  1.41 +  1.73 +  2.00 diff --git a/threadlib/threadlib.h b/threadlib/threadlib.h new file mode 100644 index 0000000..697ba18 --- /dev/null +++ b/threadlib/threadlib.h @@ -0,0 +1,21 @@ +#ifndef	threadlib_h +#define	threadlib_h + +/* +** Copyright 2000 Double Precision, Inc.  See COPYING for +** distribution information. +*/ + + +#include	"config.h" + +struct cthreadinfo; +struct cthreadlock; + +#if	HAVE_PTHREADS +#include	"havepthread.h" +#else +#include	"nopthread.h" +#endif + +#endif | 
