timers in unix/linux

29
Timers Time is kept relative to a particular point in time: Jan 1, 1970 GMT Two kernel counters: one for the seconds since Jan 1, 1970 and one for the microseconds since Jan 1, 1970

Upload: geeksrik

Post on 10-Jun-2015

12.565 views

Category:

Technology


0 download

TRANSCRIPT

Page 1: Timers in Unix/Linux

Timers

� Time is kept relative to a particular point in time:

Jan 1, 1970 GMT

� Two kernel counters: one for the seconds since

Jan 1, 1970 and one for the microseconds since

Jan 1, 1970

Page 2: Timers in Unix/Linux

Code

� #include <sys/time.h>

� structu timeval theTime;

� gettimeofday(&theTime, NULL);

� struct timeval { long tv_sec; long tv_usec;}

Page 3: Timers in Unix/Linux

System code

� You can read the system code in kernel/time.c

� (if you are looking at linux, you'll realy need to

look in the appropriate arch directory.)

� For tv_usec to correct, it needs to be

incremented once every microsecond. The

system can track the passage of time by

counting the number of interrupts that have

occurred since system boot.

Page 4: Timers in Unix/Linux

time of day clock

� i386 has a time of day clock (this may run

continuously or may be set at system boot

time). Although it may not have the accuracy

desired, it can be used as the base for

incrementing the 10-millisecond clock.

Page 5: Timers in Unix/Linux

10 millisecond clock

� The hardware has a programmable time that

can be set to issue an interrupt every k time

units: in Linux this is set to 10 milliseconds.

� So the gettimeofday function determines how

many microseconds and seconds have passed

since the time of day clock.

� when is the system clock updated?

Page 6: Timers in Unix/Linux

Updating the system clock

� the interrupt service routine for the clock

(timer_interrupt) calls the do_timer function in

kernel/sched.c (scheduler related functions).

� This increment the jiffies counter each time it

runs and marks a counter (TIMER_BH) for

execution in the ret_from_sys_call . For an

overview of the sequence of events in the case

of an interrupt see p 26 (Sec 4.1.1)

Page 7: Timers in Unix/Linux

Task Control

Page 8: Timers in Unix/Linux

ret_from_sys_call

� this is a standard set of tasks to complete

(dispatch) any accumulated system work:

− pending signals

− pending interrupt tasks

− schedule other tasks

� slow vs fast: fast interrupts don't do much work,

so interrupts are disabled. That means no

further work will need to be done.

Page 9: Timers in Unix/Linux

slow

� slow interrupts have more to do. So the ISR is

divided into two pieces: the “upper” half that is

“fast”, so interrupts can be disabled, and the

“lower” half, which is “slow”, but the tasks do not

require non-interruptable status.

� These defered tasks can be scheduled later.

Since the kernel is really “multi-threaded”, more

than one ISR may have run with postponed

bottom half events: these are all handled when

the bottom half is scheduled.

Page 10: Timers in Unix/Linux

timer bottom half

� time bottom half activities:

− system timer updates

− per process time updates

− stores the value in the struct timeval

Page 11: Timers in Unix/Linux

Per process timers

� kernel needs to maintain time spent by each

process

� timer info saved in the process's descriptor

� when a new task is created, the kernel create's

a new task_struct

� the task_struct contains all the process specific

info, some of which is time info:

Page 12: Timers in Unix/Linux

struct task_struct {

...

long counter;

...

unsigned long polkicy, rt_priority;

unsigned long it_real_value, it_prof_value, it_virt_value;

unsigned long it_real_incr, it_prof_incr, it_virt_incr;

struct time_list real_timer;

// contains tms_utime, tms_stime. tmx_cstime

struct tms;

unsigned long start_time;

long per_cpu_utime[NR_CPUS], per_cpu_stime[], cutime, cstime;

...

}

Page 13: Timers in Unix/Linux

// in timer.c (bottom half processing)

/*

* Called from the timer interrupt handler to charge one tick to the current

* process. user_tick is 1 if the tick is user time, 0 for system.

*/

void update_process_times(int user_tick)

{

struct task_struct *p = current;

int cpu = smp_processor_id(), system = user_tick ^ 1;

update_one_process(p, user_tick, system, cpu);

run_local_timers();

scheduler_tick(user_tick, system);

}

Page 14: Timers in Unix/Linux

static inline void do_it_prof(struct task_struct *p)

{

unsigned long it_prof = p->it_prof_value;

if (it_prof) {

if (--it_prof == 0) {

it_prof = p->it_prof_incr;

send_sig(SIGPROF, p, 1);

}

p->it_prof_value = it_prof;

}

}

Page 15: Timers in Unix/Linux

