static void synch_wait(const struct timeval *tv, void *arg) { if (tv->tv_sec>=maxd.tv_sec || tv->tv_sec<0) tadd(tr->ndelay, maxd); else tadd(tr->ndelay, *tv); }
Timer* addclock0link(void (*f)(void), int ms) { Timer *nt; uvlong when; if(!timersinited) panic("addclock0link: timersinit not called yet"); /* Synchronize to hztimer if ms is 0 */ nt = malloc(sizeof(Timer)); if(nt == nil) error(Enomem); if(ms == 0) ms = 1000/HZ; nt->tns = (vlong)ms*1000000LL; nt->tmode = Tperiodic; nt->tt = nil; nt->tf = (void (*)(Ureg*, Timer*))f; ilock(&timers[0]); when = tadd(&timers[0], nt); if(when) timerset(when); iunlock(&timers[0]); return nt; }
static void synch_print(const char *buf, int len, void *arg) { struct ttyrec_frame *nf; if (!(nf=malloc(sizeof(struct ttyrec_frame)))) return; if (!(nf->data=malloc(len))) { free(nf); return; } nf->len=len; memcpy(nf->data, buf, len); nf->t=tr->tev_tail->t; tadd(nf->t, tr->ndelay); tr->ndelay.tv_sec=tr->ndelay.tv_usec=0; nf->snapshot=0; nf->next=0; tr->tev_tail->next=nf; tr->tev_tail=nf; tty_write(tr->tev_vt, buf, len); if ((tr->nchunk+=len)>=SNAPSHOT_CHUNK) // do a snapshot every 64KB of data { nf->snapshot=tty_copy(tr->tev_vt); tr->nchunk=0; } }
void timerkproc(void *v) { sigset_t sigs; Timers *tt; Timer *t; uvlong when, now; struct timespec ts; Ureg u; int signo; memset(&u, 0, sizeof u); timer_pid = pthread_self(); tt = &timers; ilock(&tt->lk); for(;;){ if((t = tt->head) == nil){ iunlock(&tt->lk); sigemptyset(&sigs); sigaddset(&sigs, SIGURG); sigwait(&sigs, &signo); ilock(&tt->lk); continue; } /* * No need to ilock t here: any manipulation of t * requires tdel(t) and this must be done with a * lock to tt held. We have tt, so the tdel will * wait until we're done */ now = fastticks(nil); when = t->twhen; if(when > now){ iunlock(&tt->lk); when -= now; ts.tv_sec = when/1000000000; ts.tv_nsec = when%1000000000; pthread_sigmask(SIG_SETMASK, nil, &sigs); sigdelset(&sigs, SIGURG); pselect(0, nil, nil, nil, &ts, &sigs); ilock(&tt->lk); continue; } tt->head = t->tnext; assert(t->tt == tt); t->tt = nil; iunlock(&tt->lk); (*t->tf)(&u, t); ilock(&tt->lk); if(t->tmode == Tperiodic) tadd(tt, t); } }
static void export_file(void) { char fn[MAXFILENAME],errmsg[MAXFILENAME+20+128]; OPENFILENAME dlg; int record_f; const char *format; struct timeval sel1, sel2; memset(&dlg, 0, sizeof(dlg)); dlg.lStructSize=sizeof(dlg); dlg.hwndOwner=wndMain; dlg.lpstrFilter= "ttyrec videos (*.ttyrec, *.ttyrec.[gz|bz2|xz])\000*.ttyrec;*.ttyrec.gz;*.ttyrec.bz2;*.ttyrec.xz\000" "nh-recorder videos (*.nh, *.nh.[gz|bz2|xz])\000*.nh;*.nh.gz;*.nh.bz2;*.nh.xz\000" "RealLogs videos (*.rl, *.rl.[gz|bz2|xz])\000*.rl;*.rl.gz;*.rl.bz2;*.rl.xz\000" "ANSI logs (*.txt, *.txt.[gz|bz2|xz])\000*.txt;*.txt.gz;*.txt.bz2;*.txt.xz\000" "all files\000*\000" "\000\000"; dlg.nFilterIndex=1; dlg.lpstrFile=fn; dlg.nMaxFile=MAXFILENAME; dlg.Flags=OFN_HIDEREADONLY|OFN_LONGNAMES; dlg.lpstrDefExt="ttyrec.bz2"; *fn=0; if (!GetSaveFileName(&dlg)) return; format=ttyrec_w_find_format(0, fn, "ansi"); if ((record_f=open(fn, O_WRONLY|O_CREAT|O_TRUNC, 0666))==-1) { sprintf(errmsg, "Can't write to %s: %s", fn, strerror(errno)); MessageBox(wndMain, errmsg, "Write error", MB_ICONERROR); return; } record_f=open_stream(record_f, fn, SM_WRITE, 0); sel1=selstart; tadd(sel1, tdate); sel2=selend; tadd(sel2, tdate); ttyrec_save(ttr, record_f, format, filename, &sel1, &sel2); }
void timerintr(Ureg *u, Tval) { Timer *t; Timers *tt; uvlong when, now; int count, callhzclock; intrcount[m->machno]++; callhzclock = 0; tt = &timers[m->machno]; now = fastticks(nil); if(now == 0) panic("timerintr: zero fastticks()"); ilock(tt); count = Maxtimerloops; while((t = tt->head) != nil){ /* * No need to ilock t here: any manipulation of t * requires tdel(t) and this must be done with a * lock to tt held. We have tt, so the tdel will * wait until we're done */ when = t->twhen; if(when > now){ timerset(when); iunlock(tt); if(callhzclock) hzclock(u); return; } tt->head = t->tnext; assert(t->tt == tt); t->tt = nil; fcallcount[m->machno]++; iunlock(tt); if(t->tf) (*t->tf)(u, t); else callhzclock++; ilock(tt); if(t->tmode == Tperiodic) tadd(tt, t); if (--count <= 0) { count = Maxtimerloops; iprint("timerintr: probably stuck in while loop; " "scrutinise clock.c or use faster cycle " "counter\n"); } } iunlock(tt); }
// find the frame containing time "tr", update "t0" static void replay_seek(void) { struct timeval t; t=tr; tadd(t, tdate); tev_cur=ttyrec_seek(ttr, &t, &vt); tev_curlp=0; gettimeofday(&t0, 0); tdiv1000(tr, speed); tsub(t0, tr); }
int __pmAFregister(const struct timeval *delta, void *data, void (*func)(int, void *)) { qelt *qp; struct timeval now; struct timeval interval; if (PM_MULTIPLE_THREADS(PM_SCOPE_AF)) return PM_ERR_THREAD; if (!block) AFhold(); if (afid == 0x8000 && !block) /* first time */ AFrearm(); if ((qp = (qelt *)malloc(sizeof(qelt))) == NULL) { return -oserror(); } qp->q_afid = ++afid; qp->q_data = data; qp->q_delta = *delta; qp->q_func = func; __pmtimevalNow(&qp->q_when); tadd(&qp->q_when, &qp->q_delta); enqueue(qp); if (root == qp) { /* we ended up at the head of the list, set itimer */ interval = qp->q_when; __pmtimevalNow(&now); tsub(&interval, &now); if (interval.tv_sec == 0 && interval.tv_usec < MIN_ITIMER_USEC) /* use minimal delay (platform dependent) */ interval.tv_usec = MIN_ITIMER_USEC; #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_AF) { __pmPrintStamp(stderr, &now); fprintf(stderr, " AFsetitimer for delta "); printdelta(stderr, &interval); fputc('\n', stderr); } #endif AFsetitimer(&interval); } if (!block) AFrelse(); return qp->q_afid; }
static void record_live(FILE *f, void* state, struct timeval *tm, char *buf, int len) { struct timeval tv, wall; gettimeofday(&wall, 0); tv=*tm; tadd(tv, *((struct timeval*)state)); tsub(tv, wall); if (tv.tv_sec>=0 && (tv.tv_sec || tv.tv_usec)) // can't go back in time select(0, 0, 0, 0, &tv); else tsub(*(struct timeval*)state, tv); // move the origin by the (negative) time skipped fwrite(buf, 1, len, f); fflush(f); }
void timerintr(Ureg *u, Tval) { Timer *t; Timers *tt; uvlong when, now; int callhzclock; static int sofar; intrcount[m->machno]++; callhzclock = 0; tt = &timers[m->machno]; now = fastticks(nil); ilock(tt); while(t = tt->head){ /* * No need to ilock t here: any manipulation of t * requires tdel(t) and this must be done with a * lock to tt held. We have tt, so the tdel will * wait until we're done */ when = t->twhen; if(when > now){ timerset(when); iunlock(tt); if(callhzclock) hzclock(u); return; } tt->head = t->tnext; assert(t->tt == tt); t->tt = nil; fcallcount[m->machno]++; iunlock(tt); if(t->tf) (*t->tf)(u, t); else callhzclock++; ilock(tt); if(t->tmode == Tperiodic) tadd(tt, t); } iunlock(tt); }
static int replay_play(struct timeval *delay) { // structures touched: tev, vt struct timeval tr1; ttyrec_frame fn; switch (play_state) { case 0: default: case 1: return 0; case 2: gettimeofday(&tr, 0); tsub(tr, t0); tmul1000(tr, speed); tr1=tr; tadd(tr1, tdate); if (tev_cur && tev_cur->len>tev_curlp) { tty_write(vt, tev_cur->data+tev_curlp, tev_cur->len-tev_curlp); tev_curlp=tev_cur->len; } while ((fn=ttyrec_next_frame(ttr, tev_cur)) && tcmp(fn->t, tr1)==-1) { tev_cur=fn; if (tev_cur->data) tty_write(vt, tev_cur->data, tev_cur->len); tev_curlp=tev_cur->len; } if ((fn=ttyrec_next_frame(ttr, tev_cur))) { *delay=fn->t; tsub(*delay, tdate); tsub(*delay, tr); tdiv1000(*delay, speed); return 1; } play_state=tev_done?0:3; case 3: return 0; } }
/* add or modify a timer */ void timeradd(Timer *nt) { Timers *tt; int64_t when; /* Must lock Timer struct before Timers struct */ ilock(&nt->l); if(tt = nt->tt){ ilock(&tt->l); tdel(nt); iunlock(&tt->l); } tt = &timers[machp()->machno]; ilock(&tt->l); when = tadd(tt, nt); if(when) timerset(when); iunlock(&tt->l); iunlock(&nt->l); }
/* add or modify a timer */ void timeradd(Timer *nt) { Timers *tt; vlong when; /* Must lock Timer struct before Timers struct */ ilock(nt); if(tt = nt->tt){ ilock(tt); tdel(nt); iunlock(tt); } tt = &timers[m->machno]; ilock(tt); when = tadd(tt, nt); if(when) timerset(when); iunlock(tt); iunlock(nt); }
/* add or modify a timer */ void timeradd(Timer *nt) { Timers *tt; vlong when; /* Must lock Timer struct before Timers struct */ ilock(&nt->lk); if((tt = nt->tt)){ ilock(&tt->lk); tdel(nt); iunlock(&tt->lk); } tt = &timers; ilock(&tt->lk); when = tadd(tt, nt); if(when) kicktimerproc(); iunlock(&tt->lk); iunlock(&nt->lk); }
Timer* addclock0link(void (*f)(void), int ms) { Timer *nt; int64_t when; /* Synchronize to hztimer if ms is 0 */ nt = malloc(sizeof(Timer)); if(ms == 0) ms = 1000/HZ; nt->tns = (int64_t)ms*1000000LL; nt->tmode = Tperiodic; nt->tt = nil; nt->tf = (void (*)(Ureg*, Timer*))f; ilock(&timers[0].l); when = tadd(&timers[0], nt); if(when) timerset(when); iunlock(&timers[0].l); return nt; }
static void onalarm(int dummy) { struct timeval now; struct timeval tmp; struct timeval interval; qelt *qp; if (!block) AFhold(); #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_AF) { __pmtimevalNow(&now); __pmPrintStamp(stderr, &now); fprintf(stderr, " AFonalarm(%d)\n", dummy); } #endif if (root != NULL) { /* something to do ... */ while (root != NULL) { /* compute difference between scheduled time and now */ __pmtimevalNow(&now); tmp = root->q_when; tsub(&tmp, &now); if (tmp.tv_sec == 0 && tmp.tv_usec <= 10000) { /* * within one 10msec tick, the time has passed for this one, * execute the callback and reschedule */ qp = root; root = root->q_next; #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_AF) { __pmPrintStamp(stderr, &now); fprintf(stderr, " AFcallback " PRINTF_P_PFX "%p(%d, " PRINTF_P_PFX "%p)\n", qp->q_func, qp->q_afid, qp->q_data); } #endif qp->q_func(qp->q_afid, qp->q_data); if (qp->q_delta.tv_sec == 0 && qp->q_delta.tv_usec == 0) { /* * if delta is zero, this is a single-shot event, * so do not reschedule it */ free(qp); } else { /* * avoid falling too far behind * if the scheduled time is more than q_delta in the * past we will never catch up ... better to skip some * events to catch up ... * * <------------ next q_when range -----------------> * * cannot catchup | may catchup | on schedule * | | * --------------------|---------------|------------> time * | | * | +-- now * +-- now - q_delta */ __pmtimevalNow(&now); for ( ; ; ) { tadd(&qp->q_when, &qp->q_delta); tmp = qp->q_when; tsub_real(&tmp, &now); tadd(&tmp, &qp->q_delta); if (tmp.tv_sec >= 0) break; #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_AF) { __pmPrintStamp(stderr, &now); fprintf(stderr, " AFcallback event %d too slow, skip callback for ", qp->q_afid); __pmPrintStamp(stderr, &qp->q_when); fputc('\n', stderr); } #endif } enqueue(qp); } } else /* * head of the queue (and hence all others) are too far in * the future ... done for this time */ break; } if (root == NULL) { pmprintf("Warning: AF event queue is empty, nothing more will be scheduled\n"); pmflush(); } else { /* set itimer for head of queue */ interval = root->q_when; __pmtimevalNow(&now); tsub(&interval, &now); if (interval.tv_sec == 0 && interval.tv_usec < MIN_ITIMER_USEC) /* use minimal delay (platform dependent) */ interval.tv_usec = MIN_ITIMER_USEC; #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_AF) { __pmPrintStamp(stderr, &now); fprintf(stderr, " AFsetitimer for delta "); printdelta(stderr, &interval); fputc('\n', stderr); } #endif AFsetitimer(&interval); } } if (!block) { AFrearm(); AFrelse(); } }