1433d6423SLionel Sambuc /* The kernel call implemented in this file:
2433d6423SLionel Sambuc * m_type: SYS_VTIMER
3433d6423SLionel Sambuc *
4433d6423SLionel Sambuc * The parameters for this kernel call are:
5433d6423SLionel Sambuc * m2_i1: VT_WHICH (the timer: VT_VIRTUAL or VT_PROF)
6433d6423SLionel Sambuc * m2_i2: VT_SET (whether to set, or just retrieve)
7433d6423SLionel Sambuc * m2_l1: VT_VALUE (new/old expiration time, in ticks)
8433d6423SLionel Sambuc * m2_l2: VT_ENDPT (process to which the timer belongs)
9433d6423SLionel Sambuc */
10433d6423SLionel Sambuc
11433d6423SLionel Sambuc #include "kernel/system.h"
12433d6423SLionel Sambuc
13433d6423SLionel Sambuc #include <signal.h>
14433d6423SLionel Sambuc #include <minix/endpoint.h>
15433d6423SLionel Sambuc
16433d6423SLionel Sambuc #if USE_VTIMER
17433d6423SLionel Sambuc
18433d6423SLionel Sambuc /*===========================================================================*
19433d6423SLionel Sambuc * do_vtimer *
20433d6423SLionel Sambuc *===========================================================================*/
do_vtimer(struct proc * caller,message * m_ptr)21433d6423SLionel Sambuc int do_vtimer(struct proc * caller, message * m_ptr)
22433d6423SLionel Sambuc {
23433d6423SLionel Sambuc /* Set and/or retrieve the value of one of a process' virtual timers. */
24433d6423SLionel Sambuc struct proc *rp; /* pointer to process the timer belongs to */
25433d6423SLionel Sambuc register int pt_flag; /* the misc on/off flag for the req.d timer */
26433d6423SLionel Sambuc register clock_t *pt_left; /* pointer to the process' ticks-left field */
27433d6423SLionel Sambuc clock_t old_value; /* the previous number of ticks left */
28433d6423SLionel Sambuc int proc_nr, proc_nr_e;
29433d6423SLionel Sambuc
30433d6423SLionel Sambuc /* The requesting process must be privileged. */
31433d6423SLionel Sambuc if (! (priv(caller)->s_flags & SYS_PROC)) return(EPERM);
32433d6423SLionel Sambuc
33433d6423SLionel Sambuc if (m_ptr->VT_WHICH != VT_VIRTUAL && m_ptr->VT_WHICH != VT_PROF)
34433d6423SLionel Sambuc return(EINVAL);
35433d6423SLionel Sambuc
36433d6423SLionel Sambuc /* The target process must be valid. */
37433d6423SLionel Sambuc proc_nr_e = (m_ptr->VT_ENDPT == SELF) ? caller->p_endpoint : m_ptr->VT_ENDPT;
38433d6423SLionel Sambuc if (!isokendpt(proc_nr_e, &proc_nr)) return(EINVAL);
39433d6423SLionel Sambuc rp = proc_addr(proc_nr);
40433d6423SLionel Sambuc
41433d6423SLionel Sambuc /* Determine which flag and which field in the proc structure we want to
42433d6423SLionel Sambuc * retrieve and/or modify. This saves us having to differentiate between
43433d6423SLionel Sambuc * VT_VIRTUAL and VT_PROF multiple times below.
44433d6423SLionel Sambuc */
45433d6423SLionel Sambuc if (m_ptr->VT_WHICH == VT_VIRTUAL) {
46433d6423SLionel Sambuc pt_flag = MF_VIRT_TIMER;
47433d6423SLionel Sambuc pt_left = &rp->p_virt_left;
48433d6423SLionel Sambuc } else { /* VT_PROF */
49433d6423SLionel Sambuc pt_flag = MF_PROF_TIMER;
50433d6423SLionel Sambuc pt_left = &rp->p_prof_left;
51433d6423SLionel Sambuc }
52433d6423SLionel Sambuc
53433d6423SLionel Sambuc /* Retrieve the old value. */
54433d6423SLionel Sambuc if (rp->p_misc_flags & pt_flag) {
55433d6423SLionel Sambuc old_value = *pt_left;
56433d6423SLionel Sambuc } else {
57433d6423SLionel Sambuc old_value = 0;
58433d6423SLionel Sambuc }
59433d6423SLionel Sambuc
60433d6423SLionel Sambuc if (m_ptr->VT_SET) {
61433d6423SLionel Sambuc rp->p_misc_flags &= ~pt_flag; /* disable virtual timer */
62433d6423SLionel Sambuc
63433d6423SLionel Sambuc if (m_ptr->VT_VALUE > 0) {
64433d6423SLionel Sambuc *pt_left = m_ptr->VT_VALUE; /* set new timer value */
65433d6423SLionel Sambuc rp->p_misc_flags |= pt_flag; /* (re)enable virtual timer */
66433d6423SLionel Sambuc } else {
67433d6423SLionel Sambuc *pt_left = 0; /* clear timer value */
68433d6423SLionel Sambuc }
69433d6423SLionel Sambuc }
70433d6423SLionel Sambuc
71433d6423SLionel Sambuc m_ptr->VT_VALUE = old_value;
72433d6423SLionel Sambuc
73433d6423SLionel Sambuc return(OK);
74433d6423SLionel Sambuc }
75433d6423SLionel Sambuc
76433d6423SLionel Sambuc #endif /* USE_VTIMER */
77433d6423SLionel Sambuc
78433d6423SLionel Sambuc /*===========================================================================*
79433d6423SLionel Sambuc * vtimer_check *
80433d6423SLionel Sambuc *===========================================================================*/
vtimer_check(struct proc * rp)81*6077d1adSDr. Florian Grätz void vtimer_check(struct proc * rp)
82433d6423SLionel Sambuc {
83433d6423SLionel Sambuc /* This is called from the clock task, so we can be interrupted by the clock
84433d6423SLionel Sambuc * interrupt, but not by the system task. Therefore we only have to protect
85433d6423SLionel Sambuc * against interference from the clock handler. We can safely perform the
86433d6423SLionel Sambuc * following actions without locking as well though, as the clock handler
87433d6423SLionel Sambuc * never alters p_misc_flags, and only decreases p_virt_left/p_prof_left.
88433d6423SLionel Sambuc */
89433d6423SLionel Sambuc
90433d6423SLionel Sambuc /* Check if the virtual timer expired. If so, send a SIGVTALRM signal. */
91433d6423SLionel Sambuc if ((rp->p_misc_flags & MF_VIRT_TIMER) && rp->p_virt_left == 0) {
92433d6423SLionel Sambuc rp->p_misc_flags &= ~MF_VIRT_TIMER;
93433d6423SLionel Sambuc rp->p_virt_left = 0;
94433d6423SLionel Sambuc cause_sig(rp->p_nr, SIGVTALRM);
95433d6423SLionel Sambuc }
96433d6423SLionel Sambuc
97433d6423SLionel Sambuc /* Check if the profile timer expired. If so, send a SIGPROF signal. */
98433d6423SLionel Sambuc if ((rp->p_misc_flags & MF_PROF_TIMER) && rp->p_prof_left == 0) {
99433d6423SLionel Sambuc rp->p_misc_flags &= ~MF_PROF_TIMER;
100433d6423SLionel Sambuc rp->p_prof_left = 0;
101433d6423SLionel Sambuc cause_sig(rp->p_nr, SIGPROF);
102433d6423SLionel Sambuc }
103433d6423SLionel Sambuc }
104