From 1c1fa720d46b7cecd74fde50715a921f208b0135 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Tue, 29 Jul 2008 07:48:28 -0400 Subject: [PATCH 01/21] New journal event command Redundant information, but makes the journal easier to read. The redundancy might help making a journal replay tool robust. Put it in Hvy Metal II now to gather some real data. --- include/journal.h | 1 + src/lib/player/dispatch.c | 2 ++ src/lib/subs/journal.c | 8 ++++++++ 3 files changed, 11 insertions(+) diff --git a/include/journal.h b/include/journal.h index ed2224a3..d0cbacdc 100644 --- a/include/journal.h +++ b/include/journal.h @@ -41,6 +41,7 @@ void journal_login(void); void journal_logout(void); void journal_prng(unsigned); void journal_input(char *); +void journal_command(char *); void journal_update(int); #endif diff --git a/src/lib/player/dispatch.c b/src/lib/player/dispatch.c index f629f5d3..50c0f43d 100644 --- a/src/lib/player/dispatch.c +++ b/src/lib/player/dispatch.c @@ -38,6 +38,7 @@ #include "com.h" #include "empio.h" #include "file.h" +#include "journal.h" #include "match.h" #include "misc.h" #include "nat.h" @@ -102,6 +103,7 @@ dispatch(char *buf, char *redir) uprnf(buf); pr("\n"); } + journal_command(command->c_form); switch (command->c_addr()) { case RET_OK: player->btused += command->c_cost; diff --git a/src/lib/subs/journal.c b/src/lib/subs/journal.c index cd187132..90c34a62 100644 --- a/src/lib/subs/journal.c +++ b/src/lib/subs/journal.c @@ -44,6 +44,7 @@ * prng NAME SEED * login CNUM HOSTADDR USER * logout CNUM + * command NAME * input INPUT * update ETU */ @@ -173,6 +174,13 @@ journal_input(char *input) journal_entry("input %s", input); } +void +journal_command(char *cmd) +{ + char *eptr = strchr(cmd, ' '); + journal_entry("command %.*s", eptr ? (int)(eptr - cmd) : -1, cmd); +} + void journal_update(int etu) { From c4687e15d5289d4e38a1d849a6291a742dd9b927 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Tue, 29 Jul 2008 20:38:48 -0400 Subject: [PATCH 02/21] New journal event output To enable, set econfig key keep_journal to at least 2. Output events are *not* flushed to disk immediately. Put it in Hvy Metal II now to gather real data for future testing of a journal replay tool. --- include/journal.h | 3 +++ src/lib/subs/journal.c | 15 ++++++++++++++- src/lib/subs/pr.c | 3 +++ 3 files changed, 20 insertions(+), 1 deletion(-) diff --git a/include/journal.h b/include/journal.h index d0cbacdc..b52e14b1 100644 --- a/include/journal.h +++ b/include/journal.h @@ -34,12 +34,15 @@ #ifndef JOURNAL_H #define JOURNAL_H +struct player; /* FIXME temporary hack */ + int journal_startup(void); void journal_shutdown(void); int journal_reopen(void); void journal_login(void); void journal_logout(void); void journal_prng(unsigned); +void journal_output(struct player *, int, char *); void journal_input(char *); void journal_command(char *); void journal_update(int); diff --git a/src/lib/subs/journal.c b/src/lib/subs/journal.c index 90c34a62..e0ec1762 100644 --- a/src/lib/subs/journal.c +++ b/src/lib/subs/journal.c @@ -46,6 +46,7 @@ * logout CNUM * command NAME * input INPUT + * output THREAD ID OUTPUT * update ETU */ @@ -99,7 +100,8 @@ journal_entry(char *fmt, ...) fprintf(journal, "\\%03o", *p); } fputs("\n", journal); - fflush(journal); + if (fmt[0] != 'o') /* FIXME disgusting hack */ + fflush(journal); if (ferror(journal)) { logerror("Error writing journal (%s)", strerror(errno)); clearerr(journal); @@ -168,6 +170,17 @@ journal_logout(void) journal_entry("logout %d", player->cnum); } +void +journal_output(struct player *pl, int id, char *output) +{ + if (keep_journal < 2) + return; + if (pl && pl->state == PS_PLAYING) + journal_entry("output %d %d %s", pl->cnum, id, output); + else + journal_entry("output %p %d %s", pl, id, output); +} + void journal_input(char *input) { diff --git a/src/lib/subs/pr.c b/src/lib/subs/pr.c index 3ba199ee..55fb0c13 100644 --- a/src/lib/subs/pr.c +++ b/src/lib/subs/pr.c @@ -56,6 +56,7 @@ #include "com.h" #include "empio.h" #include "file.h" +#include "journal.h" #include "misc.h" #include "nat.h" #include "player.h" @@ -245,6 +246,7 @@ pr_player(struct player *pl, int id, char *buf) bp += len; } } + journal_output(pl, id, buf); } /* @@ -299,6 +301,7 @@ upr_player(struct player *pl, int id, char *buf) io_puts(pl->iop, printbuf); } } + journal_output(pl, id, buf); } /* From 87512fb644c2b099d433d3abd303b5e276e964fd Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Wed, 30 Jul 2008 08:26:34 -0400 Subject: [PATCH 03/21] Journal output lines instead of chunks Output often arrives in chunks other than lines. Hard to read in the journal. Delay journalling until we got a full line or our buffer is exhausted. This is less precise, but it'll do for now. --- include/journal.h | 2 +- src/lib/subs/journal.c | 28 +++++++++++++++++++++++++--- src/lib/subs/pr.c | 6 ++++-- 3 files changed, 30 insertions(+), 6 deletions(-) diff --git a/include/journal.h b/include/journal.h index b52e14b1..4afc2f85 100644 --- a/include/journal.h +++ b/include/journal.h @@ -42,7 +42,7 @@ int journal_reopen(void); void journal_login(void); void journal_logout(void); void journal_prng(unsigned); -void journal_output(struct player *, int, char *); +void journal_output(struct player *, char *); void journal_input(char *); void journal_command(char *); void journal_update(int); diff --git a/src/lib/subs/journal.c b/src/lib/subs/journal.c index e0ec1762..0c739ab0 100644 --- a/src/lib/subs/journal.c +++ b/src/lib/subs/journal.c @@ -69,6 +69,7 @@ static FILE *journal; static void journal_entry(char *fmt, ...) ATTRIBUTE((format (printf, 1, 2))); +static void journal_output_1(struct player *, char *, char *, int); static FILE * journal_open(void) @@ -171,14 +172,35 @@ journal_logout(void) } void -journal_output(struct player *pl, int id, char *output) +journal_output(struct player *pl, char *output) { + static char buf[1024]; + char *s, *e; + if (keep_journal < 2) return; + + for (s = output; (e = strchr(s, '\n')); s = e + 1) { + journal_output_1(pl, buf, s, (int)(e + 1 - s)); + buf[0] = 0; + } + if (strlen(buf) + strlen(s) < 1024) + strcpy(buf + strlen(buf), s); + else { + journal_output_1(pl, buf, s, -1); + buf[0] = 0; + } +} + +void +journal_output_1(struct player *pl, char *buf1, char *buf2, int buf2prec) +{ if (pl && pl->state == PS_PLAYING) - journal_entry("output %d %d %s", pl->cnum, id, output); + journal_entry("output %d %s%.*s", + pl->cnum, buf1, buf2prec, buf2); else - journal_entry("output %p %d %s", pl, id, output); + journal_entry("output %p %s%.*s", + pl, buf1, buf2prec, buf2); } void diff --git a/src/lib/subs/pr.c b/src/lib/subs/pr.c index 55fb0c13..38bc98fa 100644 --- a/src/lib/subs/pr.c +++ b/src/lib/subs/pr.c @@ -125,6 +125,7 @@ pr_id(struct player *p, int id, char *format, ...) if (p->curid >= 0) { io_puts(p->iop, "\n"); + journal_output(p, "\n"); p->curid = -1; } va_start(ap, format); @@ -246,7 +247,7 @@ pr_player(struct player *pl, int id, char *buf) bp += len; } } - journal_output(pl, id, buf); + journal_output(pl, buf); } /* @@ -301,7 +302,7 @@ upr_player(struct player *pl, int id, char *buf) io_puts(pl->iop, printbuf); } } - journal_output(pl, id, buf); + journal_output(pl, buf); } /* @@ -323,6 +324,7 @@ outid(struct player *pl, int n) buf[1] = ' '; buf[2] = '\0'; io_puts(pl->iop, buf); + journal_output(pl, buf); pl->curid = n; } From 9a19dc973aee99408e45c32ae5e8fa779ae3baba Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Sat, 2 Aug 2008 09:04:16 -0400 Subject: [PATCH 04/21] Fix journalling of output ids --- include/journal.h | 2 +- src/lib/subs/journal.c | 34 ++++++++++++++++++++++------------ src/lib/subs/pr.c | 7 +++---- 3 files changed, 26 insertions(+), 17 deletions(-) diff --git a/include/journal.h b/include/journal.h index 4afc2f85..b52e14b1 100644 --- a/include/journal.h +++ b/include/journal.h @@ -42,7 +42,7 @@ int journal_reopen(void); void journal_login(void); void journal_logout(void); void journal_prng(unsigned); -void journal_output(struct player *, char *); +void journal_output(struct player *, int, char *); void journal_input(char *); void journal_command(char *); void journal_update(int); diff --git a/src/lib/subs/journal.c b/src/lib/subs/journal.c index 0c739ab0..5eddb136 100644 --- a/src/lib/subs/journal.c +++ b/src/lib/subs/journal.c @@ -69,7 +69,7 @@ static FILE *journal; static void journal_entry(char *fmt, ...) ATTRIBUTE((format (printf, 1, 2))); -static void journal_output_1(struct player *, char *, char *, int); +static void journal_output_1(struct player *, int, char *, char *, int); static FILE * journal_open(void) @@ -172,35 +172,45 @@ journal_logout(void) } void -journal_output(struct player *pl, char *output) +journal_output(struct player *pl, int id, char *output) { static char buf[1024]; + static struct player *bpl; + static int bid; char *s, *e; if (keep_journal < 2) return; - for (s = output; (e = strchr(s, '\n')); s = e + 1) { - journal_output_1(pl, buf, s, (int)(e + 1 - s)); + if (buf[0] && (pl != bpl && id != bid)) { + journal_output_1(bpl, bid, buf, "", -1); buf[0] = 0; } - if (strlen(buf) + strlen(s) < 1024) + + for (s = output; (e = strchr(s, '\n')); s = e + 1) { + journal_output_1(pl, id, buf, s, (int)(e + 1 - s)); + buf[0] = 0; + } + if (strlen(buf) + strlen(s) < 1024) { strcpy(buf + strlen(buf), s); - else { - journal_output_1(pl, buf, s, -1); + bpl = pl; + bid = id; + } else { + journal_output_1(pl, id, buf, s, -1); buf[0] = 0; } } void -journal_output_1(struct player *pl, char *buf1, char *buf2, int buf2prec) +journal_output_1(struct player *pl, int id, + char *buf1, char *buf2, int buf2prec) { if (pl && pl->state == PS_PLAYING) - journal_entry("output %d %s%.*s", - pl->cnum, buf1, buf2prec, buf2); + journal_entry("output %d %d %s%.*s", + pl->cnum, id, buf1, buf2prec, buf2); else - journal_entry("output %p %s%.*s", - pl, buf1, buf2prec, buf2); + journal_entry("output %p %id %s%.*s", + pl, id, buf1, buf2prec, buf2); } void diff --git a/src/lib/subs/pr.c b/src/lib/subs/pr.c index 38bc98fa..76b0faa8 100644 --- a/src/lib/subs/pr.c +++ b/src/lib/subs/pr.c @@ -125,7 +125,7 @@ pr_id(struct player *p, int id, char *format, ...) if (p->curid >= 0) { io_puts(p->iop, "\n"); - journal_output(p, "\n"); + journal_output(p, p->curid, "\n"); p->curid = -1; } va_start(ap, format); @@ -247,7 +247,7 @@ pr_player(struct player *pl, int id, char *buf) bp += len; } } - journal_output(pl, buf); + journal_output(pl, id, buf); } /* @@ -302,7 +302,7 @@ upr_player(struct player *pl, int id, char *buf) io_puts(pl->iop, printbuf); } } - journal_output(pl, buf); + journal_output(pl, id, buf); } /* @@ -324,7 +324,6 @@ outid(struct player *pl, int n) buf[1] = ' '; buf[2] = '\0'; io_puts(pl->iop, buf); - journal_output(pl, buf); pl->curid = n; } From 1bf3f557e96ae24bcd1e8c8809750ac21cde3e21 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Sat, 5 Apr 2008 16:09:24 +0200 Subject: [PATCH 05/21] Make fairland record the island number in the deity territory Can be useful for deities when further customizing their game setup. --- src/util/fairland.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/util/fairland.c b/src/util/fairland.c index 08d2af28..a8867f1f 100644 --- a/src/util/fairland.c +++ b/src/util/fairland.c @@ -1092,6 +1092,7 @@ write_sects(void) sct->sct_type = SCT_MOUNT; sct->sct_elev = total; sct->sct_newtype = sct->sct_type; + sct->sct_dterr = own[sct->sct_x][y] + 1; if (ORE) add_resources(sct); } From f8be963202a86ffdc47cd5f568461a4f016cc919 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Mon, 23 Feb 2009 21:56:49 +0100 Subject: [PATCH 06/21] New info Hvy-Plastic --- info/Hvy-Plastic.t | 49 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) create mode 100644 info/Hvy-Plastic.t diff --git a/info/Hvy-Plastic.t b/info/Hvy-Plastic.t new file mode 100644 index 00000000..fa3f6a05 --- /dev/null +++ b/info/Hvy-Plastic.t @@ -0,0 +1,49 @@ +.TH Concept "Hvy-Plastic" +.NA Hvy-Plastic "Special rules for Hvy Plastic" +.LV Basic +.s1 +Ship types are customized. Better check show for the details. +.s1 +Dreadnoughts are more heavily armored. Frigates are more fragile. +.s1 +More ships can carry choppers. Some ships are not ideal for this, and +this is reflected by the lack of large petrol and shell storage. +.s1 +Land unit types are heavily customized. Better check show for the +details. Non-mechanized units are slower and more vulnerable, +artillery firing ranges differ, few units are light (but troop +transports and landing ships can carry non-light units). +.s1 +Planes are tweaked somewhat. show is your friend. +.s1 +Nukes are on sale, but nuclear plants are not. Did I mention the show +command? +.s1 +Infrastructure is disabled. +.s1 +Your refineries make less petrol from each barrel of oil than usual. +.s1 +Natural resources gold, oil and uran deplete much slower than usual. +A 100% gold resource contains 2500d, a 100% oil resource contains +2500o, and a 100% uranium resource contains 500u. Fully depleting a +sector will take you several updates, and a small fraction of the +resource contents will be lost. +.s1 +Gold in mountains does not deplete at all. +.s1 +Oil production does not depend on tech; you don't have to micro-manage +to conserve oil. +.s1 +Missed updates due to server problems will be forced if caught within +15 minutes of planned update time or skipped otherwise. +.s1 +Everything you do in this game is logged by the deities for their own +nefarious purposes. However, the logs are treated confidentially. +.s1 +Make the deity laugh and get up to 5 gold bars. +.s1 +Source code and configuration is available from +.br +http://www.pond.sub.org/~armbru/empire/hvy-plastic.html +.s1 +.SA "Introduction, Server, show" From 20b31defe7f0dbf68ce48c09f464624fa4090554 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Sun, 1 Mar 2009 18:56:41 +0100 Subject: [PATCH 07/21] Generation numbers to catch write back of stale copies Oops when a stale copy is written back, i.e. the processor was yielded since the copy was made. Such bugs are difficult to spot. Sequence numbers catch them when they do actual harm (they also catch different bugs). Generation numbers catch them even when they don't. New ef_generation to count generations. Call new ef_make_stale() to step it whenever the processor may be yielded. New struct emptypedstr member generation. Make sure all members of unit empobj_storage share it. It is only used in copies; its value on disk and in the cache is meaningless. Set it to ef_generation by calling new ef_mark_fresh() when making copies in ef_read() and ef_blank(). Do the same in obj_changed() to make check_sect_ok() & friends freshen their argument when it is unchanged. Copies with generation other than ef_generation are stale. Oops in ef_write() when a stale copy is written back. --- include/commodity.h | 1 + include/empobj.h | 1 + include/file.h | 3 +++ include/game.h | 1 + include/land.h | 1 + include/loan.h | 1 + include/lost.h | 1 + include/nat.h | 2 ++ include/news.h | 1 + include/nuke.h | 1 + include/plane.h | 1 + include/sect.h | 1 + include/ship.h | 1 + include/trade.h | 1 + include/treaty.h | 1 + src/lib/common/file.c | 40 ++++++++++++++++++++++++++++++++++++++-- src/lib/empthread/io.c | 12 ++++++++++++ src/lib/empthread/lwp.c | 9 +++++++++ src/lib/subs/check.c | 6 +++++- 19 files changed, 82 insertions(+), 3 deletions(-) diff --git a/include/commodity.h b/include/commodity.h index e3545785..38ef0990 100644 --- a/include/commodity.h +++ b/include/commodity.h @@ -45,6 +45,7 @@ struct comstr { short ef_type; short com_uid; unsigned com_seqno; + unsigned com_generation; time_t com_timestamp; natid com_owner; /* end of part matching struct empobj */ diff --git a/include/empobj.h b/include/empobj.h index 713f2f4a..3906c13a 100644 --- a/include/empobj.h +++ b/include/empobj.h @@ -58,6 +58,7 @@ struct empobj { short ef_type; short uid; unsigned seqno; + unsigned generation; time_t timestamp; /* end of part matching struct emptypedstr */ natid own; /* valid if EFF_OWNER is in table's flags */ diff --git a/include/file.h b/include/file.h index 9aa6f389..0ffa5b0c 100644 --- a/include/file.h +++ b/include/file.h @@ -88,6 +88,7 @@ struct emptypedstr { short ef_type; short uid; unsigned seqno; + unsigned generation; time_t timestamp; }; @@ -203,6 +204,8 @@ enum { 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); diff --git a/include/game.h b/include/game.h index 9f77dc0f..b10426fc 100644 --- a/include/game.h +++ b/include/game.h @@ -41,6 +41,7 @@ struct gamestr { short ef_type; short game_uid; unsigned game_seqno; + unsigned game_generation; time_t game_timestamp; /* end of part matching struct empobj */ char game_upd_disable; /* updates disabled? */ diff --git a/include/land.h b/include/land.h index 6f5232ff..99f9c301 100644 --- a/include/land.h +++ b/include/land.h @@ -52,6 +52,7 @@ struct lndstr { short ef_type; short lnd_uid; /* unit id (land unit) */ unsigned lnd_seqno; + unsigned lnd_generation; time_t lnd_timestamp; /* Last time this unit was touched */ natid lnd_own; /* owner's country num */ coord lnd_x; /* x location in abs coords */ diff --git a/include/loan.h b/include/loan.h index f4f900f7..fbfe1568 100644 --- a/include/loan.h +++ b/include/loan.h @@ -45,6 +45,7 @@ struct lonstr { short ef_type; short l_uid; unsigned l_seqno; + unsigned l_generation; time_t l_timestamp; /* end of part matching struct empobj */ natid l_loner; /* loan shark */ diff --git a/include/lost.h b/include/lost.h index d30f8e85..021f2633 100644 --- a/include/lost.h +++ b/include/lost.h @@ -42,6 +42,7 @@ struct loststr { short ef_type; short lost_uid; unsigned lost_seqno; + unsigned lost_generation; time_t lost_timestamp; /* When it was lost */ natid lost_owner; /* Who lost it */ /* end of part matching struct empobj */ diff --git a/include/nat.h b/include/nat.h index 5749a1bd..e4c135f9 100644 --- a/include/nat.h +++ b/include/nat.h @@ -73,6 +73,7 @@ struct realmstr { short ef_type; short r_uid; /* realm table index */ unsigned r_seqno; + unsigned r_generation; time_t r_timestamp; /* Last time this realm was touched */ natid r_cnum; /* country number */ /* end of part matching struct empobj */ @@ -86,6 +87,7 @@ struct natstr { short ef_type; short nat_uid; /* equals nat_cnum */ unsigned nat_seqno; + unsigned nat_generation; time_t nat_timestamp; natid nat_cnum; /* our country number */ /* end of part matching struct empobj */ diff --git a/include/news.h b/include/news.h index 24554f09..01a47826 100644 --- a/include/news.h +++ b/include/news.h @@ -49,6 +49,7 @@ struct nwsstr { short ef_type; short nws_uid; unsigned nws_seqno; + unsigned nws_generation; time_t nws_timestamp; /* end of part matching struct empobj */ natid nws_ano; /* "actor" country # */ diff --git a/include/nuke.h b/include/nuke.h index 231f0a04..bb1efd53 100644 --- a/include/nuke.h +++ b/include/nuke.h @@ -45,6 +45,7 @@ struct nukstr { short ef_type; short nuk_uid; unsigned nuk_seqno; + unsigned nuk_generation; time_t nuk_timestamp; /* Last time this nuke was touched */ natid nuk_own; coord nuk_x, nuk_y; /* current loc of device */ diff --git a/include/plane.h b/include/plane.h index 8e37d0d2..5e809e2d 100644 --- a/include/plane.h +++ b/include/plane.h @@ -49,6 +49,7 @@ struct plnstr { short ef_type; short pln_uid; /* plane unit id */ unsigned pln_seqno; + unsigned pln_generation; time_t pln_timestamp; /* Last time this plane was touched */ natid pln_own; /* owning country */ coord pln_x; /* plane x-y */ diff --git a/include/sect.h b/include/sect.h index 336b71f1..f242b22f 100644 --- a/include/sect.h +++ b/include/sect.h @@ -47,6 +47,7 @@ struct sctstr { short ef_type; short sct_uid; /* equals XYOFFSET(sct_x, sct_y) */ unsigned sct_seqno; + unsigned sct_generation; time_t sct_timestamp; /* Last time this sector was written to */ natid sct_own; /* owner's country num */ coord sct_x; /* x coord of sector */ diff --git a/include/ship.h b/include/ship.h index 21e749f5..a8762d57 100644 --- a/include/ship.h +++ b/include/ship.h @@ -66,6 +66,7 @@ struct shpstr { short ef_type; short shp_uid; /* unit id (ship #) */ unsigned shp_seqno; + unsigned shp_generation; time_t shp_timestamp; /* Last time this ship was touched. */ natid shp_own; /* owner's country num */ coord shp_x; /* x location in abs coords */ diff --git a/include/trade.h b/include/trade.h index 6fc9919e..26449ae8 100644 --- a/include/trade.h +++ b/include/trade.h @@ -45,6 +45,7 @@ struct trdstr { short ef_type; short trd_uid; unsigned trd_seqno; + unsigned trd_generation; time_t trd_timestamp; natid trd_owner; /* end of part matching struct empobj */ diff --git a/include/treaty.h b/include/treaty.h index 0e164eef..e70c2f98 100644 --- a/include/treaty.h +++ b/include/treaty.h @@ -42,6 +42,7 @@ struct trtstr { short ef_type; short trt_uid; unsigned trt_seqno; + unsigned trt_generation; time_t trt_timestamp; /* end of part matching struct empobj */ natid trt_cna; /* proposer */ diff --git a/src/lib/common/file.c b/src/lib/common/file.c index 908b024b..16633eee 100644 --- a/src/lib/common/file.c +++ b/src/lib/common/file.c @@ -52,9 +52,12 @@ static int do_read(struct empfile *, void *, int, int); 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 @@ -338,6 +341,7 @@ ef_read(int type, int id, void *into) 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); @@ -500,9 +504,11 @@ ef_write(int type, int id, void *from) 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); @@ -586,6 +592,35 @@ new_seqno(struct empfile *ep, void *buf) 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); +} + /* * Extend table TYPE by COUNT elements. * Any pointers obtained from ef_ptr() become invalid. @@ -663,6 +698,7 @@ ef_blank(int type, int id, void *buf) elt = buf; elt->seqno = get_seqno(ep, elt->uid); } + ef_mark_fresh(type, buf); } /* diff --git a/src/lib/empthread/io.c b/src/lib/empthread/io.c index 5bbce8d9..3fcf164b 100644 --- a/src/lib/empthread/io.c +++ b/src/lib/empthread/io.c @@ -51,6 +51,7 @@ #include #include "empio.h" #include "empthread.h" +#include "file.h" #include "ioqueue.h" #include "misc.h" #include "queue.h" @@ -123,6 +124,9 @@ io_input(struct iop *iop, int waitforinput) int cc; int res; + if (waitforinput) + ef_make_stale(); + /* Not a read IOP */ if ((iop->flags & IO_READ) == 0) { errno = EBADF; @@ -183,6 +187,9 @@ io_output(struct iop *iop, int waitforoutput) int n; int remain; + if (waitforoutput) + ef_make_stale(); + /* If there is no output waiting. */ if (!io_outputwaiting(iop)) return 0; @@ -264,6 +271,9 @@ io_write(struct iop *iop, char *buf, int nbytes, int doWait) { int len; + if (doWait) + ef_make_stale(); + if ((iop->flags & IO_WRITE) == 0) return -1; ioq_append(iop->output, buf, nbytes); @@ -285,6 +295,8 @@ io_output_all(struct iop *iop) { int n; + ef_make_stale(); + /* * Mustn't block a player thread while update is pending, or else * a malicous player could delay the update indefinitely diff --git a/src/lib/empthread/lwp.c b/src/lib/empthread/lwp.c index 03bf4a64..66015a78 100644 --- a/src/lib/empthread/lwp.c +++ b/src/lib/empthread/lwp.c @@ -37,6 +37,7 @@ #include #include #include "empthread.h" +#include "file.h" #include "misc.h" /* Flags that were passed to empth_init() */ @@ -65,6 +66,7 @@ empth_create(void (*entry)(void *), int size, int flags, { if (!flags) flags = empth_flags; + ef_make_stale(); return lwpCreate(1, entry, size, flags, name, 0, 0, ud); } @@ -89,18 +91,21 @@ empth_set_name(empth_t *thread, char *name) 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); } @@ -113,6 +118,7 @@ empth_wakeup(empth_t *a) int empth_sleep(time_t until) { + ef_make_stale(); return lwpSleepUntil(until); } @@ -123,6 +129,7 @@ empth_wait_for_signal(void) int sig, err; time_t now; + ef_make_stale(); sigemptyset(&set); sigaddset(&set, SIGHUP); sigaddset(&set, SIGINT); @@ -153,12 +160,14 @@ empth_rwlock_destroy(empth_rwlock_t *rwlock) 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); } diff --git a/src/lib/subs/check.c b/src/lib/subs/check.c index f20f9617..6623a3ef 100644 --- a/src/lib/subs/check.c +++ b/src/lib/subs/check.c @@ -52,7 +52,11 @@ obj_changed(struct empobj *obj, size_t sz) 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 From bba8db34d0395795f24663d801dfe85531000ecd Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Mon, 2 Mar 2009 09:06:31 +0100 Subject: [PATCH 08/21] Fix generation numbers for SAIL fltp_to_list() makes copies without going through ef_read(), and therefore needs to mark them fresh by hand. --- src/lib/update/sail.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/lib/update/sail.c b/src/lib/update/sail.c index a1588759..85570e38 100644 --- a/src/lib/update/sail.c +++ b/src/lib/update/sail.c @@ -347,6 +347,7 @@ fltp_to_list(struct fltheadstr *fltp, struct emp_qelem *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); } From 8ebed5ba057d18a5ab08a0d7b2cee96c72f1f9ff Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Sun, 8 Mar 2009 18:49:06 +0100 Subject: [PATCH 09/21] Fix generation numbers for news file nreport() caches recent news reports in cache[], so it can collapse multiple news reports into one. Writing back such a collapsed news report triggered a generation oops when the processor had been yielded since the cached report was last written back. But this is actually perfectly safe, because the cache can't become stale: news file updates either go through the cache (nreport()), or they clear the entire cache (delete_old_news()). Silence the oops by marking the news report fresh. A case could be made for removing nws_generation alltogether. Maybe later. --- src/lib/subs/nreport.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/lib/subs/nreport.c b/src/lib/subs/nreport.c index 0bce9462..bcb9be58 100644 --- a/src/lib/subs/nreport.c +++ b/src/lib/subs/nreport.c @@ -61,6 +61,8 @@ nreport(natid actor, int event, natid victim, int times) return; np = ncache(actor, event, victim, times); + /* TODO get rid of nws_generation? */ + ef_mark_fresh(EF_NEWS, np); putnews(np->nws_uid, np); /* From ddbf8c482b1d45bebd43758edcc89cb66b27fd38 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Mon, 9 Mar 2009 21:22:03 +0100 Subject: [PATCH 10/21] Change fairland island size probability distribution Island size is randomly chosen from the interval [1..2*is+1], with expected value is. Use two dice to roll the size instead of one. This makes extreme sizes much less likely. --- src/util/fairland.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/util/fairland.c b/src/util/fairland.c index a8867f1f..88fe72ef 100644 --- a/src/util/fairland.c +++ b/src/util/fairland.c @@ -821,7 +821,7 @@ grow_islands(void) secs = 0; if (!place_island(c, &x, &y)) return; - isiz = 1 + rnd(2 * is - 1); + isiz = 1 + rnd(is) + rnd(is); do { ++secs; find_coast(c); From 839c6001d37488fd52f928ce7bca4d65eece395e Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Tue, 10 Mar 2009 20:48:05 +0100 Subject: [PATCH 11/21] Document disabling of anti-missile in info Hvy-Plastic --- info/Hvy-Plastic.t | 2 ++ 1 file changed, 2 insertions(+) diff --git a/info/Hvy-Plastic.t b/info/Hvy-Plastic.t index fa3f6a05..206610a3 100644 --- a/info/Hvy-Plastic.t +++ b/info/Hvy-Plastic.t @@ -34,6 +34,8 @@ Gold in mountains does not deplete at all. Oil production does not depend on tech; you don't have to micro-manage to conserve oil. .s1 +Ship capability anti-missile is disabled because of bugs. +.s1 Missed updates due to server problems will be forced if caught within 15 minutes of planned update time or skipped otherwise. .s1 From 48ba06732c33bfdd93972edd0e0c354140fdf092 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Tue, 10 Mar 2009 20:50:47 +0100 Subject: [PATCH 12/21] Fix assault not to send bogus telex to country 0 Happened when a spy got caught sneaking ashore and shot. (cherry picked from commit 7c6e56bd02d5a1dcfca6324bc1e4f788a42c8fcd) --- src/lib/commands/assa.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/commands/assa.c b/src/lib/commands/assa.c index 2d121a1c..97b138c4 100644 --- a/src/lib/commands/assa.c +++ b/src/lib/commands/assa.c @@ -181,7 +181,7 @@ assa(void) pr(" and was killed in the attempt.\n"); llp->unit.land.lnd_effic = 0; putland(llp->unit.land.lnd_uid, &llp->unit.land); - lnd_delete(llp, ""); + lnd_delete(llp, NULL); } else { wu(0, def->own, "%s spy spotted in %s.\n", cname(player->cnum), xyas(def->x, def->y, From 551676d5f2cbddb5d202279b904af64dc457af4d Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Mon, 16 Mar 2009 19:50:08 +0100 Subject: [PATCH 13/21] Document server time in info Hvy-Plastic --- info/Hvy-Plastic.t | 3 +++ 1 file changed, 3 insertions(+) diff --git a/info/Hvy-Plastic.t b/info/Hvy-Plastic.t index 206610a3..8bdfe622 100644 --- a/info/Hvy-Plastic.t +++ b/info/Hvy-Plastic.t @@ -36,6 +36,9 @@ to conserve oil. .s1 Ship capability anti-missile is disabled because of bugs. .s1 +Server time is in UTC, which means there will be no daylight savings +time. +.s1 Missed updates due to server problems will be forced if caught within 15 minutes of planned update time or skipped otherwise. .s1 From b8804d1cc0b09c9e378b56769c3a710f7d6a10bf Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Tue, 17 Mar 2009 20:07:20 +0100 Subject: [PATCH 14/21] Fix typo in journaling of output lines Screwed up in commit 9a19dc97. --- src/lib/subs/journal.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/subs/journal.c b/src/lib/subs/journal.c index 5eddb136..12d78e28 100644 --- a/src/lib/subs/journal.c +++ b/src/lib/subs/journal.c @@ -209,7 +209,7 @@ journal_output_1(struct player *pl, int id, journal_entry("output %d %d %s%.*s", pl->cnum, id, buf1, buf2prec, buf2); else - journal_entry("output %p %id %s%.*s", + journal_entry("output %p %d %s%.*s", pl, id, buf1, buf2prec, buf2); } From 56c28caf5b5f1abefe415a6a27d2d9bb610315c5 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Tue, 17 Mar 2009 20:19:49 +0100 Subject: [PATCH 15/21] Fix recipient thread in output journal Output journaling was cherry-picked from Hvy Metal II. However, how threads are identified in the journal changed since then. journal_output_1() needs updating for that. --- src/lib/subs/journal.c | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/src/lib/subs/journal.c b/src/lib/subs/journal.c index 12d78e28..ffe59f7d 100644 --- a/src/lib/subs/journal.c +++ b/src/lib/subs/journal.c @@ -201,16 +201,12 @@ journal_output(struct player *pl, int id, char *output) } } -void +static void journal_output_1(struct player *pl, int id, char *buf1, char *buf2, int buf2prec) { - if (pl && pl->state == PS_PLAYING) - journal_entry("output %d %d %s%.*s", - pl->cnum, id, buf1, buf2prec, buf2); - else - journal_entry("output %p %d %s%.*s", - pl, id, buf1, buf2prec, buf2); + journal_entry("output %s %d %s%.*s", + empth_name(empth_self()), id, buf1, buf2prec, buf2); } void From 2900de1f631976e96d556d85e70a385e927ae5da Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Sun, 22 Mar 2009 08:58:10 +0100 Subject: [PATCH 16/21] Don't log out player when he interrupts a command Broken in commit 3da4030a, v4.3.19. (cherry picked from commit 475f518be1154bac54c72bb9f543078779478e29) --- src/lib/player/player.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/player/player.c b/src/lib/player/player.c index cab28d43..030fe0e5 100644 --- a/src/lib/player/player.c +++ b/src/lib/player/player.c @@ -121,7 +121,7 @@ command(void) time_t now; if (getcommand(player->combuf) < 0) - return 0; + return player->aborted; now = time(NULL); update_timeused(now); From 56f2ca96f70cefdd6b70bb68fb06e29b5a6ac364 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Wed, 15 Apr 2009 23:06:54 +0200 Subject: [PATCH 17/21] Fix update to take dead units off carriers upd_plane() upd_land() and left planes and land units lost to lack of maintenance on their carriers. Cargo lists were fine anyway, because unit_cargo_init() ignored dead units. But when the dead unit got reused for building a new one, pln_prewrite() / lnd_prewrite() got confused and attempted to take it off its carrier, which made clink_rem() oops, because the unit wasn't on the cargo list. No real harm done, as oops recovery was fine. Fix upd_plane() and upd_land() to clear the carrier. Make unit_cargo_init() oops when it finds dead units on carriers. (cherry picked from commit c2c0d1ff77fef3adb0b8517c494838119b9b236f) --- src/lib/common/cargo.c | 15 ++++++++++++--- src/lib/update/land.c | 1 + src/lib/update/plane.c | 1 + 3 files changed, 14 insertions(+), 3 deletions(-) diff --git a/src/lib/common/cargo.c b/src/lib/common/cargo.c index 59ccf84b..d0c84d72 100644 --- a/src/lib/common/cargo.c +++ b/src/lib/common/cargo.c @@ -241,24 +241,33 @@ unit_cargo_init(void) unit_onresize(i); for (i = 0; (pp = getplanep(i)); i++) { - if (!pp->pln_own) + if (!pp->pln_own) { + if (CANT_HAPPEN(pp->pln_ship >= 0 || pp->pln_land >= 0)) + pp->pln_ship = pp->pln_land = -1; continue; + } if (CANT_HAPPEN(pp->pln_ship >= 0 && pp->pln_land >= 0)) pp->pln_land = -1; pln_carrier_change(pp, EF_SHIP, -1, pp->pln_ship); pln_carrier_change(pp, EF_LAND, -1, pp->pln_land); } for (i = 0; (lp = getlandp(i)); i++) { - if (!lp->lnd_own) + if (!lp->lnd_own) { + if (CANT_HAPPEN(lp->lnd_ship >= 0 || lp->lnd_land >= 0)) + lp->lnd_ship = lp->lnd_land = -1; continue; + } if (CANT_HAPPEN(lp->lnd_ship >= 0 && lp->lnd_land >= 0)) lp->lnd_land = -1; lnd_carrier_change(lp, EF_SHIP, -1, lp->lnd_ship); lnd_carrier_change(lp, EF_LAND, -1, lp->lnd_land); } for (i = 0; (np = getnukep(i)); i++) { - if (!np->nuk_own) + if (!np->nuk_own) { + if (CANT_HAPPEN(np->nuk_plane >= 0)) + np->nuk_plane = -1; continue; + } nuk_carrier_change(np, EF_PLANE, -1, np->nuk_plane); } } diff --git a/src/lib/update/land.c b/src/lib/update/land.c index 81ca77d3..41cc5682 100644 --- a/src/lib/update/land.c +++ b/src/lib/update/land.c @@ -125,6 +125,7 @@ upd_land(struct lndstr *lp, int etus, makelost(EF_LAND, lp->lnd_own, lp->lnd_uid, lp->lnd_x, lp->lnd_y); lp->lnd_own = 0; + lp->lnd_ship = lp->lnd_land = -1; return; } wu(0, lp->lnd_own, diff --git a/src/lib/update/plane.c b/src/lib/update/plane.c index f764f17c..dea614c0 100644 --- a/src/lib/update/plane.c +++ b/src/lib/update/plane.c @@ -110,6 +110,7 @@ upd_plane(struct plnstr *pp, int etus, makelost(EF_PLANE, pp->pln_own, pp->pln_uid, pp->pln_x, pp->pln_y); pp->pln_own = 0; + pp->pln_ship = pp->pln_land = -1; return; } wu(0, pp->pln_own, From 957f774a90b759abb31557f9b34ee77a8cf21055 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Thu, 16 Apr 2009 13:06:32 +0200 Subject: [PATCH 18/21] Fix return value of s_commod() when it can't draw enough s_commod() could incorrectly claim success when the sink ended up with at least as many supplies than were missing initially. This caused a number of problems: * shp_torp() let a ship with two shells fire a torpedo, resulting in -1 shells, which then made item_prewrite() oops. Affected missions and return fire, but not the torpedo command. * shp_missile_defense() let a ship with one shell use missile defense, resulting in -1 shells, and the same item_prewrite() oops. * Land units were considered in supply even when they had not quite enough supplies. Such land units could defend without penalty, attack and react. Commands load and lload weren't affected, because they use lnd_in_supply(), which doesn't use s_commod(). Broken in 98f24d5c, v4.3.20. (cherry picked from commit 1329c0e5441c592fa8e963ba1f70b655a1db2841) --- src/lib/subs/supply.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/subs/supply.c b/src/lib/subs/supply.c index 2650d33f..853e77fb 100644 --- a/src/lib/subs/supply.c +++ b/src/lib/subs/supply.c @@ -402,7 +402,7 @@ s_commod(struct empobj *sink, short *vec, if (actually_doit) put_empobj(sink->ef_type, sink->uid, sink); - return wanted <= vec[type]; + return 0; } /* From f571a37cde0f44e5b0ed0b99f02c3003f9c4c5af Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Sat, 18 Apr 2009 08:41:28 +0200 Subject: [PATCH 19/21] Fix tend land not to wipe out concurrent updates Fix tend_land() to bail out if the tender changed while tend_land() slept for the last argument (receiving ship). (cherry picked from commit 1ee02194c517e773888f2644c5dde30ac14f6f20) --- src/lib/commands/tend.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/commands/tend.c b/src/lib/commands/tend.c index 2c7dba37..c859d488 100644 --- a/src/lib/commands/tend.c +++ b/src/lib/commands/tend.c @@ -227,7 +227,7 @@ tend_land(struct shpstr *tenderp, char *units) if (!snxtitem(&targets, EF_SHIP, player->argp[4], "Ship to be tended? ")) return RET_FAIL; - if (!check_land_ok(&land)) + if (!check_ship_ok(tenderp) || !check_land_ok(&land)) return RET_SYN; while (nxtitem(&targets, &target)) { if (!player->owner && From bdcd59155a9a27dfe40d271dc1d16ff9d1c26e9d Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Sat, 18 Apr 2009 14:41:24 +0200 Subject: [PATCH 20/21] Really, really fix bomb not to wipe out plane updates Commit 82b5e3c2 missed escorts. (cherry picked from commit ce7fab3868c657c4b1240d3b303caa1bd78408ff) --- src/lib/commands/bomb.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/lib/commands/bomb.c b/src/lib/commands/bomb.c index f959e06d..589e5b73 100644 --- a/src/lib/commands/bomb.c +++ b/src/lib/commands/bomb.c @@ -157,6 +157,11 @@ bomb(void) plp = (struct plist *)qp; changed_plane_aborts(plp); } + for (qp = esc_list.q_forw; qp != &esc_list; qp = next) { + next = qp->q_forw; + plp = (struct plist *)qp; + changed_plane_aborts(plp); + } break; case 's': if (opt_SLOW_WAR) { From 9731e6692a1d326dcfe4b68daf82cd1572b62aad Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Fri, 24 Apr 2009 23:52:00 +0200 Subject: [PATCH 21/21] Fix generation numbers for autonav nav_ship() makes copies without going through ef_read(), and therefore needs to mark them fresh by hand. --- src/lib/update/nav_ship.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/lib/update/nav_ship.c b/src/lib/update/nav_ship.c index d57ed6aa..bb44bedb 100644 --- a/src/lib/update/nav_ship.c +++ b/src/lib/update/nav_ship.c @@ -268,6 +268,7 @@ nav_ship(struct shpstr *sp) 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);