From: Markus Armbruster Date: Mon, 15 Jan 2007 19:57:26 +0000 (+0000) Subject: Synchronize commands and update properly with a lock (towards X-Git-Tag: v4.3.10~277 X-Git-Url: http://git.pond.sub.org/?p=empserver;a=commitdiff_plain;h=6cbdd3e02a4126653523426051738414763c5de6 Synchronize commands and update properly with a lock (towards resolving #1458175 and #1504036): (update_lock): New. (update_shed): Initialize it. (update_wait, dispatch): Take exclusive update_lock around the update, shared update_lock around commands. This makes the update block until all aborted commands terminated and gave up their lock. Remove the cheesy and unsafe two second wait for commands to finish. It also makes player threads block before executing commands while the update is pending, removing the need to fail commands then. So don't. --- diff --git a/include/server.h b/include/server.h index b82052360..2f4485e26 100644 --- a/include/server.h +++ b/include/server.h @@ -39,6 +39,7 @@ extern int shutdown_pending; extern int update_pending; extern empth_sem_t *update_sem; +extern empth_rwlock_t *update_lock; extern time_t update_time; extern int updating_mob; diff --git a/src/lib/player/dispatch.c b/src/lib/player/dispatch.c index 90b33c74e..c1d9182e9 100644 --- a/src/lib/player/dispatch.c +++ b/src/lib/player/dispatch.c @@ -88,10 +88,7 @@ dispatch(char *buf, char *redir) pr("Command not implemented\n"); return 0; } - if (update_pending) { - pr("Update in progress...command failed\n"); - return 0; - } + empth_rwlock_rdlock(update_lock); if (redir) { prredir(redir); uprnf(buf); @@ -113,6 +110,7 @@ dispatch(char *buf, char *redir) logerror("%s: returned bad value", command->c_form); break; } + empth_rwlock_unlock(update_lock); player->command = 0; return 0; } diff --git a/src/server/update.c b/src/server/update.c index 75c3952c5..b6de55c17 100644 --- a/src/server/update.c +++ b/src/server/update.c @@ -48,6 +48,7 @@ #include "server.h" empth_sem_t *update_sem; +empth_rwlock_t *update_lock; time_t update_time; static void update_wait(void *unused); @@ -61,9 +62,9 @@ update_sched(void *unused) time_t now, delta; update_sem = empth_sem_create("Update", 0); + update_lock = empth_rwlock_create("Update"); empth_create(PP_SCHED, update_wait, (50 * 1024), 0, "UpdateWait", "Waits until players idle", 0); - time(&now); if (s_p_etu <= 0) { logerror("bad value for s_p_etu (%d)", s_p_etu); s_p_etu = 2 * 60; @@ -116,15 +117,12 @@ static void update_wait(void *unused) { struct player *p; - int running; - time_t now; int stacksize; struct player *dp; while (1) { empth_sem_wait(update_sem); update_pending = 1; - running = 0; for (p = player_next(0); p != 0; p = player_next(p)) { if (p->state != PS_PLAYING) continue; @@ -132,17 +130,13 @@ update_wait(void *unused) pr_flash(p, "Update aborting command\n"); p->aborted = 1; empth_wakeup(p->proc); - running++; } } - time(&now); - if (running) { - /* sleep a few, wait for aborts to take effect */ - empth_sleep(now + 2); - } + empth_rwlock_wrlock(update_lock); if (*pre_update_hook) { if (run_hook(pre_update_hook, "pre-update")) { update_pending = 0; + empth_rwlock_unlock(update_lock); continue; } } @@ -154,6 +148,7 @@ update_wait(void *unused) if (!dp) { logerror("can't create dummy player for update"); update_pending = 0; + empth_rwlock_unlock(update_lock); continue; } stacksize = 100000 + @@ -162,6 +157,11 @@ update_wait(void *unused) empth_create(PP_UPDATE, update_main, stacksize, 0, "UpdateRun", "Updates the world", dp); + + while (update_pending) + empth_yield(); /* FIXME cheesy! */ + update_pending = 0; + empth_rwlock_unlock(update_lock); } /*NOTREACHED*/ }