xref: /minix3/minix/kernel/system/do_vtimer.c (revision 433d6423c39e34ec4b79c950597bb2d236f886be)
1*433d6423SLionel Sambuc /* The kernel call implemented in this file:
2*433d6423SLionel Sambuc  *   m_type:	SYS_VTIMER
3*433d6423SLionel Sambuc  *
4*433d6423SLionel Sambuc  * The parameters for this kernel call are:
5*433d6423SLionel Sambuc  *    m2_i1:	VT_WHICH		(the timer: VT_VIRTUAL or VT_PROF)
6*433d6423SLionel Sambuc  *    m2_i2:	VT_SET			(whether to set, or just retrieve)
7*433d6423SLionel Sambuc  *    m2_l1:	VT_VALUE		(new/old expiration time, in ticks)
8*433d6423SLionel Sambuc  *    m2_l2:	VT_ENDPT		(process to which the timer belongs)
9*433d6423SLionel Sambuc  */
10*433d6423SLionel Sambuc 
11*433d6423SLionel Sambuc #include "kernel/system.h"
12*433d6423SLionel Sambuc 
13*433d6423SLionel Sambuc #include <signal.h>
14*433d6423SLionel Sambuc #include <minix/endpoint.h>
15*433d6423SLionel Sambuc 
16*433d6423SLionel Sambuc #if USE_VTIMER
17*433d6423SLionel Sambuc 
18*433d6423SLionel Sambuc /*===========================================================================*
19*433d6423SLionel Sambuc  *				do_vtimer				     *
20*433d6423SLionel Sambuc  *===========================================================================*/
21*433d6423SLionel Sambuc int do_vtimer(struct proc * caller, message * m_ptr)
22*433d6423SLionel Sambuc {
23*433d6423SLionel Sambuc /* Set and/or retrieve the value of one of a process' virtual timers. */
24*433d6423SLionel Sambuc   struct proc *rp;		/* pointer to process the timer belongs to */
25*433d6423SLionel Sambuc   register int pt_flag;		/* the misc on/off flag for the req.d timer */
26*433d6423SLionel Sambuc   register clock_t *pt_left;	/* pointer to the process' ticks-left field */
27*433d6423SLionel Sambuc   clock_t old_value;		/* the previous number of ticks left */
28*433d6423SLionel Sambuc   int proc_nr, proc_nr_e;
29*433d6423SLionel Sambuc 
30*433d6423SLionel Sambuc   /* The requesting process must be privileged. */
31*433d6423SLionel Sambuc   if (! (priv(caller)->s_flags & SYS_PROC)) return(EPERM);
32*433d6423SLionel Sambuc 
33*433d6423SLionel Sambuc   if (m_ptr->VT_WHICH != VT_VIRTUAL && m_ptr->VT_WHICH != VT_PROF)
34*433d6423SLionel Sambuc       return(EINVAL);
35*433d6423SLionel Sambuc 
36*433d6423SLionel Sambuc   /* The target process must be valid. */
37*433d6423SLionel Sambuc   proc_nr_e = (m_ptr->VT_ENDPT == SELF) ? caller->p_endpoint : m_ptr->VT_ENDPT;
38*433d6423SLionel Sambuc   if (!isokendpt(proc_nr_e, &proc_nr)) return(EINVAL);
39*433d6423SLionel Sambuc   rp = proc_addr(proc_nr);
40*433d6423SLionel Sambuc 
41*433d6423SLionel Sambuc   /* Determine which flag and which field in the proc structure we want to
42*433d6423SLionel Sambuc    * retrieve and/or modify. This saves us having to differentiate between
43*433d6423SLionel Sambuc    * VT_VIRTUAL and VT_PROF multiple times below.
44*433d6423SLionel Sambuc    */
45*433d6423SLionel Sambuc   if (m_ptr->VT_WHICH == VT_VIRTUAL) {
46*433d6423SLionel Sambuc       pt_flag = MF_VIRT_TIMER;
47*433d6423SLionel Sambuc       pt_left = &rp->p_virt_left;
48*433d6423SLionel Sambuc   } else { /* VT_PROF */
49*433d6423SLionel Sambuc       pt_flag = MF_PROF_TIMER;
50*433d6423SLionel Sambuc       pt_left = &rp->p_prof_left;
51*433d6423SLionel Sambuc   }
52*433d6423SLionel Sambuc 
53*433d6423SLionel Sambuc   /* Retrieve the old value. */
54*433d6423SLionel Sambuc   if (rp->p_misc_flags & pt_flag) {
55*433d6423SLionel Sambuc       old_value = *pt_left;
56*433d6423SLionel Sambuc   } else {
57*433d6423SLionel Sambuc       old_value = 0;
58*433d6423SLionel Sambuc   }
59*433d6423SLionel Sambuc 
60*433d6423SLionel Sambuc   if (m_ptr->VT_SET) {
61*433d6423SLionel Sambuc       rp->p_misc_flags &= ~pt_flag;	/* disable virtual timer */
62*433d6423SLionel Sambuc 
63*433d6423SLionel Sambuc       if (m_ptr->VT_VALUE > 0) {
64*433d6423SLionel Sambuc           *pt_left = m_ptr->VT_VALUE;	/* set new timer value */
65*433d6423SLionel Sambuc           rp->p_misc_flags |= pt_flag;	/* (re)enable virtual timer */
66*433d6423SLionel Sambuc       } else {
67*433d6423SLionel Sambuc           *pt_left = 0;			/* clear timer value */
68*433d6423SLionel Sambuc       }
69*433d6423SLionel Sambuc   }
70*433d6423SLionel Sambuc 
71*433d6423SLionel Sambuc   m_ptr->VT_VALUE = old_value;
72*433d6423SLionel Sambuc 
73*433d6423SLionel Sambuc   return(OK);
74*433d6423SLionel Sambuc }
75*433d6423SLionel Sambuc 
76*433d6423SLionel Sambuc #endif /* USE_VTIMER */
77*433d6423SLionel Sambuc 
78*433d6423SLionel Sambuc /*===========================================================================*
79*433d6423SLionel Sambuc  *				vtimer_check				     *
80*433d6423SLionel Sambuc  *===========================================================================*/
81*433d6423SLionel Sambuc void vtimer_check(rp)
82*433d6423SLionel Sambuc struct proc *rp;			/* pointer to the process */
83*433d6423SLionel Sambuc {
84*433d6423SLionel Sambuc   /* This is called from the clock task, so we can be interrupted by the clock
85*433d6423SLionel Sambuc    * interrupt, but not by the system task. Therefore we only have to protect
86*433d6423SLionel Sambuc    * against interference from the clock handler. We can safely perform the
87*433d6423SLionel Sambuc    * following actions without locking as well though, as the clock handler
88*433d6423SLionel Sambuc    * never alters p_misc_flags, and only decreases p_virt_left/p_prof_left.
89*433d6423SLionel Sambuc    */
90*433d6423SLionel Sambuc 
91*433d6423SLionel Sambuc   /* Check if the virtual timer expired. If so, send a SIGVTALRM signal. */
92*433d6423SLionel Sambuc   if ((rp->p_misc_flags & MF_VIRT_TIMER) && rp->p_virt_left == 0) {
93*433d6423SLionel Sambuc       rp->p_misc_flags &= ~MF_VIRT_TIMER;
94*433d6423SLionel Sambuc       rp->p_virt_left = 0;
95*433d6423SLionel Sambuc       cause_sig(rp->p_nr, SIGVTALRM);
96*433d6423SLionel Sambuc   }
97*433d6423SLionel Sambuc 
98*433d6423SLionel Sambuc   /* Check if the profile timer expired. If so, send a SIGPROF signal. */
99*433d6423SLionel Sambuc   if ((rp->p_misc_flags & MF_PROF_TIMER) && rp->p_prof_left == 0) {
100*433d6423SLionel Sambuc       rp->p_misc_flags &= ~MF_PROF_TIMER;
101*433d6423SLionel Sambuc       rp->p_prof_left = 0;
102*433d6423SLionel Sambuc       cause_sig(rp->p_nr, SIGPROF);
103*433d6423SLionel Sambuc   }
104*433d6423SLionel Sambuc }
105