* The watchdog timer function, implementing all but the actual reset.
*/
static void
-kbd_watchdog(minix_timer_t *UNUSED(tmrp))
+kbd_watchdog(int arg __unused)
{
kbd_watchdog_set = 0;
if (!kbdout.avail)
u8_t packet[ATAPI_PACKET_SIZE], prd_t *prdt, int nr_prds, int write);
static void port_issue(struct port_state *ps, int cmd, clock_t timeout);
static int port_exec(struct port_state *ps, int cmd, clock_t timeout);
-static void port_timeout(minix_timer_t *tp);
+static void port_timeout(int arg);
static void port_disconnect(struct port_state *ps);
static char *ahci_portname(struct port_state *ps);
/*===========================================================================*
* port_timeout *
*===========================================================================*/
-static void port_timeout(minix_timer_t *tp)
+static void port_timeout(int arg)
{
/* A timeout has occurred on this port. Figure out what the timeout is
* for, and take appropriate action.
struct port_state *ps;
int port, cmd;
- port = GET_PORT(tmr_arg(tp)->ta_int);
- cmd = GET_TAG(tmr_arg(tp)->ta_int);
+ port = GET_PORT(arg);
+ cmd = GET_TAG(arg);
assert(port >= 0 && port < hba_state.nr_ports);
static minix_timer_t f_tmr_timeout; /* timer for various timeouts */
static u32_t system_hz; /* system clock frequency */
static void f_expire_tmrs(clock_t stamp);
-static void stop_motor(minix_timer_t *tp);
-static void f_timeout(minix_timer_t *tp);
+static void stop_motor(int arg);
+static void f_timeout(int arg);
static struct device *f_prepare(devminor_t device);
static struct device *f_part(devminor_t minor);
/*===========================================================================*
* stop_motor *
*===========================================================================*/
-static void stop_motor(minix_timer_t *tp)
+static void stop_motor(int arg)
{
/* This routine is called from an alarm timer after several seconds have
* elapsed with no floppy disk activity. It turns the drive motor off.
*/
int s;
- motor_status &= ~(1 << tmr_arg(tp)->ta_int);
+ motor_status &= ~(1 << arg);
if ((s=sys_outb(DOR, (motor_status << MOTOR_SHIFT) | ENABLE_INT)) != OK)
panic("Sys_outb in stop_motor() failed: %d", s);
}
/*===========================================================================*
* f_timeout *
*===========================================================================*/
-static void f_timeout(minix_timer_t *UNUSED(tp))
+static void f_timeout(int arg __unused)
{
/* This routine is called when a timer expires. Usually to tell that a
* motor has spun up, but also to forge an interrupt when it takes too long
/* A device exists if at least its 'devread' function is defined. */
#define tty_active(tp) ((tp)->tty_devread != NULL)
-static void tty_timed_out(minix_timer_t *tp);
+static void tty_timed_out(int arg);
static void settimer(tty_t *tty_ptr, int enable);
static void in_transfer(tty_t *tp);
static int tty_echo(tty_t *tp, int ch);
/*===========================================================================*
* tty_timed_out *
*===========================================================================*/
-static void tty_timed_out(minix_timer_t *tp)
+static void tty_timed_out(int arg)
{
/* This timer has expired. Set the events flag, to force processing. */
tty_t *tty_ptr;
- tty_ptr = &tty_table[tmr_arg(tp)->ta_int];
+ tty_ptr = &tty_table[arg];
tty_ptr->tty_min = 0; /* force read to succeed */
tty_ptr->tty_events = 1;
}
static void parse_escape(console_t *cons, int c);
static void scroll_screen(console_t *cons, int dir);
static void set_6845(int reg, unsigned val);
-static void stop_beep(minix_timer_t *tmrp);
+static void stop_beep(int arg);
static void cons_org0(void);
static void disable_console(void);
static void reenable_console(void);
/*===========================================================================*
* stop_beep *
*===========================================================================*/
-static void stop_beep(minix_timer_t *UNUSED(tmrp))
+static void stop_beep(int arg __unused)
{
/* Turn off the beeper by turning off bits 0 and 1 in PORT_B. */
u32_t port_b_val;
struct kmessages kmess;
-static void tty_timed_out(minix_timer_t *tp);
+static void tty_timed_out(int arg);
static void settimer(tty_t *tty_ptr, int enable);
static void in_transfer(tty_t *tp);
static int tty_echo(tty_t *tp, int ch);
/*===========================================================================*
* tty_timed_out *
*===========================================================================*/
-static void tty_timed_out(minix_timer_t *tp)
+static void tty_timed_out(int arg)
{
/* This timer has expired. Set the events flag, to force processing. */
tty_t *tty_ptr;
- tty_ptr = &tty_table[tmr_arg(tp)->ta_int];
+ tty_ptr = &tty_table[arg];
tty_ptr->tty_min = 0; /* force read to succeed */
tty_ptr->tty_events = 1;
}
#include <limits.h>
#include <sys/types.h>
+#include <minix/const.h>
#include <minix/u64.h>
#include <minix/minlib.h>
#include <minix/endpoint.h>
-struct minix_timer;
-typedef void (*tmr_func_t)(struct minix_timer *tp);
-typedef union { int ta_int; long ta_long; void *ta_ptr; } ixfer_tmr_arg_t;
+typedef void (*tmr_func_t)(int arg);
/* A minix_timer_t variable must be declare for each distinct timer to be used.
* The timers watchdog function and expiration time are automatically set
- * by the library function tmrs_settimer, but its argument is not.
+ * by the library function tmrs_settimer, but its argument is not. In general,
+ * the timer is in use when it has a callback function.
*/
typedef struct minix_timer
{
struct minix_timer *tmr_next; /* next in a timer chain */
- clock_t tmr_exp_time; /* expiration time */
- tmr_func_t tmr_func; /* function to call when expired */
- ixfer_tmr_arg_t tmr_arg; /* random argument */
+ clock_t tmr_exp_time; /* expiration time (absolute) */
+ tmr_func_t tmr_func; /* function to call when expired */
+ int tmr_arg; /* integer argument */
} minix_timer_t;
-/* Used when the timer is not active. */
-#define TMR_NEVER ((clock_t) -1 < 0) ? ((clock_t) LONG_MAX) : ((clock_t) -1)
-#undef TMR_NEVER
-#define TMR_NEVER ((clock_t) LONG_MAX)
+/*
+ * Clock times may wrap. Thus, we must only ever compare relative times, which
+ * means they must be no more than half the total maximum time value apart.
+ * The clock_t type is unsigned (int or long), thus we take half that.
+ */
+#define TMRDIFF_MAX (INT_MAX)
+
+/* This value must be used only instead of a timer difference value. */
+#define TMR_NEVER ((clock_t)TMRDIFF_MAX + 1)
/* These definitions can be used to set or get data from a timer variable. */
-#define tmr_arg(tp) (&(tp)->tmr_arg)
-#define tmr_exp_time(tp) (&(tp)->tmr_exp_time)
+#define tmr_exp_time(tp) ((tp)->tmr_exp_time)
+#define tmr_is_set(tp) ((tp)->tmr_func != NULL)
+/*
+ * tmr_is_first() returns TRUE iff the first given absolute time is sooner than
+ * or equal to the second given time.
+ */
+#define tmr_is_first(a,b) ((clock_t)(b) - (clock_t)(a) <= TMRDIFF_MAX)
+#define tmr_has_expired(tp,now) tmr_is_first((tp)->tmr_exp_time, (now))
/* Timers should be initialized once before they are being used. Be careful
* not to reinitialize a timer that is in a list of timers, or the chain
* will be broken.
*/
-#define tmr_inittimer(tp) (void)((tp)->tmr_exp_time = TMR_NEVER, \
- (tp)->tmr_next = NULL)
+#define tmr_inittimer(tp) (void)((tp)->tmr_func = NULL, (tp)->tmr_next = NULL)
/* The following generic timer management functions are available. They
* can be used to operate on the lists of timers. Adding a timer to a list
* automatically takes care of removing it.
*/
-clock_t tmrs_clrtimer(minix_timer_t **tmrs, minix_timer_t *tp, clock_t *new_head);
-void tmrs_exptimers(minix_timer_t **tmrs, clock_t now, clock_t *new_head);
-clock_t tmrs_settimer(minix_timer_t **tmrs, minix_timer_t *tp, clock_t exp_time,
- tmr_func_t watchdog, clock_t *new_head);
+int tmrs_settimer(minix_timer_t **tmrs, minix_timer_t *tp, clock_t exp_time,
+ tmr_func_t watchdog, int arg, clock_t *old_head, clock_t *new_head);
+int tmrs_clrtimer(minix_timer_t **tmrs, minix_timer_t *tp, clock_t *old_head,
+ clock_t *new_head);
+int tmrs_exptimers(minix_timer_t **tmrs, clock_t now, clock_t *new_head);
#define PRINT_STATS(cum_spenttime, cum_instances) { \
if(ex64hi(cum_spenttime)) { util_stacktrace(); printf(" ( ??? %lu %lu)\n", \
*/
void init_timer(minix_timer_t *tp);
-void set_timer(minix_timer_t *tp, int ticks, tmr_func_t watchdog, int arg);
+void set_timer(minix_timer_t *tp, clock_t ticks, tmr_func_t watchdog, int arg);
void cancel_timer(minix_timer_t *tp);
void expire_timers(clock_t now);
* longer used and the "real" implementations are visible
*/
void send_diag_sig(void) { }
-void minix_shutdown(minix_timer_t *t) { arch_shutdown(0); }
+void minix_shutdown(int how) { arch_shutdown(how); }
void busy_delay_ms(int x) { }
int raise(int n) { panic("raise(%d)\n", n); }
int kern_phys_map_ptr( phys_bytes base_address, vir_bytes io_size, int vm_flags,
switch(c)
{
case 'Q':
- minix_shutdown(NULL);
+ minix_shutdown(0);
NOT_REACHABLE;
#ifdef CONFIG_SMP
case 'B':
}
void send_diag_sig(void) { }
-void minix_shutdown(minix_timer_t *t) { arch_shutdown(0); }
+void minix_shutdown(int how) { arch_shutdown(how); }
void busy_delay_ms(int x) { }
int raise(int sig) { panic("raise(%d)\n", sig); }
* When a timer expires its watchdog function is run by the CLOCK task.
*/
static minix_timer_t *clock_timers; /* queue of CLOCK timers */
-static clock_t next_timeout; /* monotonic time that next timer expires */
/* Number of ticks to adjust realtime by. A negative value implies slowing
* down realtime, a positive value implies speeding it up.
load_update();
if (cpu_is_bsp(cpuid)) {
- /* if a timer expired, notify the clock task */
- if ((next_timeout <= kclockinfo.uptime)) {
+ /*
+ * If a timer expired, notify the clock task. Keep in mind
+ * that clock tick values may overflow, so we must only look at
+ * relative differences, and only if there are timers at all.
+ */
+ if (clock_timers != NULL &&
+ tmr_has_expired(clock_timers, kclockinfo.uptime))
tmrs_exptimers(&clock_timers, kclockinfo.uptime, NULL);
- next_timeout = (clock_timers == NULL) ?
- TMR_NEVER : clock_timers->tmr_exp_time;
- }
#ifdef DEBUG_SERIAL
if (kinfo.do_serial_debug)
void set_kernel_timer(
minix_timer_t *tp, /* pointer to timer structure */
clock_t exp_time, /* expiration monotonic time */
- tmr_func_t watchdog /* watchdog to be called */
+ tmr_func_t watchdog, /* watchdog to be called */
+ int arg /* argument for watchdog function */
)
{
/* Insert the new timer in the active timers list. Always update the
* next timeout time by setting it to the front of the active list.
*/
- tmrs_settimer(&clock_timers, tp, exp_time, watchdog, NULL);
- next_timeout = clock_timers->tmr_exp_time;
+ (void)tmrs_settimer(&clock_timers, tp, exp_time, watchdog, arg, NULL, NULL);
}
/*===========================================================================*
* active and expired lists. Always update the next timeout time by setting
* it to the front of the active list.
*/
- tmrs_clrtimer(&clock_timers, tp, NULL);
- next_timeout = (clock_timers == NULL) ?
- TMR_NEVER : clock_timers->tmr_exp_time;
+ if (tmr_is_set(tp))
+ (void)tmrs_clrtimer(&clock_timers, tp, NULL, NULL);
}
/*===========================================================================*
* argument passes the shutdown status.
*/
printf("MINIX will now be shut down ...\n");
- tmr_arg(&shutdown_timer)->ta_int = how;
- set_kernel_timer(&shutdown_timer, get_monotonic() + system_hz, minix_shutdown);
+ set_kernel_timer(&shutdown_timer, get_monotonic() + system_hz,
+ minix_shutdown, how);
}
/*===========================================================================*
* shutdown *
*===========================================================================*/
-void minix_shutdown(minix_timer_t *tp)
+void minix_shutdown(int how)
{
/* This function is called from prepare_shutdown or stop_sequence to bring
* down MINIX.
*/
- int how;
#ifdef CONFIG_SMP
/*
hw_intr_disable_all();
stop_local_timer();
- how = tp ? tmr_arg(tp)->ta_int : 0;
-
/* Show shutdown message */
direct_cls();
if((how & RB_POWERDOWN) == RB_POWERDOWN)
clock_t get_monotonic(void);
void set_boottime(time_t);
time_t get_boottime(void);
-void set_kernel_timer(minix_timer_t *tp, clock_t t, tmr_func_t f);
+void set_kernel_timer(minix_timer_t *tp, clock_t t, tmr_func_t f, int arg);
void reset_kernel_timer(minix_timer_t *tp);
void ser_dump_proc(void);
#endif
void kmain(kinfo_t *cbi);
void prepare_shutdown(int how);
-__dead void minix_shutdown(minix_timer_t *tp);
+__dead void minix_shutdown(int how);
void bsp_finish_booting(void);
/* proc.c */
#if USE_SETALARM
-static void cause_alarm(minix_timer_t *tp);
+static void cause_alarm(int proc_nr_e);
/*===========================================================================*
* do_setalarm *
clock_t uptime; /* placeholder for current uptime */
/* Extract shared parameters from the request message. */
- exp_time = m_ptr->m_lsys_krn_sys_setalarm.exp_time; /* alarm's expiration time */
- use_abs_time = m_ptr->m_lsys_krn_sys_setalarm.abs_time; /* flag for absolute time */
+ exp_time = m_ptr->m_lsys_krn_sys_setalarm.exp_time;
+ use_abs_time = m_ptr->m_lsys_krn_sys_setalarm.abs_time;
if (! (priv(caller)->s_flags & SYS_PROC)) return(EPERM);
/* Get the timer structure and set the parameters for this alarm. */
tp = &(priv(caller)->s_alarm_timer);
- tmr_arg(tp)->ta_int = caller->p_endpoint;
- tp->tmr_func = cause_alarm;
/* Return the ticks left on the previous alarm. */
uptime = get_monotonic();
- if (tp->tmr_exp_time == TMR_NEVER) {
- m_ptr->m_lsys_krn_sys_setalarm.time_left = TMR_NEVER;
- } else if (uptime < tp->tmr_exp_time) {
- m_ptr->m_lsys_krn_sys_setalarm.time_left = (tp->tmr_exp_time - uptime);
+ if (!tmr_is_set(tp)) {
+ m_ptr->m_lsys_krn_sys_setalarm.time_left = TMR_NEVER;
+ } else if (tmr_is_first(uptime, tp->tmr_exp_time)) {
+ m_ptr->m_lsys_krn_sys_setalarm.time_left = tp->tmr_exp_time - uptime;
} else {
- m_ptr->m_lsys_krn_sys_setalarm.time_left = 0;
+ m_ptr->m_lsys_krn_sys_setalarm.time_left = 0;
}
/* For the caller's convenience, also return the current time. */
m_ptr->m_lsys_krn_sys_setalarm.uptime = uptime;
- /* Finally, (re)set the timer depending on the expiration time. */
- if (exp_time == 0) {
- reset_kernel_timer(tp);
+ /*
+ * Finally, (re)set the timer depending on the expiration time. Note that
+ * an absolute time of zero is as valid as any other absolute value, so only
+ * a relative time value of zero resets the timer.
+ */
+ if (!use_abs_time && exp_time == 0) {
+ reset_kernel_timer(tp);
} else {
- tp->tmr_exp_time = (use_abs_time) ? exp_time : exp_time + get_monotonic();
- set_kernel_timer(tp, tp->tmr_exp_time, tp->tmr_func);
+ if (!use_abs_time)
+ exp_time += uptime;
+ set_kernel_timer(tp, exp_time, cause_alarm, caller->p_endpoint);
}
return(OK);
}
/*===========================================================================*
* cause_alarm *
*===========================================================================*/
-static void cause_alarm(minix_timer_t *tp)
+static void cause_alarm(int proc_nr_e)
{
/* Routine called if a timer goes off and the process requested a synchronous
- * alarm. The process number is stored in timer argument 'ta_int'. Notify that
+ * alarm. The process number is stored as the timer argument. Notify that
* process with a notification message from CLOCK.
*/
- endpoint_t proc_nr_e = tmr_arg(tp)->ta_int; /* get process number */
mini_notify(proc_addr(CLOCK), proc_nr_e); /* notify process */
}
#endif
/* Abort MINIX. */
- minix_shutdown(NULL);
+ minix_shutdown(0);
}
/*===========================================================================*
/*
* Ask the kernel to schedule a synchronous alarm for the caller, using either
- * an absolute or a relative number of clock ticks. Optionally return the time
- * left on the previous timer (TMR_NEVER if none was set) and the current time.
+ * an absolute or a relative number of clock ticks. The new alarm replaces any
+ * previously set alarm. If a relative expiry time of zero is given, the
+ * current alarm is stopped. Return OK or a negative error code. On success,
+ * optionally return the time left on the previous timer (TMR_NEVER if none was
+ * set) and the current time.
*/
int
sys_setalarm2(clock_t exp_time, int abs_time, clock_t * time_left,
-/* Watchdog timer management. These functions in this file provide a
+/*
+ * Watchdog timer management. These functions in this file provide a
* convenient interface to the timers library that manages a list of
* watchdog timers. All details of scheduling an alarm at the CLOCK task
* are hidden behind this interface.
#include <minix/sysutil.h>
static minix_timer_t *timers = NULL;
-static int expiring = 0;
+static int expiring = FALSE;
-/*===========================================================================*
- * init_timer *
- *===========================================================================*/
-void init_timer(minix_timer_t *tp)
+/*
+ * Initialize the timer 'tp'.
+ */
+void
+init_timer(minix_timer_t * tp)
{
- tmr_inittimer(tp);
+
+ tmr_inittimer(tp);
}
-/*===========================================================================*
- * set_timer *
- *===========================================================================*/
-void set_timer(minix_timer_t *tp, int ticks, tmr_func_t watchdog, int arg)
+/*
+ * Set the timer 'tp' to trigger 'ticks' clock ticks in the future. When it
+ * triggers, call function 'watchdog' with argument 'arg'. The given timer
+ * object must have been initialized with init_timer(3) already. The given
+ * number of ticks must be between 0 and TMRDIFF_MAX inclusive. A ticks value
+ * of zero will cause the alarm to trigger on the next clock tick. If the
+ * timer was already set, it will be canceled first.
+ */
+void
+set_timer(minix_timer_t *tp, clock_t ticks, tmr_func_t watchdog, int arg)
{
- clock_t prev_time = 0, next_time;
+ clock_t prev_time, next_time;
+ int r, had_timers;
- /* Set timer argument and add timer to the list. */
- tmr_arg(tp)->ta_int = arg;
- prev_time = tmrs_settimer(&timers, tp, getticks() + ticks, watchdog,
- &next_time);
+ if (ticks > TMRDIFF_MAX)
+ panic("set_timer: ticks value too large: %u", (int)ticks);
- /* Reschedule our synchronous alarm if necessary. */
- if (expiring == 0 && (! prev_time || prev_time > next_time)) {
- if (sys_setalarm(next_time, 1) != OK)
- panic("set_timer: couldn't set alarm");
+ /* Add the timer to the list. */
+ had_timers = tmrs_settimer(&timers, tp, getticks() + ticks, watchdog,
+ arg, &prev_time, &next_time);
+
+ /* Reschedule our synchronous alarm if necessary. */
+ if (!expiring && (!had_timers || next_time != prev_time)) {
+ if ((r = sys_setalarm(next_time, TRUE /*abs_time*/)) != OK)
+ panic("set_timer: couldn't set alarm: %d", r);
}
}
-/*===========================================================================*
- * cancel_timer *
- *===========================================================================*/
-void cancel_timer(minix_timer_t *tp)
+/*
+ * Cancel the timer 'tp'. The timer object must have been initialized with
+ * init_timer(3) first. If the timer was not set before, the call is a no-op.
+ */
+void
+cancel_timer(minix_timer_t * tp)
{
- clock_t next_time, prev_time;
- prev_time = tmrs_clrtimer(&timers, tp, &next_time);
-
- /* If the earliest timer has been removed, we have to set the alarm to
- * the next timer, or cancel the alarm altogether if the last timer
- * has been cancelled (next_time will be 0 then).
- */
- if (expiring == 0 && (prev_time < next_time || ! next_time)) {
- if (sys_setalarm(next_time, 1) != OK)
- panic("cancel_timer: couldn't set alarm");
+ clock_t next_time, prev_time;
+ int r, have_timers;
+
+ if (!tmr_is_set(tp))
+ return;
+
+ have_timers = tmrs_clrtimer(&timers, tp, &prev_time, &next_time);
+
+ /*
+ * If the earliest timer has been removed, we have to set the alarm to
+ * the next timer, or cancel the alarm altogether if the last timer
+ * has been canceled.
+ */
+ if (!expiring) {
+ if (!have_timers)
+ r = sys_setalarm(0, FALSE /*abs_time*/);
+ else if (prev_time != next_time)
+ r = sys_setalarm(next_time, TRUE /*abs_time*/);
+ else
+ r = OK;
+
+ if (r != OK)
+ panic("cancel_timer: couldn't set alarm: %d", r);
}
}
-/*===========================================================================*
- * expire_timers *
- *===========================================================================*/
-void expire_timers(clock_t now)
+/*
+ * Expire all timers that were set to expire before/at the given current time.
+ */
+void
+expire_timers(clock_t now)
{
clock_t next_time;
+ int r, have_timers;
- /* Check for expired timers. Use a global variable to indicate that
- * watchdog functions are called, so that sys_setalarm() isn't called
- * more often than necessary when set_timer or cancel_timer are called
- * from these watchdog functions. */
- expiring = 1;
- tmrs_exptimers(&timers, now, &next_time);
- expiring = 0;
-
- /* Reschedule an alarm if necessary. */
- if (next_time > 0) {
- if (sys_setalarm(next_time, 1) != OK)
- panic("expire_timers: couldn't set alarm");
- }
+ /*
+ * Check for expired timers. Use a global variable to indicate that
+ * watchdog functions are called, so that sys_setalarm() isn't called
+ * more often than necessary when set_timer or cancel_timer are called
+ * from these watchdog functions.
+ */
+ expiring = TRUE;
+ have_timers = tmrs_exptimers(&timers, now, &next_time);
+ expiring = FALSE;
+
+ /* Reschedule an alarm if necessary. */
+ if (have_timers) {
+ if ((r = sys_setalarm(next_time, TRUE /*abs_time*/)) != OK)
+ panic("expire_timers: couldn't set alarm: %d", r);
+ }
}
+++ /dev/null
-/* This library provides generic watchdog timer management functionality.
- * See the comments in <minix/timers.h> for details.
- */
-
-#include <minix/timers.h> /* definitions and function prototypes */
-#include <sys/null.h>
-#include "timers.h"
+#include <minix/timers.h>
-/*===========================================================================*
- * tmrs_clrtimer *
- *===========================================================================*/
-clock_t tmrs_clrtimer(tmrs, tp, next_time)
-minix_timer_t **tmrs; /* pointer to timers queue */
-minix_timer_t *tp; /* timer to be removed */
-clock_t *next_time;
-{
-/* Deactivate a timer and remove it from the timers queue.
+/*
+ * Deactivate a timer and remove it from the timers queue. 'tmrs' is a pointer
+ * to the timers queue. 'tp' is a pointer to the timer to be removed, which
+ * generally should be on the queue (but this is not a requirement, and the
+ * kernel abuses this). If 'prev_time' is non-NULL, it is filled with the
+ * previous timer head time, which always exists since at least 'tp' is on it.
+ * The function returns TRUE if there is still at least one timer on the queue
+ * after this function is done, in which case 'next_time' (if non-NULL) is
+ * filled with the absolute expiry time of the new head timer.
*/
- minix_timer_t **atp;
- clock_t prev_time;
+int
+tmrs_clrtimer(minix_timer_t ** tmrs, minix_timer_t * tp, clock_t * prev_time,
+ clock_t * next_time)
+{
+ minix_timer_t **atp;
+ int r;
- if(*tmrs)
- prev_time = (*tmrs)->tmr_exp_time;
- else
- prev_time = 0;
+ if (*tmrs != NULL) {
+ if (prev_time != NULL)
+ *prev_time = (*tmrs)->tmr_exp_time;
+ r = TRUE;
+ } else
+ r = FALSE;
- tp->tmr_exp_time = TMR_NEVER;
+ tp->tmr_func = NULL; /* clear the timer object */
- for (atp = tmrs; *atp != NULL; atp = &(*atp)->tmr_next) {
- if (*atp == tp) {
- *atp = tp->tmr_next;
- break;
+ for (atp = tmrs; *atp != NULL; atp = &(*atp)->tmr_next) {
+ if (*atp == tp) {
+ *atp = tp->tmr_next;
+ break;
+ }
}
- }
- if(next_time) {
- if(*tmrs)
- *next_time = (*tmrs)->tmr_exp_time;
- else
- *next_time = 0;
- }
+ if (next_time != NULL) {
+ if (*tmrs != NULL)
+ *next_time = (*tmrs)->tmr_exp_time;
+ else
+ *next_time = 0;
+ }
- return prev_time;
+ return r;
}
-
-#include "timers.h"
+#include <minix/timers.h>
-/*===========================================================================*
- * tmrs_exptimers *
- *===========================================================================*/
-void tmrs_exptimers(tmrs, now, new_head)
-minix_timer_t **tmrs; /* pointer to timers queue */
-clock_t now; /* current time */
-clock_t *new_head;
-{
-/* Use the current time to check the timers queue list for expired timers.
+/*
+ * Use the current time to check the timers queue list for expired timers.
* Run the watchdog functions for all expired timers and deactivate them.
* The caller is responsible for scheduling a new alarm if needed.
*/
- minix_timer_t *tp;
+int
+tmrs_exptimers(minix_timer_t ** tmrs, clock_t now, clock_t * new_head)
+{
+ minix_timer_t *tp;
+ tmr_func_t func;
- while ((tp = *tmrs) != NULL && tp->tmr_exp_time <= now) {
- *tmrs = tp->tmr_next;
- tp->tmr_exp_time = TMR_NEVER;
- (*tp->tmr_func)(tp);
- }
+ while ((tp = *tmrs) != NULL && tmr_has_expired(tp, now)) {
+ *tmrs = tp->tmr_next;
- if(new_head) {
- if(*tmrs)
- *new_head = (*tmrs)->tmr_exp_time;
- else
- *new_head = 0;
- }
-}
+ func = tp->tmr_func;
+ tp->tmr_func = NULL;
+ (*func)(tp->tmr_arg);
+ }
+ if (*tmrs != NULL) {
+ if (new_head != NULL)
+ *new_head = (*tmrs)->tmr_exp_time;
+ return TRUE;
+ } else
+ return FALSE;
+}
-#include "timers.h"
+#include <minix/timers.h>
-/*===========================================================================*
- * tmrs_settimer *
- *===========================================================================*/
-clock_t tmrs_settimer(tmrs, tp, exp_time, watchdog, new_head)
-minix_timer_t **tmrs; /* pointer to timers queue */
-minix_timer_t *tp; /* the timer to be added */
-clock_t exp_time; /* its expiration time */
-tmr_func_t watchdog; /* watchdog function to be run */
-clock_t *new_head; /* new earliest timer, if non NULL */
-{
-/* Activate a timer to run function 'fp' at time 'exp_time'. If the timer is
- * already in use it is first removed from the timers queue. Then, it is put
- * in the list of active timers with the first to expire in front.
- * The caller responsible for scheduling a new alarm for the timer if needed.
+/*
+ * Activate a timer to run function 'watchdog' at absolute time 'exp_time', as
+ * part of timers queue 'tmrs'. If the timer is already in use, it is first
+ * removed from the timers queue. Then, it is put in the list of active timers
+ * with the first to expire in front. The caller responsible for scheduling a
+ * new alarm for the timer if needed. To that end, the function returns three
+ * values: its return value (TRUE or FALSE) indicates whether there was an old
+ * head timer; if TRUE, 'old_head' (if non-NULL) is filled with the absolute
+ * expiry time of the old head timer. If 'new_head' is non-NULL, it is filled
+ * with the absolute expiry time of the new head timer.
*/
- minix_timer_t **atp;
- clock_t old_head = 0;
+int
+tmrs_settimer(minix_timer_t ** tmrs, minix_timer_t * tp, clock_t exp_time,
+ tmr_func_t watchdog, int arg, clock_t * old_head, clock_t * new_head)
+{
+ minix_timer_t **atp;
+ int r;
- if(*tmrs)
- old_head = (*tmrs)->tmr_exp_time;
+ if (*tmrs != NULL) {
+ if (old_head != NULL)
+ *old_head = (*tmrs)->tmr_exp_time;
+ r = TRUE;
+ } else
+ r = FALSE;
- /* Set the timer's variables. */
- (void) tmrs_clrtimer(tmrs, tp, NULL);
- tp->tmr_exp_time = exp_time;
- tp->tmr_func = watchdog;
+ /* Set the timer's variables. */
+ if (tmr_is_set(tp))
+ (void)tmrs_clrtimer(tmrs, tp, NULL, NULL);
+ tp->tmr_exp_time = exp_time;
+ tp->tmr_func = watchdog; /* set the timer object */
+ tp->tmr_arg = arg;
- /* Add the timer to the active timers. The next timer due is in front. */
- for (atp = tmrs; *atp != NULL; atp = &(*atp)->tmr_next) {
- if (exp_time < (*atp)->tmr_exp_time) break;
- }
- tp->tmr_next = *atp;
- *atp = tp;
- if(new_head)
- (*new_head) = (*tmrs)->tmr_exp_time;
- return old_head;
-}
+ /*
+ * Add the timer to the active timers. The next timer due is in front.
+ */
+ for (atp = tmrs; *atp != NULL; atp = &(*atp)->tmr_next) {
+ if (tmr_is_first(exp_time, (*atp)->tmr_exp_time))
+ break;
+ }
+ tp->tmr_next = *atp;
+ *atp = tp;
+ if (new_head != NULL)
+ *new_head = (*tmrs)->tmr_exp_time;
+ return r;
+}
{
}
-static void arp_watchdog(__unused minix_timer_t *tp)
+static void arp_watchdog(int arg __unused)
{
etharp_tmr();
set_timer(&arp_tmr, arp_ticks, arp_watchdog, 0);
}
-static void tcp_fwatchdog(__unused minix_timer_t *tp)
+static void tcp_fwatchdog(int arg __unused)
{
tcp_fasttmr();
set_timer(&tcp_ftmr, tcp_fticks, tcp_fwatchdog, 0);
}
-static void tcp_swatchdog(__unused minix_timer_t *tp)
+static void tcp_swatchdog(int arg __unused)
{
tcp_slowtmr();
set_timer(&tcp_ftmr, tcp_sticks, tcp_swatchdog, 0);
#include <sys/time.h>
#include <minix/com.h>
#include <minix/callnr.h>
+#include <assert.h>
#include "mproc.h"
#define US 1000000UL /* shortcut for microseconds per second */
itimerval *value, struct itimerval *ovalue);
static void get_realtimer(struct mproc *mp, struct itimerval *value);
static void set_realtimer(struct mproc *mp, struct itimerval *value);
-static void cause_sigalrm(minix_timer_t *tp);
+static void cause_sigalrm(int arg);
/*===========================================================================*
* ticks_from_timeval *
/* First determine remaining time, in ticks, of previous alarm, if set. */
if (rmp->mp_flags & ALARM_ON) {
uptime = getticks();
- exptime = *tmr_exp_time(&rmp->mp_timer);
+ exptime = tmr_exp_time(&rmp->mp_timer);
remaining = exptime - uptime;
clock_t ticks; /* how many ticks delay before the signal */
{
if (ticks > 0) {
+ assert(ticks <= TMRDIFF_MAX);
set_timer(&rmp->mp_timer, ticks, cause_sigalrm, rmp->mp_endpoint);
rmp->mp_flags |= ALARM_ON;
} else if (rmp->mp_flags & ALARM_ON) {
/*===========================================================================*
* cause_sigalrm *
*===========================================================================*/
-static void cause_sigalrm(tp)
-minix_timer_t *tp;
+static void
+cause_sigalrm(int arg)
{
int proc_nr_n;
register struct mproc *rmp;
/* get process from timer */
- if(pm_isokendpt(tmr_arg(tp)->ta_int, &proc_nr_n) != OK) {
- printf("PM: ignoring timer for invalid endpoint %d\n",
- tmr_arg(tp)->ta_int);
+ if(pm_isokendpt(arg, &proc_nr_n) != OK) {
+ printf("PM: ignoring timer for invalid endpoint %d\n", arg);
return;
}
/* If an interval is set, set a new timer; otherwise clear the ALARM_ON flag.
* The set_alarm call will be calling set_timer from within this callback
- * from the expire_timers function. This is safe, but we must not use the
- * "tp" structure below this point anymore.
+ * from the expire_timers function. This is safe.
*/
if (rmp->mp_interval[ITIMER_REAL] > 0)
set_alarm(rmp, rmp->mp_interval[ITIMER_REAL]);
#define NO_EVENTSUB ((char)-1) /* no current process event subscriber */
-#define MAX_CLOCK_T ((unsigned long) 1 << ((sizeof(clock_t) * 8) - 1))
-#define MAX_SECS ( (clock_t) (MAX_CLOCK_T/system_hz) )
+#define MAX_SECS ( (clock_t) (TMRDIFF_MAX/system_hz) )
/* max.secs for setitimer() ((2^31-1)/HZ) */
#define NR_ITIMERS 3 /* number of supported interval timers */
void select_forget(void);
void select_reply1(endpoint_t driver_e, devminor_t minor, int status);
void select_reply2(endpoint_t driver_e, devminor_t minor, int status);
-void select_timeout_check(minix_timer_t *);
void select_unsuspend_by_endpt(endpoint_t proc);
/* worker.c */
#define FROM_PROC 0
#define TO_PROC 1
+#define USECPERSEC 1000000 /* number of microseconds in a second */
+
typedef fd_set *ixfer_fd_set_ptr;
static struct selectentry {
static void select_restart_filps(void);
static int tab2ops(int fd, struct selectentry *e);
static void wipe_select(struct selectentry *s);
+void select_timeout_check(int s);
static struct fdtype {
int (*select_request)(struct filp *, int *ops, int block,
* timeout and wait for either the file descriptors to become ready or the
* timer to go off. If no timeout value was provided, we wait indefinitely.
*/
- int r, nfds, do_timeout = 0, fd, s;
+ int r, nfds, do_timeout, fd, s;
struct filp *f;
unsigned int type, ops;
struct timeval timeout;
struct selectentry *se;
vir_bytes vtimeout;
+ clock_t ticks;
nfds = job_m_in.m_lc_vfs_select.nfds;
vtimeout = job_m_in.m_lc_vfs_select.timeout;
/* Did the process set a timeout value? If so, retrieve it. */
if (vtimeout != 0) {
- do_timeout = 1;
r = sys_datacopy_wrapper(who_e, vtimeout, SELF, (vir_bytes) &timeout,
sizeof(timeout));
+
+ /* No nonsense in the timeval */
+ if (r == OK && (timeout.tv_sec < 0 || timeout.tv_usec < 0 ||
+ timeout.tv_usec >= USECPERSEC))
+ r = EINVAL;
+
if (r != OK) {
se->requestor = NULL;
return(r);
}
- }
-
- /* No nonsense in the timeval */
- if (do_timeout && (timeout.tv_sec < 0 || timeout.tv_usec < 0)) {
- se->requestor = NULL;
- return(EINVAL);
- }
+ do_timeout = 1;
+ } else
+ do_timeout = 0;
/* If there is no timeout, we block forever. Otherwise, we block up to the
* specified time interval.
/* Convert timeval to ticks and set the timer. If it fails, undo
* all, return error.
*/
- if (do_timeout) {
- int ticks;
+ if (do_timeout && se->block) {
/* Open Group:
* "If the requested timeout interval requires a finer
* granularity than the implementation supports, the
* actual timeout interval shall be rounded up to the next
* supported value."
*/
-#define USECPERSEC 1000000
- while(timeout.tv_usec >= USECPERSEC) {
- /* this is to avoid overflow with *system_hz below */
- timeout.tv_usec -= USECPERSEC;
- timeout.tv_sec++;
+ if (timeout.tv_sec >= (TMRDIFF_MAX - 1) / system_hz) {
+ ticks = TMRDIFF_MAX; /* silently truncate */
+ } else {
+ ticks = timeout.tv_sec * system_hz +
+ (timeout.tv_usec * system_hz + USECPERSEC-1) / USECPERSEC;
}
- ticks = timeout.tv_sec * system_hz +
- (timeout.tv_usec * system_hz + USECPERSEC-1) / USECPERSEC;
+ assert(ticks != 0 && ticks <= TMRDIFF_MAX);
se->expiry = ticks;
set_timer(&se->timer, ticks, select_timeout_check, s);
}
/*===========================================================================*
* select_timeout_check *
*===========================================================================*/
-void select_timeout_check(minix_timer_t *timer)
+void select_timeout_check(int s)
{
/* An alarm has gone off for one of the select queries. This function MUST NOT
* block its calling thread.
*/
- int s;
struct selectentry *se;
- s = tmr_arg(timer)->ta_int;
if (s < 0 || s >= MAXSELECTS) return; /* Entry does not exist */
se = &selecttab[s];
if (se->requestor == NULL) return;
- if (se->expiry <= 0) return; /* Strange, did we even ask for a timeout? */
+ if (se->expiry == 0) return; /* Strange, did we even ask for a timeout? */
se->expiry = 0;
if (!is_deferred(se))
select_return(se);
struct timeval tv;
/* Let the parent do initial read and write tests from and to the pipe. */
- tv.tv_sec = DO_PAUSE + DO_PAUSE + DO_PAUSE + 1;
+ tv.tv_sec = DO_PAUSE + DO_PAUSE + 1;
tv.tv_usec = 0;
(void) select(0, NULL, NULL, NULL, &tv);
retval = select(fd_ap[0]+1, &fds_read, NULL, NULL, &tv);
(void) gettimeofday(&end_time, NULL); /* Record ending time */
- if(retval != 0) em(3, "Should have timed out");
- if(compute_diff(start_time, end_time, DO_PAUSE) > DO_DELTA)
- em(4, "Time difference too large");
-
+ if(retval != -1) em(3, "Should have failed");
+ if(errno != EINVAL) em(4, "Incorrect error thrown");
+
+ /* Do a few more tests for invalid timeout values. */
+ tv.tv_sec = 0;
+ tv.tv_usec = 1000000;
+ retval = select(fd_ap[0]+1, &fds_read, NULL, NULL, &tv);
+ if (retval != -1) em(0, "Should have failed");
+ if (errno != EINVAL) em(0, "Incorrect error thrown");
+
+ tv.tv_sec = 0;
+ tv.tv_usec = ~0;
+ retval = select(fd_ap[0]+1, &fds_read, NULL, NULL, &tv);
+ if (retval != -1) em(0, "Should have failed");
+ if (errno != EINVAL) em(0, "Incorrect error thrown");
+
/* Let's wait for another DO_PAUSE seconds, expressed in seconds and micro
seconds. */
FD_ZERO(&fds_read);
FD_SET(fd_ap[0], &fds_read);
tv.tv_sec = DO_PAUSE - 1;
- tv.tv_usec = (DO_PAUSE - tv.tv_sec) * 1000000L;
+ tv.tv_usec = 999999L; /* close enough */
(void) gettimeofday(&start_time, NULL); /* Record starting time */
retval = select(fd_ap[0]+1, &fds_read, NULL, NULL, &tv);