/* Copyright 1995, 1997 J"orn Rennecke */
#include <signal.h>
#include "common.h"
#include "object.h"
#include "comm.h"
#define NEED_JOBTAB
#include "schedule.h"
int job_mask;
int32 async_current_time, current_time;
volatile int total_alarms, call_out_missing;
static void flag_call_out(void);
struct interactive **pending_link;
typedef union {
fd_set full;
struct {
long i[(MAX_USER+MAX_MISC_DESCRIPTORS-1)/8/sizeof(long)+1];
} small;
} fd_uset;
void schedule(void) {
fd_uset readfds[2];
static const struct itimerval itv = {
{ TICK_SEC, TICK_USEC } , { TICK_SEC, TICK_USEC }
};
static struct sigaction alarm_action = {
(RETSIGTYPE(*)(int))flag_call_out, 0, SA_RESTART
};
struct interactive *new_pending, *old_pending;
sigaction(SIGALRM, &alarm_action, 0);
setitimer(ITIMER_REAL, &itv, 0);
bzero(&readfds, sizeof readfds);
start_comm(&readfds[0].full);
pending_link = &new_pending;
for (;;) {
struct timeval timeout;
int npending;
readfds[1].small = readfds[0].small;
*pending_link = 0;
timeout.tv_sec = !((p_int)new_pending|job_tab.mask);
timeout.tv_usec = 0;
npending = select(comm_nfds, &readfds[1].full, 0, 0, &timeout);
old_pending = new_pending;
pending_link = &new_pending;
pending_commands(old_pending);
if (npending <= 0) {
if (npending && errno != EINTR)
perror("select");
} else {
/*
* walk_fdset() will read new commands, execute max. one per
* user, and append users with remaining commands to
* pending_link. It also handles new connections and erq.
*/
walk_fdset(&readfds[1].full, npending);
}
job_tab.mask |= job_tab.isr_mask[0];
EXTRA_JOBS();
}
}
void flag_call_out(void) {
call_out_missing +=
job_tab.isr_mask[0] | job_tab.isr_mask[1] >> JOB_check_call_out & 1;
ISR_SET_JOBS(JOB(call_out)+JOB(check_call_out));
total_alarms++;
}
void check_call_out() {
CLEAR_JOB(check_call_out);
TRANSFER_ISR_JOBS;
if (job_tab.mask & JOB(do_compact_mappings))
do_compact_mappings();
}
void shutdown_simulation() {
fatal("shutdown\n");
}