archie/prospero/include/pfs_threads.h
2024-05-27 16:13:40 +02:00

454 lines
16 KiB
C

/*
* Copyright (c) 1993-1994 by the University of Southern California
*
* For copying and distribution information, please see the file
* <usc-license.h>.
*/
#include <usc-license.h>
/* This is the Prospero interface to threads. This threads package
is currently used exclusively by the Prospero server when it is operating in
multi-threaded mode.
At the moment, this stuff is experimental. It will only be tested on the
server side, not on the client.
*/
/*
* The interface to the Prospero server's use of threads is fully defined in
* this file. That means that as long as you provide the external interface
* herein defined, you're OK. */
/* This interface does not currently attempt to handle issues of cancelling
* threads, although that will be a later extension.
*/
/* Every thread (on the server) has an active RREQ associated with it. Every
* active RREQ has a live thread associated with it. RREQs get moved off of
* the queue of items to be processed to the list of items in progress when an
* available thread is there for them. When a thread is available,
* ardp_accept() is called.
*/
#ifndef PFS_THREADS_H
#define PFS_THREADS_H
#include <stdio.h> /* needed for FILE */
/* #define P_MAX_NUM_THREADS here if you want any threads, and PFS_THREADS. */
/*#define PFS_THREADS */ /* Part of the external interface. */
#ifdef PFS_THREADS
#define P_MAX_NUM_THREADS 61 /* This will define threads 0 through 60,
quite a lot. */
/* You can easily set a lower value for the number of threads the server
* will actually use, by modifying DIRSRV_SUB_THREAD_COUNT in dirsrv.c.
*/
#define PFS_THREADS_HAVE_SAFE_MALLOC /* Version */
/* Define which PFS_THREADS package you have, options supported currently
include PFS_THREADS_SOLARIS or PFS_THREADS_FLORIDA - note NONE
of these must be defined if PFS_THREADS is undefined */
/* #define PFS_THREADS_SOLARIS */
#endif /* PFS_THREADS */
#include <pfs_utils.h> /* assert */
/* To port to a new threads package
- pick an identifer (e.g. PFS_THREADS_DCE).
-- Note PFS_THREADS_POSIX is reservered for post-balloting implementation
-- Tell prospero-developers@isi.edu which you are using.
- Grep through all of the source for instances of PFS_THREADS_
-- Editing these is documented where they apply
-- This will include lib/ardp/p_th_self_num server/dirsrv
*/
#ifdef PFS_THREADS_FLORIDA
/* pthread.h is the include file from the Florida State University
PART project PTHREADS distribution.
It prototypes all of the functions and interfaces whose names start with
pthread_.
*/
#include <pthread.h>
#endif /* PFS_THREADS_FLORIDA */
#ifdef PFS_THREADS_SOLARIS
/* Make sure we get our signal.h with _POSIX_C_SOURCE before thread.h
includes sys/signal.h */
#include <posix_signal.h>
/* Thread.h prototypes most functions starting thr_ */
#include <thread.h>
#endif /* PFS_THREADS_SOLARIS */
#ifdef PFS_THREADS
/* Yield a unique integer between 0 and P_MAX_NUM_THREADS - 1 for the current
thread. Hopefully this function will go away eventually as the server's
internal structure changes in a way that a reference to the current thread
is passed around to all subfunctions. But maybe not, too.
This is implemented using the per-thread key mechanisms. */
extern void p_th_allocate_self_num(void); /* external; must be called by thread
after startup. */
extern void p_th_deallocate_self_num(void); /* external; must be called by
thread before exit. */
#endif /*PFS_THREADS*/
#ifdef PFS_THREADS
extern int p__th_self_num(void); /* not external interface. */
#else
#define p__th_self_num() 0
#endif /* PFS_THREADS */
/* We don't include a trailing ; at the end of our declarations and definitions
because a ; by itself in a declarations list is treated by C as a statement,
not as an empty declaration. This means that the AUTOSTAT declaration has to
be the last one. */
/* This declares an automatic variable name VARNAME of type char **. *VARNAME
will be a reference to a persistent per-thread static variable of type char
*, with function scope. Note that *varname will be initially NULL, but may
expand with time. Part of the external interface.*/
#ifdef PFS_THREADS
#define AUTOSTAT_CHARPP(VARNAME) \
static char *(VARNAME##_target[P_MAX_NUM_THREADS]); /* NULL by default. */\
char **VARNAME = (VARNAME##_target + p__th_self_num())
#else
#define AUTOSTAT_CHARPP(VARNAME) \
static char *VARNAME##_target = NULL; \
char **VARNAME = &VARNAME##_target
#endif /* PFS_THREADS */
/* ditto, for int* . Part of the external interface. */
#ifdef PFS_THREADS
#define AUTOSTAT_INTP(VARNAME) \
static int (VARNAME##_target[P_MAX_NUM_THREADS]); /* automatically 0 */\
int *VARNAME = (VARNAME##_target + p__th_self_num())
#else
#define AUTOSTAT_INTP(VARNAME) \
static int VARNAME##_target = 0; \
int *VARNAME = &VARNAME##_target
#endif /* PFS_THREADS */
/* ditto, for an arbitrary type* . Part of the external interface. */
#ifdef PFS_THREADS
#define AUTOSTAT_TYPEP(TYPE,VARNAME) \
static (TYPE) (VARNAME##_target[P_MAX_NUM_THREADS]); /* automatically 0 */\
(TYPE) *VARNAME = (VARNAME##_target + p__th_self_num())
#else
#define AUTOSTAT_TYPEP(TYPE,VARNAME) \
static (TYPE) VARNAME##_target = 0; \
(TYPE) *VARNAME = &VARNAME##_target
#endif /* PFS_THREADS */
#ifdef PFS_THREADS
#define AUTOSTATIC_VAR_INITIALIZED(TYPE,VARNAME,INITIALIZER) \
static TYPE (VARNAME##_target[P_MAX_NUM_THREADS]); /* automatically 0 */\
TYPE *VARNAME = (VARNAME##_target + p__th_self_num())
#else
#define AUTOSTATIC_VAR_INITIALIZED(VARNAME) \
static TYPE VARNAME##_target = 0; \
TYPE *VARNAME = &VARNAME##_target
#endif /* PFS_THREADS */
/* Possible alternative interface for a common case. I'm experimenting with
it. Experimental part of external interface. */
#if 1
#define SCRATCHBUF_CHARPP_DEF(VARNAME) AUTOSTAT_CHARPP(VARNAME)
/* Set using *VARNAME = or passing VARNAME as a pointer to the target. */
#define SCRATCHBUF_CHARPP_CLEANUP(VARNAME)
#else
/* This version of the interface will always allocate a new buffer upon
entry. It has the sole advantage that it does not leave static buffers
around. It has disadvantages too: presumably the many calls to malloc()
will not be an efficient way of using the processor. */
/* A good optimizing compiler should clean up the following (I hope). */
#define SCRATCHBUF_CHARPP_DEF(VARNAME) \
char * VARNAME##_target = NULL; \
char **VARNAME = &VARNAME##_target
/* Set using *VARNAME = or passing VARNAME as a pointer to the target. */
#define SCRATCHBUF_CHARPP_CLEANUP(VARNAME) do { \
stfree(*VARNAME); \
*VARNAME = NULL; \
} while(0)
#endif
/* The following abstraction is used for statics (per-file externs) and
real externs. */
/* Externs need separate declarations and data definitions. */
/* Each extern will need one of these after the declaration, to keep the old
stuff working. */
#ifdef PFS_THREADS
#define EXTERN_LONG_DECL(VARNAME) \
extern long p_th_ar##VARNAME[P_MAX_NUM_THREADS]
#define EXTERN_LONG_DEF(VARNAME) \
long p_th_ar##VARNAME[P_MAX_NUM_THREADS]
#define PERFILE_STATIC_LONG_DEF(VARNAME) \
static long p_th_ar##VARNAME[P_MAX_NUM_THREADS]
#define EXTERN_INT_DECL(VARNAME) \
extern int p_th_ar##VARNAME[P_MAX_NUM_THREADS]
#define EXTERN_INT_DEF(VARNAME) \
int p_th_ar##VARNAME[P_MAX_NUM_THREADS]
#define PERFILE_STATIC_INT_DEF(VARNAME) \
static int p_th_ar##VARNAME[P_MAX_NUM_THREADS]
#define EXTERN_CHARP_DECL(VARNAME) \
extern char * p_th_ar##VARNAME[P_MAX_NUM_THREADS]
#define EXTERN_CHARP_DEF(VARNAME) \
char * p_th_ar##VARNAME[P_MAX_NUM_THREADS]
#define PERFILE_STATIC_CHARP_DEF(VARNAME) \
static char * p_th_ar##VARNAME[P_MAX_NUM_THREADS]
#define EXTERN_TYPEP_DECL(TYPE,VARNAME) \
extern TYPE p_th_ar##VARNAME[P_MAX_NUM_THREADS]
#define EXTERN_TYPEP_DEF(TYPE,VARNAME) \
TYPE p_th_ar##VARNAME[P_MAX_NUM_THREADS]
#else
#define EXTERN_LONG_DECL(VARNAME) \
extern long p_th_ar##VARNAME[1]
#define EXTERN_LONG_DEF(VARNAME) \
long p_th_ar##VARNAME[1]
#define PERFILE_STATIC_LONG_DEF(VARNAME) \
static long p_th_ar##VARNAME[1]
#define EXTERN_INT_DECL(VARNAME) \
extern int p_th_ar##VARNAME[1]
#define EXTERN_INT_DEF(VARNAME) \
int p_th_ar##VARNAME[1]
#define PERFILE_STATIC_INT_DEF(VARNAME) \
static int p_th_ar##VARNAME[1]
#define EXTERN_CHARP_DECL(VARNAME) \
extern char * p_th_ar##VARNAME[1]
#define EXTERN_CHARP_DEF(VARNAME) \
char * p_th_ar##VARNAME[1]
#define PERFILE_STATIC_CHARP_DEF(VARNAME) \
static char * p_th_ar##VARNAME[1]
#define EXTERN_TYPEP_DECL(VARNAME) \
extern TYPE p_th_ar##VARNAME[1]
#define EXTERN_TYPEP_DEF(VARNAME) \
TYPE p_th_ar##VARNAME[1]
#endif /* PFS_THREADS */
/* In any case, follow definitions with a:
#define VARNAME p_th_arVARNAME[p__th_self_num()] */
#if 0 /* first attempt */
/* Externs need separate declarations and data definitions. */
#define EXTERN_INTP_DECL(VARNAMEP) extern int *VARNAMEP
/* Each extern will need one of these after the declaration, to keep the old
stuff working. */
/* #define VARNAME (*VARNAMEP) */
/* Definition. */
#define EXTERN_INTP_DEF(VARNAMEP) int *VARNAMEP
#endif /* #if 0 */
/* Mutexes,implemented on top of the pthreads package. */
/* p_th_mutex is an exported data type, used when we mutex functions or
collections of functions. See lib/ardp/ptalloc.c for an example of this.
*/
/*
Do so in init code, to keep
from depending on ONCE implementation. Again, this interface is only
called directly by Prospero and ARDP code when a set of functions need to be
mutexed; otherwise, the *_MUTEXED_* variable declaration and definition
interfaces below are used. */
#ifndef NDEBUG
#define zz(a) assert((a) == 0)
#else
#define zz(a) a
#endif
#if defined(PFS_THREADS) && !defined(NDEBUG)
#define DIAGMUTEX(MX1,MX2) if (p_th_mutex_islocked(&p_th_mutex##MX1 )) { printf(mutex_locked_msg,MX2); }
extern char mutex_locked_msg[];
#else
#define DIAGMUTEX(MX1,MX2) do { } while(0)
#endif
#ifdef PFS_THREADS_FLORIDA
typedef pthread_mutex_t p_th_mutex;
#define p_th_mutex_init(MUTEX) \
pthread_mutex_init(&(MUTEX), (pthread_mutexattr_t *) NULL)
#define p_th_mutex_lock(MUTEX) { pthread_mutex_lock(&(MUTEX)) }
#define p_th_mutex_unlock(MUTEX) pthread_mutex_unlock(&(MUTEX))
#define p_th_mutex_islocked(MUTEX) (pthread_mutex_trylock(&(MUTEX)) == -1)
#define p_th_mutex_trylock(MUTEX) \
( (p_th_mutex_trylock(&(MUTEX)) != -1) \
? p_th_mutex_lock(MUTEX) \
: TRUE )
#endif /*PFS_THREADS_FLORIDA*/
#ifdef PFS_THREADS_SOLARIS
typedef mutex_t p_th_mutex;
#define p_th_mutex_init(MUTEX) zz(mutex_init(&(MUTEX), USYNC_THREAD, NULL))
#define p_th_mutex_lock(MUTEX) zz(mutex_lock(&(MUTEX)))
#define p_th_mutex_unlock(MUTEX) zz(mutex_unlock(&(MUTEX)))
extern int p_th_mutex_islocked(mutex_t *mp);
#define p_th_mutex_trylock(MUTEX) (mutex_trylock(&(MUTEX)))
#endif /*PFS_THREADS_SOLARIS*/
#ifndef PFS_THREADS
#define p_th_mutex_init(MUTEX) do { } while(0)
#define p_th_mutex_lock(MUTEX) do { } while(0)
#define p_th_mutex_unlock(MUTEX) do { } while(0)
/* Used only in ardp_accept() */
#define p_th_mutex_islocked(MUTEX) 0
#define p_th_mutex_trylock(MUTEX) 0
#endif /*!PFS_THREADS*/
/* Handling of global shared variables (e.g., ardp_runQ) */
/* Mutex initialized in ardp_mutexes.c (ardp_init_mutexes()). */
/* Variable defined and declared as mutexed. */
#ifdef PFS_THREADS
#define EXTERN_MUTEX_DECL(VARNAME) \
extern p_th_mutex p_th_mutex##VARNAME
#define EXTERN_MUTEX_DEF(VARNAME) \
p_th_mutex p_th_mutex##VARNAME
/* Initialize the mutex (in ardp_init_mutexes(), pfs_init_mutexes(),
dirsrv_init_mutexes()) */
#define EXTERN_MUTEXED_INIT_MUTEX(VARNAME) \
p_th_mutex_init(p_th_mutex##VARNAME)
#else
/* No-ops if not threaded. */
#define EXTERN_MUTEX_DECL(VARNAME)
#define EXTERN_MUTEX_DEF(VARNAME)
#define EXTERN_MUTEXED_INIT_MUTEX(VARNAME) do {} while(0) /* no-op */
#endif /* PFS_THREADS */
#define EXTERN_ALLOC_DECL(VARNAME) \
EXTERN_MUTEX_DECL(VARNAME)
#define EXTERN_MUTEXED_DECL(TYPE,VARNAME) \
EXTERN_MUTEX_DECL(VARNAME); \
extern TYPE VARNAME
#define EXTERN_MUTEXED_DEF(TYPE,VARNAME) \
EXTERN_MUTEX_DEF(VARNAME); \
TYPE VARNAME
#define EXTERN_MUTEXED_DEF_INITIALIZER(TYPE,VARNAME,INITIALIZER) \
EXTERN_MUTEX_DEF(VARNAME); \
TYPE VARNAME = (INITIALIZER)
/* Lock and unlock a mutexed external variable. */
/* In order to avoid potential deadlock situations, all variables must be
locked in alphabetical order. */
#ifdef PFS_THREADS
#define EXTERN_MUTEXED_LOCK(VARNAME) p_th_mutex_lock(p_th_mutex##VARNAME)
#define EXTERN_MUTEXED_UNLOCK(VARNAME) p_th_mutex_unlock(p_th_mutex##VARNAME)
#else
#define EXTERN_MUTEXED_LOCK(VARNAME) do {} while (0)
#define EXTERN_MUTEXED_UNLOCK(VARNAME) do {} while (0)
#endif /* PFS_THREADS */
/* This is found in assertions inside functions that expect to be called only
when they are running as the 'master' thread in Prospero. */
/* The master thread is the one that is started off. When we're
single-threaded, that's the master. */
/* This is used entirely in assertions. */
#define P_IS_THIS_THREAD_MASTER() (p__th_self_num() == 0)
#ifdef PFS_THREADS_FLORIDA
/* Note that under the Draft 7 standard, pthread_detach
takes a pthread_t, whereas under Draft 6, it takes a pointer to
a pthread_t. This implementation uses Draft 6. */
#define p_th_t pthread_t
#define p_th_create_detached(NEWTHREAD,FUNC,ARG) ( \
pthread_create(&NEWTHREAD, (pthread_attr_t *) NULL, \
(pthread_funct_t) FUNC, (any_t) ARG) \
: pthread_detach(&NEWTHREAD) \
)
#define p_th_self pthread_self
#define p_th_equal(a,b) pthread_equal(a,b)
#endif
#ifdef PFS_THREADS_SOLARIS
#define p_th_t thread_t
/* caller needs to check this for errors */
#define p_th_create_detached(NEWTHREAD,FUNC,ARG) \
thr_create(NULL,0,(void *)FUNC,ARG,THR_DETACHED, &NEWTHREAD)
#define p_th_self thr_self
/* thread_t is an int so ...*/
#define p_th_equal(a,b) (a == b)
#endif
/* Mutexed versions of everything that might possibly call malloc() and free().
We can yank this out once we have thread-safe libraries, but that might be a
few years off. */
/* Note that we have converted over all of the server code that might be
called when multi-threaded to not call any of the printf() family of
functions. With a thread_safe malloc() now available from FSU, that
means we need none of these special definitions. Hooray! */
#if defined(PFS_THREADS) && !defined(PFS_THREADS_SOLARIS) && !defined(PFS_THREADS_FLORIDA)
/* commented out for the implemented thread implementations.*/
#define free(P) p_th_free((P))
extern void p_th_free(void *P);
#define malloc(P) p_th_malloc((P))
extern void *p_th_malloc(unsigned size);
#define calloc(A,B) p_th_calloc((A),(B))
extern void *p_th_calloc(unsigned nelem, unsigned size);
#define _filbuf(p) p_th__filbuf((p))
#define _flsbuf(p,q) p_th__flsbuf((p),(q))
#define fgets(a,b,c) p_th_fgets((a),(b), (c))
extern char *p_th_fgets(char *s, int n, FILE *stream);
#define gets(a) p_th_gets((a))
extern char *p_th_gets(char *s);
#define fputs(a,b) p_th_fputs((a),(b))
extern int p_th_fputs(const char *s, FILE *stream);
#define puts(a) p_th_puts((a))
extern int p_th_puts(const char *s);
#define sprintf p_th_sprintf
extern char *p_th_sprintf();
#define fprintf p_th_fprintf
#define printf p_th_printf
#define fflush(a) p_th_fflush((a))
extern int p_th_fflush(FILE *);
#define fgetc(a) p_th_fgetc((a))
extern int p_th_fgetc(FILE *);
#define fputc(a,b) p_th_fputc((a),(b))
extern int p_th_fputc();
#define fread(a,b,c,d) p_th_fread((a),(b),(c), (d))
extern int p_th_fread(char *ptr, int size, int nitems, FILE*stream);
#define fwrite(a,b,c,d) p_th_fwrite((a),(b),(c), (d))
extern int p_th_fwrite(const char *ptr, int size, int nitems, FILE *stream);
#define fopen(a,b) p_th_fopen((a),(b))
extern FILE *p_th_fopen(const char *a, const char *b);
#define fclose(a) p_th_fclose((a))
extern int p_th_fclose(FILE *a);
#endif /* !defined(PFS_THREADS_FLORIDA) && !defined(PFS_THREADS_SOLARIS */
/* also in ardp.h */
extern FILE *locked_fopen(const char *a, const char *b);
extern int locked_fclose_A(FILE *a, const char*filename, int readonly);
extern void locked_clear(FILE *a);
int locked_fclose_and_rename(FILE *afile, const char *tmpfilename, const char *filename, int retval);
#if 0
#define locked_fopen(a,b) fopen((a),(b))
#define locked_fclose_A(a,b,c) fclose((a))
#define locked_clear(a)
#endif /* 0 */
extern void p__th_set_self_master();
#endif /* PFS_THREADS_H */