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.
This commit is contained in:
parent
0c52f203c0
commit
6cbdd3e02a
3 changed files with 13 additions and 14 deletions
|
@ -39,6 +39,7 @@
|
||||||
extern int shutdown_pending;
|
extern int shutdown_pending;
|
||||||
extern int update_pending;
|
extern int update_pending;
|
||||||
extern empth_sem_t *update_sem;
|
extern empth_sem_t *update_sem;
|
||||||
|
extern empth_rwlock_t *update_lock;
|
||||||
extern time_t update_time;
|
extern time_t update_time;
|
||||||
extern int updating_mob;
|
extern int updating_mob;
|
||||||
|
|
||||||
|
|
|
@ -88,10 +88,7 @@ dispatch(char *buf, char *redir)
|
||||||
pr("Command not implemented\n");
|
pr("Command not implemented\n");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
if (update_pending) {
|
empth_rwlock_rdlock(update_lock);
|
||||||
pr("Update in progress...command failed\n");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
if (redir) {
|
if (redir) {
|
||||||
prredir(redir);
|
prredir(redir);
|
||||||
uprnf(buf);
|
uprnf(buf);
|
||||||
|
@ -113,6 +110,7 @@ dispatch(char *buf, char *redir)
|
||||||
logerror("%s: returned bad value", command->c_form);
|
logerror("%s: returned bad value", command->c_form);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
empth_rwlock_unlock(update_lock);
|
||||||
player->command = 0;
|
player->command = 0;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -48,6 +48,7 @@
|
||||||
#include "server.h"
|
#include "server.h"
|
||||||
|
|
||||||
empth_sem_t *update_sem;
|
empth_sem_t *update_sem;
|
||||||
|
empth_rwlock_t *update_lock;
|
||||||
time_t update_time;
|
time_t update_time;
|
||||||
|
|
||||||
static void update_wait(void *unused);
|
static void update_wait(void *unused);
|
||||||
|
@ -61,9 +62,9 @@ update_sched(void *unused)
|
||||||
time_t now, delta;
|
time_t now, delta;
|
||||||
|
|
||||||
update_sem = empth_sem_create("Update", 0);
|
update_sem = empth_sem_create("Update", 0);
|
||||||
|
update_lock = empth_rwlock_create("Update");
|
||||||
empth_create(PP_SCHED, update_wait, (50 * 1024), 0, "UpdateWait",
|
empth_create(PP_SCHED, update_wait, (50 * 1024), 0, "UpdateWait",
|
||||||
"Waits until players idle", 0);
|
"Waits until players idle", 0);
|
||||||
time(&now);
|
|
||||||
if (s_p_etu <= 0) {
|
if (s_p_etu <= 0) {
|
||||||
logerror("bad value for s_p_etu (%d)", s_p_etu);
|
logerror("bad value for s_p_etu (%d)", s_p_etu);
|
||||||
s_p_etu = 2 * 60;
|
s_p_etu = 2 * 60;
|
||||||
|
@ -116,15 +117,12 @@ static void
|
||||||
update_wait(void *unused)
|
update_wait(void *unused)
|
||||||
{
|
{
|
||||||
struct player *p;
|
struct player *p;
|
||||||
int running;
|
|
||||||
time_t now;
|
|
||||||
int stacksize;
|
int stacksize;
|
||||||
struct player *dp;
|
struct player *dp;
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
empth_sem_wait(update_sem);
|
empth_sem_wait(update_sem);
|
||||||
update_pending = 1;
|
update_pending = 1;
|
||||||
running = 0;
|
|
||||||
for (p = player_next(0); p != 0; p = player_next(p)) {
|
for (p = player_next(0); p != 0; p = player_next(p)) {
|
||||||
if (p->state != PS_PLAYING)
|
if (p->state != PS_PLAYING)
|
||||||
continue;
|
continue;
|
||||||
|
@ -132,17 +130,13 @@ update_wait(void *unused)
|
||||||
pr_flash(p, "Update aborting command\n");
|
pr_flash(p, "Update aborting command\n");
|
||||||
p->aborted = 1;
|
p->aborted = 1;
|
||||||
empth_wakeup(p->proc);
|
empth_wakeup(p->proc);
|
||||||
running++;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
time(&now);
|
empth_rwlock_wrlock(update_lock);
|
||||||
if (running) {
|
|
||||||
/* sleep a few, wait for aborts to take effect */
|
|
||||||
empth_sleep(now + 2);
|
|
||||||
}
|
|
||||||
if (*pre_update_hook) {
|
if (*pre_update_hook) {
|
||||||
if (run_hook(pre_update_hook, "pre-update")) {
|
if (run_hook(pre_update_hook, "pre-update")) {
|
||||||
update_pending = 0;
|
update_pending = 0;
|
||||||
|
empth_rwlock_unlock(update_lock);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -154,6 +148,7 @@ update_wait(void *unused)
|
||||||
if (!dp) {
|
if (!dp) {
|
||||||
logerror("can't create dummy player for update");
|
logerror("can't create dummy player for update");
|
||||||
update_pending = 0;
|
update_pending = 0;
|
||||||
|
empth_rwlock_unlock(update_lock);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
stacksize = 100000 +
|
stacksize = 100000 +
|
||||||
|
@ -162,6 +157,11 @@ update_wait(void *unused)
|
||||||
|
|
||||||
empth_create(PP_UPDATE, update_main, stacksize, 0,
|
empth_create(PP_UPDATE, update_main, stacksize, 0,
|
||||||
"UpdateRun", "Updates the world", dp);
|
"UpdateRun", "Updates the world", dp);
|
||||||
|
|
||||||
|
while (update_pending)
|
||||||
|
empth_yield(); /* FIXME cheesy! */
|
||||||
|
update_pending = 0;
|
||||||
|
empth_rwlock_unlock(update_lock);
|
||||||
}
|
}
|
||||||
/*NOTREACHED*/
|
/*NOTREACHED*/
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue