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