X-Git-Url: http://git.pond.sub.org/?p=empserver;a=blobdiff_plain;f=include%2Fempthread.h;h=4bdcf444cc6881e79a52edbf757088605bc27413;hp=b58c06545e72e11545aa3ecbdea46081fad4621f;hb=HEAD;hpb=d86c6e89fff7a452d514fa51d0c9599c526fb0ed diff --git a/include/empthread.h b/include/empthread.h index b58c06545..4bdcf444c 100644 --- a/include/empthread.h +++ b/include/empthread.h @@ -1,11 +1,11 @@ /* * Empire - A multi-player, client/server Internet based war game. - * Copyright (C) 1986-2005, Dave Pare, Jeff Bailey, Thomas Ruschak, - * Ken Stevens, Steve McClure + * Copyright (C) 1986-2021, Dave Pare, Jeff Bailey, Thomas Ruschak, + * Ken Stevens, Steve McClure, Markus Armbruster * - * This program is free software; you can redistribute it and/or modify + * Empire is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or + * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, @@ -14,23 +14,24 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * along with this program. If not, see . * * --- * - * See the "LEGAL", "LICENSE", "CREDITS" and "README" files for all the - * related information and legal notices. It is expected that any future - * projects/authors will amend these files as needed. + * See files README, COPYING and CREDITS in the root of the source + * tree for related information and legal notices. It is expected + * that future projects/authors will amend these files as needed. * * --- * * empthread.h: Definitions for Empire threading - * + * * Known contributors to this file: * Sasha Mikheev * Doug Hay, 1998 * Steve McClure, 1998 + * Markus Armbruster, 2005-2012 + * Ron Koenderink, 2005-2009 */ /* @@ -39,33 +40,26 @@ * * 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. + * one of the runnable threads. The most common form of yielding the + * processor is sleeping for some event to happen. */ -#ifndef _EMTHREAD_H_ -#define _EMTHREAD_H_ - -#include "misc.h" +#ifndef EMPTHREAD_H +#define EMPTHREAD_H -#if defined(_WIN32) -#undef _EMPTH_LWP -#undef _EMPTH_POSIX -#define _EMPTH_WIN32 -#endif +#include +#include -#ifdef _EMPTH_LWP +#ifdef EMPTH_LWP #include "lwp.h" /* Abstract data types */ -/* empth_t * represents a thread. */ +/* A thread. */ typedef struct lwpProc empth_t; -/* empth_sem_t * represents a semaphore */ -typedef struct lwpSem empth_sem_t; +/* A read-write lock, perferring writers */ +typedef struct lwp_rwlock empth_rwlock_t; /* Flags for empth_select(): whether to sleep on input or output */ #define EMPTH_FD_READ LWP_FD_READ @@ -77,49 +71,21 @@ typedef struct lwpSem empth_sem_t; /* Request stack checking */ #define EMPTH_STACKCHECK LWP_STACKCHECK -#endif /* _EMPTH_LWP */ +#endif /* EMPTH_LWP */ -#ifdef _EMPTH_POSIX -#ifdef __linux__ -#define _MIT_POSIX_THREADS 1 -#endif -#include +#ifdef EMPTH_POSIX #define EMPTH_FD_READ 0x1 #define EMPTH_FD_WRITE 0x2 #define EMPTH_PRINT 0x1 #define EMPTH_STACKCHECK 0x2 -#define EMPTH_KILLED 1 -typedef struct { - char *name; /* thread name */ - char *desc; /* description */ - void *ud; /* user data */ - int state; /* my state */ - void (*ep)(void *); /* entry point */ - pthread_t id; /* thread id */ -} empth_t; - -typedef struct { - pthread_mutex_t mtx_update; /* use it to update count */ - int count; - char name[80]; - pthread_mutex_t mtx_sem; - pthread_cond_t cnd_sem; -} empth_sem_t; - -#endif /* _EMPTH_POSIX */ - -/* DEC has slightly different names for whatever reason... */ -#ifdef _DECTHREADS_ -#define pthread_key_create pthread_keycreate -#define pthread_attr_init pthread_attr_create -#define pthread_attr_destroy pthread_attr_delete - -#endif +typedef struct empth_t empth_t; +typedef struct empth_rwlock_t empth_rwlock_t; +#endif /* EMPTH_POSIX */ -#if defined(_EMPTH_WIN32) +#ifdef EMPTH_W32 /* The Windows NT Threads */ #define EMPTH_FD_READ 0x1 #define EMPTH_FD_WRITE 0x2 @@ -127,16 +93,16 @@ typedef struct { #define EMPTH_PRINT 0x1 #define EMPTH_STACKCHECK 0x2 -typedef struct loc_Thread_t empth_t; -typedef struct loc_Sem_t empth_sem_t; +typedef struct loc_Thread empth_t; +typedef struct loc_RWLock empth_rwlock_t; void empth_request_shutdown(void); -#endif /* _EMPTH_WIN32 */ +#endif /* EMPTH_W32 */ /* * Initialize thread package. - * CTX points to a thread context variable; see empth_create(). - * FLAGS request optional features. + * @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. */ @@ -144,27 +110,41 @@ 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 + * @entry is the entry point. It will be called with argument @ud. + * If it returns, the thread terminates as if it called empth_exit(). + * Thread stack is at least @size bytes. + * @flags should be the same as were passed to empth_init(), or zero. + * @name is the thread's name, it is 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. + * Yield the processor. * 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); +empth_t *empth_create(void (*entry)(void *), + int size, int flags, char *name, void *ud); /* - * Return the current thread. + * Return the current thread, NULL before empth_init(). + * This is the only function that may be called before empth_init(). */ empth_t *empth_self(void); +/* + * Return @thread's name. + */ +char *empth_name(empth_t *thread); + +/* + * Set @thread's name to @name. + */ +void empth_set_name(empth_t *thread, char *name); + /* * Terminate the current thread. + * The current thread should not be the thread that executed main(). + * If it is, implementations may terminate the process rather than the + * thread. * Never returns. */ void empth_exit(void); @@ -175,64 +155,79 @@ void empth_exit(void); void empth_yield(void); /* - * 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. + * 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. * At most one thread may sleep on the same file descriptor. - * Note: Currently, Empire sleeps only on network I/O, i.e. FD is a + * @timeout, if non-null, limits the sleep time. + * Return one when the @fd is ready, zero on timeout or early wakeup by + * empth_wakeup(), -1 on error with errno set. + * 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); +int empth_select(int fd, int flags, struct timeval *timeout); /* - * Awaken THREAD if it is sleeping in empth_select(). - * Note: This must not awaken threads sleeping in other functions. + * Awaken @thread if it is sleeping in empth_select() or empth_sleep(). + * This does not awaken threads sleeping in other functions. + * Does not yield the processor. */ void empth_wakeup(empth_t *thread); /* - * Put current thread to sleep until the time is UNTIL. - * May sleep somehwat longer, but never shorter. + * Put current thread to sleep until the time is @until. + * Return 0 if it slept until that time. + * Return -1 if woken up early, by empth_wakeup(). + */ +int empth_sleep(time_t until); + +/* + * Put current thread to sleep until SIGHUP, SIGINT or SIGTERM is received. + * Return the signal number. + */ +int empth_wait_for_signal(void); + +/* + * Create a read-write lock. + * @name is its name, it is used for debugging. + * Return the read-write lock, or NULL on error. */ -void empth_sleep(time_t until); +empth_rwlock_t *empth_rwlock_create(char *name); /* - * 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. + * Destroy @rwlock. */ -empth_sem_t *empth_sem_create(char *name, int count); +void empth_rwlock_destroy(empth_rwlock_t *rwlock); /* - * 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. + * Lock @rwlock for writing. + * A read-write lock can be locked for writing only when it is + * unlocked. If this is not the case, put the current thread to sleep + * until it is. */ -void empth_sem_signal(empth_sem_t *sem); +void empth_rwlock_wrlock(empth_rwlock_t *rwlock); + +/* + * Lock @rwlock for reading. + * A read-write lock can be locked for reading only when it is not + * locked for writing, and no other thread is attempting to lock it + * for writing. If this is not the case, put the current thread to + * sleep until it is. + */ +void empth_rwlock_rdlock(empth_rwlock_t *rwlock); + +/* + * Unlock read-write lock @rwlock. + * The current thread must hold @rwlock. + * Wake up threads that can now lock it. + */ +void empth_rwlock_unlock(empth_rwlock_t *rwlock); + /* - * 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. + * Stuff for implementations, not for clients. */ -void empth_sem_wait(empth_sem_t *sem); -/* Internal function, not part of the thread abstraction */ -void empth_alarm(int); +void empth_init_signals(void); #endif