/* initial part must match struct empobj */
signed ef_type: 8;
unsigned com_seqno: 12;
+ unsigned com_generation: 12;
int com_uid;
time_t com_timestamp;
natid com_owner;
*/
signed ef_type: 8;
unsigned seqno: 12;
+ unsigned generation: 12;
int uid;
time_t timestamp;
/* end of part matching struct emptypedstr */
struct emptypedstr {
signed ef_type: 8;
unsigned seqno: 12;
+ unsigned generation: 12;
int uid;
time_t timestamp;
};
extern struct castr *ef_cadef(int);
extern int ef_read(int, int, void *);
+extern void ef_make_stale(void);
+extern void ef_mark_fresh(int, void *);
extern void *ef_ptr(int, int);
extern char *ef_nameof(int);
extern time_t ef_mtime(int);
/* initial part must match struct empobj */
signed ef_type: 8;
unsigned game_seqno: 12;
+ unsigned game_generation: 12;
int game_uid;
time_t game_timestamp;
/* end of part matching struct empobj */
/* initial part must match struct empobj */
signed ef_type: 8;
unsigned lnd_seqno: 12;
+ unsigned lnd_generation: 12;
int lnd_uid; /* unit id (land #) */
time_t lnd_timestamp; /* Last time this unit was touched */
natid lnd_own; /* owner's country num */
/* initial part must match struct empobj */
signed ef_type: 8;
unsigned l_seqno: 12;
+ unsigned l_generation: 12;
int l_uid;
time_t l_timestamp;
/* end of part matching struct empobj */
/* initial part must match struct empobj */
signed ef_type: 8;
unsigned lost_seqno: 12;
+ unsigned lost_generation: 12;
int lost_uid;
time_t lost_timestamp; /* When it was lost */
natid lost_owner; /* Who lost it */
/* initial part must match struct empobj */
signed ef_type: 8;
unsigned r_seqno: 12;
+ unsigned r_generation: 12;
int r_uid; /* realm table index */
time_t r_timestamp; /* Last time this realm was touched */
natid r_cnum; /* country number */
/* initial part must match struct empobj */
signed ef_type: 8;
unsigned nat_seqno: 12;
+ unsigned nat_generation: 12;
int nat_uid; /* equals nat_cnum */
time_t nat_timestamp;
natid nat_cnum; /* our country number */
/* initial part must match struct empobj */
signed ef_type: 8;
unsigned nuk_seqno: 12;
+ unsigned nuk_generation: 12;
int nuk_uid; /* unit id (nuke #) */
time_t nuk_timestamp; /* Last time this nuke was touched */
natid nuk_own;
/* initial part must match struct empobj */
signed ef_type: 8;
unsigned pln_seqno: 12;
+ unsigned pln_generation: 12;
int pln_uid; /* unit id (plane #) */
time_t pln_timestamp; /* Last time this plane was touched */
natid pln_own; /* owning country */
/* initial part must match struct empobj */
signed ef_type: 8;
unsigned sct_seqno: 12;
+ unsigned sct_generation: 12;
int sct_uid; /* equals XYOFFSET(sct_x, sct_y) */
time_t sct_timestamp; /* Last time this sector was written to */
natid sct_own; /* owner's country num */
/* initial part must match struct empobj */
signed ef_type: 8;
unsigned shp_seqno: 12;
+ unsigned shp_generation: 12;
int shp_uid; /* unit it (ship #) */
time_t shp_timestamp; /* Last time this ship was touched. */
natid shp_own; /* owner's country num */
/* initial part must match struct empobj */
signed ef_type: 8;
unsigned trd_seqno: 12;
+ unsigned trd_generation: 12;
int trd_uid;
time_t trd_timestamp;
natid trd_owner;
/* initial part must match struct empobj */
signed ef_type: 8;
unsigned trt_seqno: 12;
+ unsigned trt_generation: 12;
int trt_uid;
time_t trt_timestamp;
/* end of part matching struct empobj */
static int do_write(struct empfile *, void *, int, int);
static unsigned get_seqno(struct empfile *, int);
static void new_seqno(struct empfile *, void *);
+static void must_be_fresh(struct empfile *, void *);
static void do_blank(struct empfile *, void *, int, int);
static int ef_check(int);
+static unsigned ef_generation;
+
/*
* Open the file-backed table TYPE (EF_SECTOR, ...).
* HOW are flags to control operation. Naturally, immutable flags are
cachep = ep->cache + (id - ep->baseid) * ep->size;
}
memcpy(into, cachep, ep->size);
+ ef_mark_fresh(type, into);
if (ep->postread)
ep->postread(id, into);
if (ep->onresize && ep->onresize(type) < 0)
return 0;
}
- if (id >= ep->baseid && id < ep->baseid + ep->cids)
+ if (id >= ep->baseid && id < ep->baseid + ep->cids) {
cachep = ep->cache + (id - ep->baseid) * ep->size;
- else
+ if (cachep != from)
+ must_be_fresh(ep, from);
+ } else
cachep = NULL;
if (ep->prewrite)
ep->prewrite(id, cachep, from);
elt->seqno = old_seqno + 1;
}
+void
+ef_make_stale(void)
+{
+ ef_generation++;
+}
+
+void
+ef_mark_fresh(int type, void *buf)
+{
+ struct empfile *ep;
+
+ if (ef_check(type) < 0)
+ return;
+ ep = &empfile[type];
+ if (!(ep->flags & EFF_TYPED))
+ return;
+ ((struct emptypedstr *)buf)->generation = ef_generation;
+}
+
+static void
+must_be_fresh(struct empfile *ep, void *buf)
+{
+ struct emptypedstr *elt = buf;
+
+ if (!(ep->flags & EFF_TYPED))
+ return;
+ CANT_HAPPEN(elt->generation != (ef_generation & 0xfff));
+}
+
/*
* Extend table TYPE by COUNT elements.
* Any pointers obtained from ef_ptr() become invalid.
elt = buf;
elt->seqno = get_seqno(ep, elt->uid);
}
+ ef_mark_fresh(type, buf);
}
/*
#include <unistd.h>
#include "empio.h"
#include "empthread.h"
+#include "file.h"
#include "ioqueue.h"
#include "misc.h"
#include "queue.h"
struct iovec iov[16];
int n, res, cc;
+ if (wait)
+ ef_make_stale();
+
if (!ioq_qsize(iop->output))
return 0;
#include <signal.h>
#include <time.h>
#include "empthread.h"
+#include "file.h"
#include "misc.h"
/* Flags that were passed to empth_init() */
{
if (!flags)
flags = empth_flags;
+ ef_make_stale();
return lwpCreate(1, entry, size, flags, name, 0, NULL, ud);
}
void
empth_exit(void)
{
+ ef_make_stale();
lwpExit();
}
void
empth_yield(void)
{
+ ef_make_stale();
lwpYield();
}
int
empth_select(int fd, int flags, struct timeval *timeout)
{
+ ef_make_stale();
return lwpSleepFd(fd, flags, timeout);
}
int
empth_sleep(time_t until)
{
+ ef_make_stale();
return lwpSleepUntil(until);
}
int sig, err;
time_t now;
+ ef_make_stale();
sigemptyset(&set);
sigaddset(&set, SIGHUP);
sigaddset(&set, SIGINT);
void
empth_rwlock_wrlock(empth_rwlock_t *rwlock)
{
+ ef_make_stale();
lwp_rwlock_wrlock(rwlock);
}
void
empth_rwlock_rdlock(empth_rwlock_t *rwlock)
{
+ ef_make_stale();
lwp_rwlock_rdlock(rwlock);
}
#include <process.h>
#include "misc.h"
#include "empthread.h"
+#include "file.h"
#include "prototypes.h"
#include "server.h"
#include "sys/socket.h"
empth_t *pThread = NULL;
loc_debug("creating new thread %s", name);
+ ef_make_stale();
pThread = malloc(sizeof(*pThread));
if (!pThread) {
empth_t *pThread = TlsGetValue(dwTLSIndex);
loc_debug("empth_exit");
+ ef_make_stale();
loc_BlockThisThread();
TlsSetValue(dwTLSIndex, NULL);
void
empth_yield(void)
{
+ ef_make_stale();
loc_BlockThisThread();
Sleep(0);
loc_RunThisThread(NULL);
loc_debug("%s select on %d",
flags == EMPTH_FD_READ ? "read" : "write", fd);
+ ef_make_stale();
loc_BlockThisThread();
hEventObject[0] = WSACreateEvent();
empth_t *pThread = TlsGetValue(dwTLSIndex);
DWORD result;
+ ef_make_stale();
loc_BlockThisThread();
do {
int
empth_wait_for_signal(void)
{
+ ef_make_stale();
loc_BlockThisThread();
loc_RunThisThread(hShutdownEvent);
return SIGTERM;
void
empth_rwlock_wrlock(empth_rwlock_t *rwlock)
{
+ ef_make_stale();
/* block any new readers */
ResetEvent(rwlock->can_read);
rwlock->nwrite++;
void
empth_rwlock_rdlock(empth_rwlock_t *rwlock)
{
+ ef_make_stale();
loc_BlockThisThread();
loc_RunThisThread(rwlock->can_read);
ResetEvent(rwlock->can_write);
#include <unistd.h>
#include "misc.h"
#include "empthread.h"
+#include "file.h"
#include "prototypes.h"
struct empth_t {
int eno;
empth_status("creating new thread %s", name);
+ ef_make_stale();
ctx = malloc(sizeof(empth_t));
if (!ctx) {
empth_t *ctx = pthread_getspecific(ctx_key);
empth_status("empth_exit");
+ ef_make_stale();
pthread_mutex_unlock(&mtx_ctxsw);
free(ctx->name);
free(ctx);
void
empth_yield(void)
{
+ ef_make_stale();
pthread_mutex_unlock(&mtx_ctxsw);
pthread_mutex_lock(&mtx_ctxsw);
empth_restorectx();
empth_t *ctx;
int res = 0;
+ ef_make_stale();
pthread_mutex_unlock(&mtx_ctxsw);
empth_status("select on %d for %d", fd, flags);
struct timeval tv;
int res;
+ ef_make_stale();
pthread_mutex_unlock(&mtx_ctxsw);
do {
now = time(NULL);
sigset_t set;
int sig, err;
+ ef_make_stale();
sigemptyset(&set);
sigaddset(&set, SIGHUP);
sigaddset(&set, SIGINT);
{
empth_status("wrlock %s %d %d",
rwlock->name, rwlock->nread, rwlock->nwrite);
+ ef_make_stale();
rwlock->nwrite++;
while (rwlock->nread != 0 || rwlock->nwrite != 1) {
empth_status("waiting for wrlock %s", rwlock->name);
{
empth_status("rdlock %s %d %d",
rwlock->name, rwlock->nread, rwlock->nwrite);
+ ef_make_stale();
while (rwlock->nwrite) {
empth_status("waiting for rdlock %s", rwlock->name);
pthread_cond_wait(&rwlock->can_read, &mtx_ctxsw);
get_empobj(obj->ef_type, obj->uid, &old);
memcpy(&tobj, obj, sz);
old.gen.timestamp = tobj.gen.timestamp = 0;
- return memcmp(&tobj, &old, sz);
+ old.gen.generation = tobj.gen.generation = 0;
+ if (memcmp(&tobj, &old, sz))
+ return 1;
+ ef_mark_fresh(obj->ef_type, obj);
+ return 0;
}
int
mlp = malloc(sizeof(struct ulist));
mlp->chrp = (struct empobj_chr *)(mchr + sp->shp_type);
mlp->unit.ship = *sp;
+ ef_mark_fresh(EF_SHIP, &mlp->unit.ship);
mlp->mobil = sp->shp_mobil;
emp_insque(&mlp->queue, &ship_list);
sp = getshipp(fe->num);
mlp->chrp = (struct empobj_chr *)(mchr + sp->shp_type);
mlp->unit.ship = *sp;
+ ef_mark_fresh(EF_SHIP, &mlp->unit.ship);
mlp->mobil = fe->mobil;
emp_insque(&mlp->queue, list);
}