1433d6423SLionel Sambuc /* The kernel call implemented in this file:
2433d6423SLionel Sambuc * m_type: SYS_SETALARM
3433d6423SLionel Sambuc *
4433d6423SLionel Sambuc * The parameters for this kernel call are:
5433d6423SLionel Sambuc * m_lsys_krn_sys_setalarm.exp_time (alarm's expiration time)
6433d6423SLionel Sambuc * m_lsys_krn_sys_setalarm.abs_time (expiration time is absolute?)
7433d6423SLionel Sambuc * m_lsys_krn_sys_setalarm.time_left (return seconds left of previous)
8433d6423SLionel Sambuc */
9433d6423SLionel Sambuc
10433d6423SLionel Sambuc #include "kernel/system.h"
11433d6423SLionel Sambuc
12433d6423SLionel Sambuc #include <minix/endpoint.h>
13433d6423SLionel Sambuc #include <assert.h>
14433d6423SLionel Sambuc
15433d6423SLionel Sambuc #if USE_SETALARM
16433d6423SLionel Sambuc
17*cfd712b4SDavid van Moolenbroek static void cause_alarm(int proc_nr_e);
18433d6423SLionel Sambuc
19433d6423SLionel Sambuc /*===========================================================================*
20433d6423SLionel Sambuc * do_setalarm *
21433d6423SLionel Sambuc *===========================================================================*/
do_setalarm(struct proc * caller,message * m_ptr)22433d6423SLionel Sambuc int do_setalarm(struct proc * caller, message * m_ptr)
23433d6423SLionel Sambuc {
24433d6423SLionel Sambuc /* A process requests a synchronous alarm, or wants to cancel its alarm. */
25433d6423SLionel Sambuc long exp_time; /* expiration time for this alarm */
26433d6423SLionel Sambuc int use_abs_time; /* use absolute or relative time */
27433d6423SLionel Sambuc minix_timer_t *tp; /* the process' timer structure */
28433d6423SLionel Sambuc clock_t uptime; /* placeholder for current uptime */
29433d6423SLionel Sambuc
30433d6423SLionel Sambuc /* Extract shared parameters from the request message. */
31*cfd712b4SDavid van Moolenbroek exp_time = m_ptr->m_lsys_krn_sys_setalarm.exp_time;
32*cfd712b4SDavid van Moolenbroek use_abs_time = m_ptr->m_lsys_krn_sys_setalarm.abs_time;
33433d6423SLionel Sambuc if (! (priv(caller)->s_flags & SYS_PROC)) return(EPERM);
34433d6423SLionel Sambuc
35433d6423SLionel Sambuc /* Get the timer structure and set the parameters for this alarm. */
36433d6423SLionel Sambuc tp = &(priv(caller)->s_alarm_timer);
37433d6423SLionel Sambuc
38433d6423SLionel Sambuc /* Return the ticks left on the previous alarm. */
39433d6423SLionel Sambuc uptime = get_monotonic();
40*cfd712b4SDavid van Moolenbroek if (!tmr_is_set(tp)) {
41e10ce184SDavid van Moolenbroek m_ptr->m_lsys_krn_sys_setalarm.time_left = TMR_NEVER;
42*cfd712b4SDavid van Moolenbroek } else if (tmr_is_first(uptime, tp->tmr_exp_time)) {
43*cfd712b4SDavid van Moolenbroek m_ptr->m_lsys_krn_sys_setalarm.time_left = tp->tmr_exp_time - uptime;
44433d6423SLionel Sambuc } else {
45433d6423SLionel Sambuc m_ptr->m_lsys_krn_sys_setalarm.time_left = 0;
46433d6423SLionel Sambuc }
47433d6423SLionel Sambuc
48e10ce184SDavid van Moolenbroek /* For the caller's convenience, also return the current time. */
49e10ce184SDavid van Moolenbroek m_ptr->m_lsys_krn_sys_setalarm.uptime = uptime;
50e10ce184SDavid van Moolenbroek
51*cfd712b4SDavid van Moolenbroek /*
52*cfd712b4SDavid van Moolenbroek * Finally, (re)set the timer depending on the expiration time. Note that
53*cfd712b4SDavid van Moolenbroek * an absolute time of zero is as valid as any other absolute value, so only
54*cfd712b4SDavid van Moolenbroek * a relative time value of zero resets the timer.
55*cfd712b4SDavid van Moolenbroek */
56*cfd712b4SDavid van Moolenbroek if (!use_abs_time && exp_time == 0) {
57433d6423SLionel Sambuc reset_kernel_timer(tp);
58433d6423SLionel Sambuc } else {
59*cfd712b4SDavid van Moolenbroek if (!use_abs_time)
60*cfd712b4SDavid van Moolenbroek exp_time += uptime;
61*cfd712b4SDavid van Moolenbroek set_kernel_timer(tp, exp_time, cause_alarm, caller->p_endpoint);
62433d6423SLionel Sambuc }
63433d6423SLionel Sambuc return(OK);
64433d6423SLionel Sambuc }
65433d6423SLionel Sambuc
66433d6423SLionel Sambuc /*===========================================================================*
67433d6423SLionel Sambuc * cause_alarm *
68433d6423SLionel Sambuc *===========================================================================*/
cause_alarm(int proc_nr_e)69*cfd712b4SDavid van Moolenbroek static void cause_alarm(int proc_nr_e)
70433d6423SLionel Sambuc {
71433d6423SLionel Sambuc /* Routine called if a timer goes off and the process requested a synchronous
72*cfd712b4SDavid van Moolenbroek * alarm. The process number is stored as the timer argument. Notify that
73433d6423SLionel Sambuc * process with a notification message from CLOCK.
74433d6423SLionel Sambuc */
75433d6423SLionel Sambuc mini_notify(proc_addr(CLOCK), proc_nr_e); /* notify process */
76433d6423SLionel Sambuc }
77433d6423SLionel Sambuc
78433d6423SLionel Sambuc #endif /* USE_SETALARM */
79