diff --git a/include/empthread.h b/include/empthread.h index 9ea8316d..ed57279b 100644 --- a/include/empthread.h +++ b/include/empthread.h @@ -33,6 +33,18 @@ * Steve McClure, 1998 */ +/* + * This header defines Empire's abstract thread interface. There are + * several concrete implementations. + * + * Empire threads are non-preemptive, i.e. they run until they + * voluntarily yield the processor. The thread scheduler then picks + * one of the runnable threads with the highest priority. Priorities + * are static. Empire code relies on these properties heavily. The + * most common form of yielding the processor is sleeping for some + * event to happen. + */ + #ifndef _EMTHREAD_H_ #define _EMTHREAD_H_ @@ -46,13 +58,26 @@ #ifdef _EMPTH_LWP #include "lwp.h" + +/* Abstract data types */ + +/* empth_t * represents a thread. */ typedef struct lwpProc empth_t; + +/* empth_sem_t * represents a semaphore */ typedef struct lwpSem empth_sem_t; + +/* Flags for empth_select(): whether to sleep on input or output */ #define EMPTH_FD_READ LWP_FD_READ #define EMPTH_FD_WRITE LWP_FD_WRITE + +/* Flags for empth_init() and empth_create() */ +/* Request debug prints */ #define EMPTH_PRINT LWP_PRINT +/* Request stack checking */ #define EMPTH_STACKCHECK LWP_STACKCHECK -#endif + +#endif /* _EMPTH_LWP */ #ifdef _EMPTH_POSIX #ifdef __linux__ @@ -83,7 +108,7 @@ typedef struct { pthread_cond_t cnd_sem; } empth_sem_t; -#endif +#endif /* _EMPTH_POSIX */ /* DEC has slightly different names for whatever reason... */ #ifdef _DECTHREADS_ @@ -106,20 +131,107 @@ typedef struct loc_Thread_t empth_t; typedef struct loc_Sem_t empth_sem_t; void empth_request_shutdown(void); -#endif +#endif /* _EMPTH_WIN32 */ -int empth_init(char **ctx, int flags); -empth_t *empth_create(int, void (*)(void *), int, int, char *, char *, void *); +/* + * Initialize thread package. + * CTX points to a thread context variable; see empth_create(). + * FLAGS request optional features. + * Should return 0 on success, -1 on error, but currently always + * returns 0. + */ +int empth_init(void **ctx, int flags); + +/* + * Create a new thread. + * PRIO is the scheduling priority. + * ENTRY is the entry point. It will be called with argument UD. + * Thread stack is at least SIZE bytes. + * FLAGS should be the same as were passed to empth_init(), or zero. + * NAME is the threads name, and DESC its description. These are used + * for logging and debugging. + * UD is the value to pass to ENTRY. It is also assigned to the + * context variable defined with empth_init() whenever the thread gets + * scheduled. + * Return the thread, or NULL on error. + */ +empth_t *empth_create(int prio, void (*entry)(void *), + int size, int flags, char *name, char *desc, void *ud); + +/* + * Return the current thread. + */ empth_t *empth_self(void); + +/* + * Terminate the current thread. + * Never returns. + */ void empth_exit(void); + +/* + * Yield the processor. + */ void empth_yield(void); -void empth_terminate(empth_t *); + +/* + * Terminate THREAD. + * THREAD will not be scheduled again. Instead, it will terminate as + * if it executed empth_exit(). It is unspecified when exactly that + * happens. + * THREAD must not be the current thread. + */ +void empth_terminate(empth_t *thread); + +/* + * Put current thread to sleep until file descriptor FD is ready for I/O. + * If FLAGS & EMPTH_FD_READ, wake up if FD is ready for input. + * If FLAGS & EMPTH_FD_WRITE, wake up if FD is ready for output. + * Note: Currently, Empire sleeps only on network I/O, i.e. FD is a + * socket. Implementations should not rely on that. + */ void empth_select(int fd, int flags); -void empth_wakeup(empth_t *); -void empth_sleep(long until); + +/* + * Awaken THREAD if it is sleeping in empth_select(). + * Note: This must not awaken threads sleeping in other functions. + */ +void empth_wakeup(empth_t *thread); + +/* + * Put current thread to sleep until the time is UNTIL. + * May sleep somehwat longer, but never shorter. + */ +void empth_sleep(time_t until); + +/* + * Create a semaphore. + * NAME is its name, it is used for debugging. + * COUNT is the initial count value of the semaphore, it must not be + * negative. + * Return the semaphore, or NULL on error. + */ empth_sem_t *empth_sem_create(char *name, int count); -void empth_sem_signal(empth_sem_t *); -void empth_sem_wait(empth_sem_t *); + +/* + * Signal SEM. + * Increase SEM's count. If threads are sleeping on it, wake up + * exactly one of them. If that thread has a higher priority, yield + * the processor. + * This semaphore operation is often called `down' or `V' otherwhere. + */ +void empth_sem_signal(empth_sem_t *sem); + +/* + * Wait for SEM. + * If SEM has a zero count, put current thread to sleep until + * empth_sem_signal() awakens it. SEM will have non-zero value then. + * Decrement SEM's count. + * This semaphore operation is often called `up' or `P' otherwhere. + */ +void empth_sem_wait(empth_sem_t *sem); + +/* Internal function, not part of the thread abstraction */ void empth_alarm(int); #endif diff --git a/src/lib/empthread/lwp.c b/src/lib/empthread/lwp.c index f6f488a6..353c4de6 100644 --- a/src/lib/empthread/lwp.c +++ b/src/lib/empthread/lwp.c @@ -38,9 +38,9 @@ #ifdef _EMPTH_LWP int -empth_init(char **ctx, int flags) +empth_init(void **ctx, int flags) { - lwpInitSystem(7, ctx, flags); + lwpInitSystem(7, (char **)ctx, flags); return 0; } @@ -113,7 +113,7 @@ empth_wakeup(empth_t *a) } void -empth_sleep(long int until) +empth_sleep(time_t until) { lwpSleepUntil(until); } diff --git a/src/lib/empthread/ntthread.c b/src/lib/empthread/ntthread.c index 529cbf86..b870723b 100644 --- a/src/lib/empthread/ntthread.c +++ b/src/lib/empthread/ntthread.c @@ -139,7 +139,7 @@ static struct { /* Pointer out to global context. "player". */ /* From empth_init parameter. */ - char **ppvUserData; + void **ppvUserData; /* Global flags. From empth_init parameter. */ int flags; @@ -379,7 +379,7 @@ empth_threadMain(void *pvData) * This is called from the program main line. */ int -empth_init(char **ctx_ptr, int flags) +empth_init(void **ctx_ptr, int flags) { loc_Thread_t *pThread = NULL; @@ -640,7 +640,7 @@ empth_wakeup(empth_t *a) * Put the given thread to sleep... */ void -empth_sleep(long until) +empth_sleep(time_t until) { loc_Thread_t *pThread = (loc_Thread_t *)TlsGetValue(loc_GVAR.dwTLSIndex); diff --git a/src/lib/empthread/pthread.c b/src/lib/empthread/pthread.c index a01c1b5e..bdd925c9 100644 --- a/src/lib/empthread/pthread.c +++ b/src/lib/empthread/pthread.c @@ -52,7 +52,7 @@ #ifdef _EMPTH_POSIX static pthread_key_t ctx_key; static int empth_flags; -static char **udata; /* pointer to out global context */ +static void **udata; /* pointer to out global context */ static pthread_mutex_t mtx_ctxsw; /* thread in critical section */ @@ -121,7 +121,7 @@ empth_status(char *format, ...) int -empth_init(char **ctx_ptr, int flags) +empth_init(void **ctx_ptr, int flags) { empth_t *ctx; struct sigaction act; @@ -425,7 +425,7 @@ empth_wakeup(empth_t *a) } void -empth_sleep(long until) +empth_sleep(time_t until) { struct timeval tv; diff --git a/src/server/main.c b/src/server/main.c index e9ab723b..36e67316 100644 --- a/src/server/main.c +++ b/src/server/main.c @@ -309,7 +309,7 @@ start_server(int flags) sigaction(SIGPIPE, &act, NULL); #endif /* !_WIN32 */ - empth_init((char **)&player, flags); + empth_init((void **)&player, flags); empth_create(PP_ACCEPT, player_accept, (50 * 1024), flags, "AcceptPlayers", "Accept network connections", 0);