00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037 #include <config.h>
00038
00039 #include <errno.h>
00040 #ifndef _WIN32
00041 #include <sys/wait.h>
00042 #endif
00043 #include <time.h>
00044 #include "empthread.h"
00045 #include "game.h"
00046 #include "misc.h"
00047 #include "optlist.h"
00048 #include "player.h"
00049 #include "prototypes.h"
00050 #include "server.h"
00051
00052
00053
00054
00055
00056 int update_running;
00057
00058 static time_t update_schedule_anchor;
00059 static int update_wanted;
00060
00061 static empth_t *update_thread;
00062
00063 static int update_get_schedule(void);
00064 static void update_sched(void *);
00065 static void update_run(void);
00066 static int run_hook(char *cmd, char *name);
00067
00068 void
00069 update_init(void)
00070 {
00071 struct player *dp;
00072 int stacksize;
00073
00074 update_schedule_anchor = (time(NULL) + 59) / 60 * 60;
00075 if (update_get_schedule() < 0)
00076 exit(1);
00077
00078 play_lock = empth_rwlock_create("Update");
00079 if (!play_lock)
00080 exit_nomem();
00081
00082 dp = player_new(-1);
00083 if (!dp)
00084 exit_nomem();
00085
00086 stacksize = 100000 +
00087 WORLD_X * WORLD_Y * (2 * sizeof(double) +
00088 sizeof(char *));
00089 update_thread = empth_create(update_sched, stacksize, 0,
00090 "Update", dp);
00091 if (!update_thread)
00092 exit_nomem();
00093 }
00094
00095
00096
00097
00098
00099 static int
00100 update_get_schedule(void)
00101 {
00102 time_t now = time(NULL);
00103
00104 if (read_schedule(schedulefil, update_time,
00105 sizeof(update_time) / sizeof(*update_time),
00106 now + 30, update_schedule_anchor) < 0) {
00107 logerror("No update schedule!");
00108 update_time[0] = 0;
00109 return -1;
00110 }
00111 logerror("Update schedule read");
00112 return 0;
00113 }
00114
00115
00116 static void
00117 update_sched(void *unused)
00118 {
00119 time_t next_update, now;
00120
00121 player->proc = empth_self();
00122 player->cnum = 0;
00123 player->god = 1;
00124
00125 for (;;) {
00126
00127
00128
00129
00130 next_update = update_time[0];
00131 if (next_update) {
00132 if (update_window > 0)
00133 next_update += random() % update_window;
00134 logerror("Next update at %s", ctime(&next_update));
00135
00136 empth_sleep(next_update);
00137 } else {
00138 logerror("No update scheduled");
00139
00140 while (empth_sleep(time(NULL) + (60 * 60 * 24)) >= 0) ;
00141 }
00142
00143 now = time(NULL);
00144 if (next_update != 0 && now >= next_update) {
00145
00146 if (now >= next_update + 60)
00147 logerror("Missed the update!");
00148 else if (update_demand == UPD_DEMAND_SCHED && !demand_check())
00149 ;
00150 else if (updates_disabled())
00151 logerror("Updates disabled...skipping update");
00152 else
00153 update_wanted = 1;
00154 update_schedule_anchor = update_time[0];
00155 }
00156
00157
00158 if (update_wanted) {
00159 update_wanted = 0;
00160 update_run();
00161 }
00162
00163 update_get_schedule();
00164 }
00165
00166 }
00167
00168
00169
00170
00171
00172 int
00173 update_trigger(void)
00174 {
00175 logerror("Triggering unscheduled update");
00176 update_wanted = 1;
00177 empth_wakeup(update_thread);
00178 return 0;
00179 }
00180
00181
00182
00183
00184
00185 int
00186 update_reschedule(void)
00187 {
00188 empth_wakeup(update_thread);
00189 return 0;
00190 }
00191
00192 static void
00193 update_run(void)
00194 {
00195 struct player *p;
00196
00197 play_wrlock_wanted = 1;
00198 for (p = player_next(0); p != 0; p = player_next(p)) {
00199 if (p->state != PS_PLAYING)
00200 continue;
00201 if (p->command) {
00202 pr_flash(p, "Update aborting command\n");
00203 p->aborted = 1;
00204 empth_wakeup(p->proc);
00205 }
00206 }
00207 empth_rwlock_wrlock(play_lock);
00208 if (*pre_update_hook) {
00209 if (run_hook(pre_update_hook, "pre-update")) {
00210 play_wrlock_wanted = 0;
00211 empth_rwlock_unlock(play_lock);
00212 return;
00213 }
00214 }
00215 update_running = 1;
00216 update_main();
00217 play_wrlock_wanted = update_running = 0;
00218 empth_rwlock_unlock(play_lock);
00219 }
00220
00221 static int
00222 run_hook(char *cmd, char *name)
00223 {
00224 int status;
00225
00226 fflush(NULL);
00227
00228 status = system(cmd);
00229 if (status == 0)
00230 ;
00231 else if (status == -1)
00232 logerror("couldn't execute command processor for %s hook (%s)",
00233 name, strerror(errno));
00234 #ifndef _WIN32
00235 else if (WIFEXITED(status))
00236 logerror("%s hook terminated unsuccessfully (exit status %d)",
00237 name, WEXITSTATUS(status));
00238 else if (WIFSIGNALED(status))
00239 logerror("%s hook terminated abnormally (signal %d)",
00240 name, WTERMSIG(status));
00241 #endif
00242 else if (status)
00243 logerror("%s hook terminated strangely (status %d)",
00244 name, status);
00245 return status;
00246 }