typedef struct {
clock_t exp_time;
clock_t time_left;
+ clock_t uptime;
int abs_time;
- uint8_t padding[44];
+ uint8_t padding[40];
} mess_lsys_krn_sys_setalarm;
_ASSERT_MSG_SIZE(mess_lsys_krn_sys_setalarm);
*/
int sys_times(endpoint_t proc_ep, clock_t *user_time, clock_t *sys_time,
clock_t *uptime, time_t *boottime);
-int sys_setalarm(clock_t exp_time, int abs_time);
+
+#define sys_setalarm(exp, abs) sys_setalarm2(exp, abs, NULL, NULL)
+int sys_setalarm2(clock_t exp_time, int abs_time, clock_t *time_left,
+ clock_t *uptime);
+
int sys_vtimer(endpoint_t proc_nr, int which, clock_t *newval, clock_t
*oldval);
/* Return the ticks left on the previous alarm. */
uptime = get_monotonic();
- if ((tp->tmr_exp_time != TMR_NEVER) && (uptime < tp->tmr_exp_time) ) {
+ 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);
} else {
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);
#include "syslib.h"
-/*===========================================================================*
- * sys_setalarm *
- *===========================================================================*/
-int sys_setalarm(exp_time, abs_time)
-clock_t exp_time; /* expiration time for the alarm */
-int abs_time; /* use absolute or relative expiration time */
-{
-/* Ask the SYSTEM schedule a synchronous alarm for the caller. The process
- * number can be SELF if the caller doesn't know its process number.
+/*
+ * 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.
*/
- message m;
- m.m_lsys_krn_sys_setalarm.exp_time = exp_time; /* the expiration time */
- m.m_lsys_krn_sys_setalarm.abs_time = abs_time; /* time is absolute? */
- return _kernel_call(SYS_SETALARM, &m);
+int
+sys_setalarm2(clock_t exp_time, int abs_time, clock_t * time_left,
+ clock_t * uptime)
+{
+ message m;
+ int r;
+
+ m.m_lsys_krn_sys_setalarm.exp_time = exp_time; /* expiration time */
+ m.m_lsys_krn_sys_setalarm.abs_time = abs_time; /* time is absolute? */
+
+ if ((r = _kernel_call(SYS_SETALARM, &m)) != OK)
+ return r;
+
+ if (time_left != NULL)
+ *time_left = m.m_lsys_krn_sys_setalarm.time_left;
+ if (uptime != NULL)
+ *uptime = m.m_lsys_krn_sys_setalarm.uptime;
+ return OK;
}
{
/* This function uses the synchronous alarm to delay for a while. This works
* even if a previous synchronous alarm was scheduled, because the remaining
- * tick of the previous alarm are returned so that it can be rescheduled.
- * Note however that a long tick_delay (longer than the remaining time of the
+ * ticks of the previous alarm are returned so that it can be rescheduled.
+ * Note however that a long tick delay (longer than the remaining time of the
* previous) alarm will also delay the previous alarm.
*/
- message m, m_alarm;
- int s;
+ clock_t time_left, uptime;
+ message m;
+ int r, status;
if (ticks <= 0) return OK; /* check for robustness */
- m.m_lsys_krn_sys_setalarm.exp_time = ticks; /* request message after ticks */
- m.m_lsys_krn_sys_setalarm.abs_time = 0; /* ticks are relative to now */
- s = _kernel_call(SYS_SETALARM, &m);
- if (s != OK) return(s);
-
- sef_receive(CLOCK,&m_alarm); /* await synchronous alarm */
-
- /* Check if we must reschedule the current alarm. */
- if (m.m_lsys_krn_sys_setalarm.time_left > 0 &&
- m.m_lsys_krn_sys_setalarm.time_left != TMR_NEVER) {
+ /* Set the new alarm while getting the time left on the previous alarm. */
+ if ((r = sys_setalarm2(ticks, FALSE, &time_left, &uptime)) != OK)
+ return r;
+
+ /* Await synchronous alarm. Since an alarm notification may already have
+ * been dispatched by the time that we set the new alarm, we keep going
+ * until we actually receive an alarm with a timestamp no earlier than the
+ * alarm time we expect.
+ */
+ while ((r = ipc_receive(CLOCK, &m, &status)) == OK) {
+ if (m.m_type == NOTIFY_MESSAGE &&
+ m.m_notify.timestamp >= uptime + ticks)
+ break;
+ }
- m.m_lsys_krn_sys_setalarm.exp_time =
- m.m_lsys_krn_sys_setalarm.time_left - ticks;
+ /* Check if we must reschedule the previous alarm. */
+ if (time_left != TMR_NEVER) {
+ if (time_left > ticks)
+ time_left -= ticks;
+ else
+ time_left = 1; /* force an alarm */
- if (m.m_lsys_krn_sys_setalarm.exp_time <= 0)
- m.m_lsys_krn_sys_setalarm.exp_time = 1;
- s = _kernel_call(SYS_SETALARM, &m);
+ /* There's no point in returning an error from here.. */
+ (void)sys_setalarm(time_left, FALSE);
}
- return(s);
+ return r;
}