1 / 17

Generalidades

MINIX3 CLOCK TASK Cátedra: Diseño e Implementación de Sistemas Operativos UTN-FRSF Tomado de: Operating Systems Design and Implementation, Third Edition. Generalidades. Los temporizadores son esenciales en los Sistemas Operativos Mantener Fecha y Hora Time slice Timeouts Alarmas

beck-patel
Télécharger la présentation

Generalidades

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. MINIX3CLOCK TASKCátedra: Diseño e Implementación de Sistemas Operativos UTN-FRSFTomado de: Operating Systems Design and Implementation, Third Edition

  2. Generalidades • Los temporizadores son esenciales en los Sistemas Operativos • Mantener Fecha y Hora • Time slice • Timeouts • Alarmas • Tareas periódicas • Accounting • Estadísticas • La CLOCK Task se compila en el mismo binario que el kernel y accede a todas sus variables y funciones. • El término correcto es TIMER • Se dispone de un único temporizador en Hardware por lo que hay que virtualizar en varios temporizadores por Software.

  3. Programmable Interrupt Timer • Dispositivo que permite generar Interrupciones en un plazo especificado. • Puede programarse en modo: • ONE SHOT: Se generará una única interrupción en un momento dado. • SQUARE WAVE: Se generarán interrupciones periódicas. TIMER_FREQ 1193182 Hz

  4. Mantener la Fecha/Hora • Contador de 64 bits => Realizar una suma de 64 bits en cada Tick del Timer • Segundos y Ticks separados => Realiza una suma de 16 bits cada Tick del Timer y una de 32 bits cada segundo • Relativo al tiempo de booteo: Se cuentan solo los ticks desde que el sistema booteo en un contador de 32 bits. (MINIX3)

  5. Temporizadores Software • Tabla de Vencimientos => Realizar un rastreo de toda la tabla en cada Tick del Timer O(n). Rápida inserción/remoción O(1). • Lista Ordenada por Vencimiento => Solo se decrementa el tiempo al vencimiento del primer temporizador O(1). Compleja inserción/remoción O(n).

  6. Timeslice/Watchdogs • Cuando se inicia un proceso, se inicializa un contador con el timeslice en Tics para ese proceso. • Para cada interrupción del reloj (Tick), la TIMER ISR decrementará en 1 el valor del contador. • Cuando este contador llegue a tener valor 0, envía un notify() a CLOCK TASK para quitar al proceso de la cabeza de la Cola de READY e insertarlo al final de ella. • El planificador que se encargará de poner en marcha otro proceso

  7. Accounting • Cada vez que se inicia un proceso de USUARIO se mantienen dos contadores (p_user_time, p_sys_time) para contabilizar el uso de CPU. • Por cada Tick se actualizan los contadores según si se ha producido una interrupción de Reloj en modo usuario o en modo kernel • Modo Usuario: Se incrementa p_user_time del proceso de Usuario • Modo Kernel: Se incrementa p_sys_time del proceso de Usuario y el p_user_time del proceso de Sistema interrumpido

  8. Tarea de Reloj lost_ticks: Lleva la cuenta de ticks que pudiesen haberse perdido a causa de desactivar las interrupciones usando el MONITOR y la BIOS (no es útil). realtime: Permite calcular la hora del día actual. proc_ptr->p_ticks_left: Se decrementa en cada tick para controlar el cuanto de ejecución de un proceso en la CPU. next_timeout: Esta variable registra cuando podrá ocurrir la próxima alarma.

  9. Clock Task 10465 /*===========================================================================* 10466 * clock_task * 10467 *===========================================================================*/ 10468 PUBLIC void clock_task() 10469 { 10470 /* Main program of clock task. If the call is not HARD_INT it is an error. 10471 */ 10472 message m; /* message buffer for both input and output */ 10473 int result; /* result returned by the handler */ 10474 10475 init_clock(); /* initialize clock task */ 10476 10477 /* Main loop of the clock task. Get work, process it. Never reply. */ 10478 while (TRUE) { 10479 10480 /* Go get a message. */ 10481 receive(ANY, &m); 10482 10483 /* Handle the request. Only clock ticks are expected. */ 10484 switch (m.m_type) { 10485 case HARD_INT: 10486 result = do_clocktick(&m); /* handle clock tick */ 10487 break; 10488 default: /* illegal request type */ 10489 kprintf("CLOCK: illegal request %d from %d.\n", m.m_type,m.m_source); 10490 } 10491 }

  10. Clock Task 10494 /*===========================================================================* 10495 * do_clocktick * 10496 *===========================================================================*/ 10497 PRIVATE int do_clocktick(m_ptr) 10498 message *m_ptr; /* pointer to request message */ 10499 { 10500 /* Despite its name, this routine is not called on every clock tick. It 10501 * is called on those clock ticks when a lot of work needs to be done. 10502 */ 10503 10504 /* A process used up a full quantum. The interrupt handler stored this 10505 * process in 'prev_ptr'. First make sure that the process is not on the 10506 * scheduling queues. Then announce the process ready again. Since it has 10507 * no more time left, it gets a new quantum and is inserted at the right 10508 * place in the queues. As a side-effect a new process will be scheduled. 10509 */ 10510 if (prev_ptr->p_ticks_left <= 0 && priv(prev_ptr)->s_flags & PREEMPTIBLE) { 10511 lock_dequeue(prev_ptr); /* take it off the queues */ 10512 lock_enqueue(prev_ptr); /* and reinsert it again */ 10513 } 10514 10515 /* Check if a clock timer expired and run its watchdog function. */ 10516 if (next_timeout <= realtime) { 10517 tmrs_exptimers(&clock_timers, realtime, NULL); 10518 next_timeout = clock_timers == NULL ? 10519 TMR_NEVER : clock_timers->tmr_exp_time; 10520 } 10521 10522 /* Inhibit sending a reply. */ 10523 return(EDONTREPLY); 10524 }

  11. Clock Task 10526 /*===========================================================================* 10527 * init_clock * 10528 *===========================================================================*/ 10529 PRIVATE void init_clock() 10530 { 10531 /* Initialize the CLOCK's interrupt hook. */ 10532 clock_hook.proc_nr = CLOCK; 10533 10534 /* Initialize channel 0 of the 8253A timer to, e.g., 60 Hz. */ 10535 outb(TIMER_MODE, SQUARE_WAVE); /* set timer to run continuously */ 10536 outb(TIMER0, TIMER_COUNT); /* load timer low byte */ 10537 outb(TIMER0, TIMER_COUNT >> 8); /* load timer high byte */ 10538 put_irq_handler(&clock_hook, CLOCK_IRQ, clock_handler);/* register handler */ 10539 enable_irq(&clock_hook); /* ready for clock interrupts */ 10540 } 10542 /*===========================================================================* 10543 * clock_stop * 10544 *===========================================================================*/ 10545 PUBLIC void clock_stop() 10546 { 10547 /* Reset the clock to the BIOS rate. (For rebooting) */ 10548 outb(TIMER_MODE, 0x36); 10549 outb(TIMER0, 0); 10550 outb(TIMER0, 0); 10551 }

  12. Clock Task 10553 /*===========================================================================* 10554 * clock_handler * 10555 *===========================================================================*/ 10556 PRIVATE int clock_handler(hook) 10557 irq_hook_t *hook; 10558 { 10559 /* This executes on each clock tick (i.e., every time the timer chip generates 10560 * an interrupt). It does a little bit of work so the clock task does not have 10561 * to be called on every tick. The clock task is called when: 10562 * 10563 * (1) the scheduling quantum of the running process has expired, or 10564 * (2) a timer has expired and the watchdog function should be run. 10565 * 10566 * Many global global and static variables are accessed here. The safety of 10567 * this must be justified. All scheduling and message passing code acquires a 10568 * lock by temporarily disabling interrupts, so no conflicts with calls from 10569 * the task level can occur. Furthermore, interrupts are not reentrant, the 10570 * interrupt handler cannot be bothered by other interrupts. 10571 * 10572 * Variables that are updated in the clock's interrupt handler: 10573 * lost_ticks: 10574 * Clock ticks counted outside the clock task. This for example 10575 * is used when the boot monitor processes a real mode interrupt. 10576 * realtime: 10577 * The current uptime is incremented with all outstanding ticks. 10578 * proc_ptr, bill_ptr: 10579 * These are used for accounting. It does not matter if proc.c 10580 * is changing them, provided they are always valid pointers, 10581 * since at worst the previous process would be billed. 10582 */

  13. Clock Task 10583 register unsigned ticks; 10585 /* Acknowledge the PS/2 clock interrupt. */ 10586 if (machine.ps_mca) outb(PORT_B, inb(PORT_B) | CLOCK_ACK_BIT); 10588 /* Get number of ticks and update realtime. */ 10589 ticks = lost_ticks + 1; 10590 lost_ticks = 0; 10591 realtime += ticks; 10592 10593 /* Update user and system accounting times. Charge the current process for 10594 * user time. If the current process is not billable, that is, if a non-user 10595 * process is running, charge the billable process for system time as well. 10596 * Thus the unbillable process' user time is the billable user's system time. 10597 */ 10598 proc_ptr->p_user_time += ticks; 10599 if (priv(proc_ptr)->s_flags & PREEMPTIBLE) { 10600 proc_ptr->p_ticks_left -= ticks; 10601 } 10602 if (! (priv(proc_ptr)->s_flags & BILLABLE)) { 10603 bill_ptr->p_sys_time += ticks; 10604 bill_ptr->p_ticks_left -= ticks; 10605 } 10606 10607 /* Check if do_clocktick() must be called. Done for alarms and scheduling. 10608 * Some processes, such as the kernel tasks, cannot be preempted. 10609 */ 10610 if ((next_timeout <= realtime) || (proc_ptr->p_ticks_left <= 0)) { 10611 prev_ptr = proc_ptr; /* store running process */ 10612 lock_notify(HARDWARE, CLOCK); /* send notification */ 10613 } 10614 return(1); /* reenable interrupts */ 10615 }

  14. Clock Task 10617 /*===========================================================================* 10618 * get_uptime * 10619 *===========================================================================*/ 10620 PUBLIC clock_t get_uptime() 10621 { 10622 /* Get and return the current clock uptime in ticks. */ 10623 return(realtime); 10624 } 10626 /*===========================================================================* 10627 * set_timer * 10628 *===========================================================================*/ 10629 PUBLIC void set_timer(tp, exp_time, watchdog) 10630 struct timer *tp; /* pointer to timer structure */ 10631 clock_t exp_time; /* expiration realtime */ 10632 tmr_func_t watchdog; /* watchdog to be called */ 10633 { 10634 /* Insert the new timer in the active timers list. Always update the 10635 * next timeout time by setting it to the front of the active list. 10636 */ 10637 tmrs_settimer(&clock_timers, tp, exp_time, watchdog, NULL); 10638 next_timeout = clock_timers->tmr_exp_time; 10639 }

  15. Clock Task 10641 /*===========================================================================* 10642 * reset_timer * 10643 *===========================================================================*/ 10644 PUBLIC void reset_timer(tp) 10645 struct timer *tp; /* pointer to timer structure */ 10646 { 10647 /* The timer pointed to by 'tp' is no longer needed. Remove it from both the 10648 * active and expired lists. Always update the next timeout time by setting 10649 * it to the front of the active list. 10650 */ 10651 tmrs_clrtimer(&clock_timers, tp, NULL); 10652 next_timeout = (clock_timers == NULL) ? 10653 TMR_NEVER : clock_timers->tmr_exp_time; 10654 } 10656 /*===========================================================================* 10657 * read_clock * 10658 *===========================================================================*/ 10659 PUBLIC unsigned long read_clock() 10660 { 10661 /* Read the counter of channel 0 of the 8253A timer. This counter counts 10662 * down at a rate of TIMER_FREQ and restarts at TIMER_COUNT-1 when it 10663 * reaches zero. A hardware interrupt (clock tick) occurs when the counter 10664 * gets to zero and restarts its cycle. 10665 */ 10666 unsigned count; 10667 10668 outb(TIMER_MODE, LATCH_COUNT); 10669 count = inb(TIMER0); 10670 count |= (inb(TIMER0) << 8); 10672 return count; 10673 }

  16. Synchronous Alarms User Process alarm PM sys_setalarm signal SYSTASK set_timer notify CLOCK cause_alarm HARD_INT CLOCK ISR

  17. Servicios Relacionados

More Related