Changeset View
Changeset View
Standalone View
Standalone View
sys/kern/kern_time.c
Show First 20 Lines • Show All 875 Lines • ▼ Show 20 Lines | #endif | ||||
} | } | ||||
#ifdef KTRACE | #ifdef KTRACE | ||||
if (KTRPOINT(td, KTR_STRUCT)) | if (KTRPOINT(td, KTR_STRUCT)) | ||||
ktritimerval(oitv); | ktritimerval(oitv); | ||||
#endif | #endif | ||||
return (0); | return (0); | ||||
} | } | ||||
static void | |||||
realitexpire_reset_callout(struct proc *p, sbintime_t *isbtp) | |||||
{ | |||||
sbintime_t prec; | |||||
prec = isbtp == NULL ? tvtosbt(p->p_realtimer.it_interval) : *isbtp; | |||||
callout_reset_sbt(&p->p_itcallout, tvtosbt(p->p_realtimer.it_value), | |||||
prec >> tc_precexp, realitexpire, p, C_ABSOLUTE); | |||||
} | |||||
void | |||||
itimer_proc_continued(struct proc *p) | |||||
{ | |||||
struct timeval ctv; | |||||
PROC_LOCK_ASSERT(p, MA_OWNED); | |||||
if ((p->p_flag2 & P2_ITSTOPPED) == 0) | |||||
return; | |||||
p->p_flag2 &= ~P2_ITSTOPPED; | |||||
microuptime(&ctv); | |||||
if (timevalcmp(&p->p_realtimer.it_value, &ctv, >=)) | |||||
realitexpire(p); | |||||
else | |||||
realitexpire_reset_callout(p, NULL); | |||||
markj: This will use `it_interval` to set the precision, but suppose it_interval is not set, and the… | |||||
kibAuthorUnsubmitted Done Inline ActionsIf it_interval is not set, then P2_ITSTOPPED is not set, and itimer_proc_continue() is not called. I only stop periodic (rescheduling) timers, one-shot timers are left alone for stopped process. And for periodic, I do not cancel scheduled callout, I let it execute and observe the process state, then decide if it needs to reschedule. Cancellation is simply not reliable, esp. while network people do not even consider other users and make incompatible KBI changes without handling all callers. kib: If it_interval is not set, then P2_ITSTOPPED is not set, and itimer_proc_continue() is not… | |||||
} | |||||
/* | /* | ||||
* Real interval timer expired: | * Real interval timer expired: | ||||
* send process whose timer expired an alarm signal. | * send process whose timer expired an alarm signal. | ||||
Done Inline ActionsI think we need to verify that p->p_itimers != NULL first. markj: I think we need to verify that `p->p_itimers != NULL` first. | |||||
* If time is not set up to reload, then just return. | * If time is not set up to reload, then just return. | ||||
* Else compute next time timer should go off which is > current time. | * Else compute next time timer should go off which is > current time. | ||||
* This is where delay in processing this timeout causes multiple | * This is where delay in processing this timeout causes multiple | ||||
* SIGALRM calls to be compressed into one. | * SIGALRM calls to be compressed into one. | ||||
* tvtohz() always adds 1 to allow for the time until the next clock | * tvtohz() always adds 1 to allow for the time until the next clock | ||||
* interrupt being strictly less than 1 clock tick, but we don't want | * interrupt being strictly less than 1 clock tick, but we don't want | ||||
* that here since we want to appear to be in sync with the clock | * that here since we want to appear to be in sync with the clock | ||||
* interrupt even when we're delayed. | * interrupt even when we're delayed. | ||||
*/ | */ | ||||
void | void | ||||
realitexpire(void *arg) | realitexpire(void *arg) | ||||
{ | { | ||||
struct proc *p; | struct proc *p; | ||||
struct timeval ctv; | struct timeval ctv; | ||||
sbintime_t isbt; | sbintime_t isbt; | ||||
p = (struct proc *)arg; | p = (struct proc *)arg; | ||||
kern_psignal(p, SIGALRM); | kern_psignal(p, SIGALRM); | ||||
if (!timevalisset(&p->p_realtimer.it_interval)) { | if (!timevalisset(&p->p_realtimer.it_interval)) { | ||||
timevalclear(&p->p_realtimer.it_value); | timevalclear(&p->p_realtimer.it_value); | ||||
if (p->p_flag & P_WEXIT) | if (p->p_flag & P_WEXIT) | ||||
wakeup(&p->p_itcallout); | wakeup(&p->p_itcallout); | ||||
return; | return; | ||||
} | } | ||||
isbt = tvtosbt(p->p_realtimer.it_interval); | isbt = tvtosbt(p->p_realtimer.it_interval); | ||||
if (isbt >= sbt_timethreshold) | if (isbt >= sbt_timethreshold) | ||||
getmicrouptime(&ctv); | getmicrouptime(&ctv); | ||||
else | else | ||||
microuptime(&ctv); | microuptime(&ctv); | ||||
do { | do { | ||||
timevaladd(&p->p_realtimer.it_value, | timevaladd(&p->p_realtimer.it_value, | ||||
&p->p_realtimer.it_interval); | &p->p_realtimer.it_interval); | ||||
} while (timevalcmp(&p->p_realtimer.it_value, &ctv, <=)); | } while (timevalcmp(&p->p_realtimer.it_value, &ctv, <=)); | ||||
callout_reset_sbt(&p->p_itcallout, tvtosbt(p->p_realtimer.it_value), | |||||
isbt >> tc_precexp, realitexpire, p, C_ABSOLUTE); | if (P_SHOULDSTOP(p) || P_KILLED(p)) { | ||||
p->p_flag2 |= P2_ITSTOPPED; | |||||
return; | |||||
} | |||||
p->p_flag2 &= ~P2_ITSTOPPED; | |||||
realitexpire_reset_callout(p, &isbt); | |||||
} | } | ||||
/* | /* | ||||
* Check that a proposed value to load into the .it_value or | * Check that a proposed value to load into the .it_value or | ||||
* .it_interval part of an interval timer is acceptable, and | * .it_interval part of an interval timer is acceptable, and | ||||
* fix it to have at least minimal value (i.e. if it is less | * fix it to have at least minimal value (i.e. if it is less | ||||
* than the resolution of the clock, round it up.) | * than the resolution of the clock, round it up.) | ||||
*/ | */ | ||||
▲ Show 20 Lines • Show All 817 Lines • Show Last 20 Lines |
This will use it_interval to set the precision, but suppose it_interval is not set, and the process was stopped and started again before the timeout expires. Then we will use a zero-valued it_interval to calculate the precision for the callout. Really I think we should not be scheduling a callout at all if one is still pending at this point.