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