static inline void do_it_virt(struct task_struct * p, unsigned long ticks)

{

unsigned long it_virt = p->it_virt_value;

if (it_virt) {

it_virt -= ticks;

if (!it_virt) {

it_virt = p->it_virt_incr;

send_sig(SIGVTALRM, p, 1);

}

p->it_virt_value = it_virt;

}

}

Page 16: Timers in Unix/Linux

static inline void do_process_times(struct task_struct *p,

unsigned long user, unsigned long system)

{

unsigned long psecs;

psecs = (p->utime += user);

psecs += (p->stime += system);

if (psecs / HZ > p->rlim[RLIMIT_CPU].rlim_cur) {

/* Send SIGXCPU every second.. */

if (!(psecs % HZ))

send_sig(SIGXCPU, p, 1);

/* and SIGKILL when we go over max.. */

if (psecs / HZ > p->rlim[RLIMIT_CPU].rlim_max)

send_sig(SIGKILL, p, 1);

}

}

Page 17: Timers in Unix/Linux

void update_one_process(struct task_struct *p, unsigned long user,

unsigned long system, int cpu)

{

do_process_times(p, user, system);

do_it_virt(p, user);

do_it_prof(p);

}

Page 18: Timers in Unix/Linux

itimers

� the itimers use kernel time to keep track of

− itimer real: passage of real time

− itimer virtual: passage of virtual time (only when the

process is running)

− itimer prof: time the the process is actually running

and the time that the kernel is doing work on the

process's behalf

� (countdown timers)

Page 19: Timers in Unix/Linux

Initializing timers

� setitimer (do a man)

Page 20: Timers in Unix/Linux

int getitimer(int which, struct itimerval *value);

int setitimer(int which, const struct itimerval *value, struct itimer-

val *ovalue);

The system provides each process with three interval timers, each

decrementing in a distinct time domain. When any timer expires, a sig-

nal is sent to the process, and the timer (potentially) restarts.

ITIMER_REAL decrements in real time, and delivers SIGALRM upon expi-

ration.

ITIMER_VIRTUAL decrements only when the process is executing, and

delivers SIGVTALRM upon expiration.

ITIMER_PROF decrements both when the process executes and when the

system is executing on behalf of the process. Coupled

with ITIMER_VIRTUAL, this timer is usually used to pro-

file the time spent by the application in user and ker-

nel space. SIGPROF is delivered upon expiration.

Page 21: Timers in Unix/Linux

Timer values are defined by the following structures:

struct itimerval {

struct timeval it_interval; /* next value */

struct timeval it_value; /* current value */

};

struct timeval {

long tv_sec; /* seconds */

long tv_usec; /* microseconds */

};

Page 22: Timers in Unix/Linux

itimers

� two values:

− current value

− interval: value to initialize the counter: it's a

countdown)

Page 23: Timers in Unix/Linux

getitimer

� getitimer reads the value of a timer

Page 24: Timers in Unix/Linux

#include <sys/time.h>

struct itimerval v;

v.it_interval.tv_sec = 9;

v.it_interval.tv_usec = 999999;

v.it_value.tv_sec = 9

v.it_value.tv_usec = 999999;

setitimer(ITIMER_REAL, &v, NULL);

getitimer(ITIMER_REAL, &v);

printf("... %ld seconds, $ld microseconds ...",

..., v.it_value.tv_sec, v.it_value.tv_usec, ...);

...

Page 25: Timers in Unix/Linux

Signals

� A signal will be sent when a timer “runs out”. In

order to make use of this, you need to set your

own signal handler.

� this means that you define a function that will be

scheduled (invoked) when the signal is

received.

� It's the user version of an ISR.

Page 26: Timers in Unix/Linux

How to add a handler

signal(SIGALRM, p_realt_handler);

signal(SIGVTALRM, p_virtt_handler);

signal(SIGPROF, p_proft_handler);

Page 27: Timers in Unix/Linux

which signals?

� a signal can be sent from one process to

another

� do a man 7 signal to see all the signals

� You can use a signal for arbitrary events

(though there are better ways to indicate an

event and coordinate actions among processes)

� Specific SIGALRM: SIGPROF, SIGVTALRM,

SIGALRM

Page 28: Timers in Unix/Linux

my sigA

� check sigA.c for an example of setting a handler

(his version has a “race” condition.

Page 29: Timers in Unix/Linux

doing Part A

� Your part A should just set a real itimer to raise

a signal once every second.

� You should define a handler that increments a

counter each time it is interrupted.

� You can integrate this with your shell so that

you can do a variety of actions and then check

how much time you've used. (*You don't need

to convert to actual time of day.)