📄 clock.c
字号:
11276 int proc_nr; /* which process wants the alarm */
11277 long delta_ticks; /* in how many clock ticks does he want it? */
11278
11279 /* Extract the parameters from the message. */
11280 proc_nr = m_ptr->CLOCK_PROC_NR; /* process to interrupt later */
11281 delta_ticks = m_ptr->DELTA_TICKS; /* how many ticks to wait */
11282 rp = proc_addr(proc_nr);
11283 mc.SECONDS_LEFT = (rp->p_alarm == 0 ? 0 : (rp->p_alarm - realtime)/HZ );
11284 common_setalarm(proc_nr, delta_ticks, cause_alarm);
11285 }
11288 /*===========================================================================*
11289 * common_setalarm *
11290 *===========================================================================*/
11291 PRIVATE void common_setalarm(proc_nr, delta_ticks, function)
11292 int proc_nr; /* which process wants the alarm */
11293 long delta_ticks; /* in how many clock ticks does he want it? */
11294 watchdog_t function; /* function to call (0 if cause_sig is
11295 * to be called */
11296 {
11297 /* Finish up work of do_set_alarm and do_setsyn_alrm. Record an alarm
11298 * request and check to see if it is the next alarm needed.
11299 */
11300
11301 register struct proc *rp;
11302
11303 rp = proc_addr(proc_nr);
11304 rp->p_alarm = (delta_ticks == 0 ? 0 : realtime + delta_ticks);
11305 watch_dog[proc_nr+NR_TASKS] = function;
11306
11307 /* Which alarm is next? */
11308 next_alarm = LONG_MAX;
11309 for (rp = BEG_PROC_ADDR; rp < END_PROC_ADDR; rp++)
11310 if(rp->p_alarm != 0 && rp->p_alarm < next_alarm)next_alarm=rp->p_alarm;
11311
11312 }
11315 /*===========================================================================*
11316 * cause_alarm *
11317 *===========================================================================*/
11318 PRIVATE void cause_alarm()
11319 {
11320 /* Routine called if a timer goes off and the process requested a synchronous
11321 * alarm. The process number is in the global variable watchdog_proc (HACK).
11322 */
11323 message mess;
11324
11325 syn_table[watchdog_proc + NR_TASKS]= TRUE;
11326 if (!syn_al_alive) send (SYN_ALRM_TASK, &mess);
11327 }
11330 /*===========================================================================*
11331 * syn_alrm_task *
11332 *===========================================================================*/
11333 PUBLIC void syn_alrm_task()
11334 {
11335 /* Main program of the synchronous alarm task.
11336 * This task receives messages only from cause_alarm in the clock task.
11337 * It sends a CLOCK_INT message to a process that requested a syn_alrm.
11338 * Synchronous alarms are so called because, unlike a signals or the
11339 * activation of a watchdog, a synchronous alarm is received by a process
11340 * when it is in a known part of its code, that is, when it has issued
11341 * a call to receive a message.
11342 */
11343
11344 message mess;
11345 int work_done; /* ready to sleep ? */
11346 int *al_ptr; /* pointer in syn_table */
11347 int i;
11348
11349 syn_al_alive= TRUE;
11350 for (i= 0, al_ptr= syn_table; i<NR_TASKS+NR_PROCS; i++, al_ptr++)
11351 *al_ptr= FALSE;
11352
11353 while (TRUE) {
11354 work_done= TRUE;
11355 for (i= 0, al_ptr= syn_table; i<NR_TASKS+NR_PROCS; i++, al_ptr++)
11356 if (*al_ptr) {
11357 *al_ptr= FALSE;
11358 mess.m_type= CLOCK_INT;
11359 send (i-NR_TASKS, &mess);
11360 work_done= FALSE;
11361 }
11362 if (work_done) {
11363 syn_al_alive= FALSE;
11364 receive (CLOCK, &mess);
11365 syn_al_alive= TRUE;
11366 }
11367 }
11368 }
11371 /*===========================================================================*
11372 * clock_handler *
11373 *===========================================================================*/
11374 PRIVATE int clock_handler(irq)
11375 int irq;
11376 {
11377 /* This executes on every clock tick (i.e., every time the timer chip
11378 * generates an interrupt). It does a little bit of work so the clock
11379 * task does not have to be called on every tick.
11380 *
11381 * Switch context to do_clocktick if an alarm has gone off.
11382 * Also switch there to reschedule if the reschedule will do something.
11383 * This happens when
11384 * (1) quantum has expired
11385 * (2) current process received full quantum (as clock sampled it!)
11386 * (3) something else is ready to run.
11387 * Also call TTY and PRINTER and let them do whatever is necessary.
11388 *
11389 * Many global global and static variables are accessed here. The safety
11390 * of this must be justified. Most of them are not changed here:
11391 * k_reenter:
11392 * This safely tells if the clock interrupt is nested.
11393 * proc_ptr, bill_ptr:
11394 * These are used for accounting. It does not matter if proc.c
11395 * is changing them, provided they are always valid pointers,
11396 * since at worst the previous process would be billed.
11397 * next_alarm, realtime, sched_ticks, bill_ptr, prev_ptr,
11398 * rdy_head[USER_Q]:
11399 * These are tested to decide whether to call interrupt(). It
11400 * does not matter if the test is sometimes (rarely) backwards
11401 * due to a race, since this will only delay the high-level
11402 * processing by one tick, or call the high level unnecessarily.
11403 * The variables which are changed require more care:
11404 * rp->user_time, rp->sys_time:
11405 * These are protected by explicit locks in system.c. They are
11406 * not properly protected in dmp.c (the increment here is not
11407 * atomic) but that hardly matters.
11408 * pending_ticks:
11409 * This is protected by explicit locks in clock.c. Don't
11410 * update realtime directly, since there are too many
11411 * references to it to guard conveniently.
11412 * lost_ticks:
11413 * Clock ticks counted outside the clock task.
11414 * sched_ticks, prev_ptr:
11415 * Updating these competes with similar code in do_clocktick().
11416 * No lock is necessary, because if bad things happen here
11417 * (like sched_ticks going negative), the code in do_clocktick()
11418 * will restore the variables to reasonable values, and an
11419 * occasional missed or extra sched() is harmless.
11420 *
11421 * Are these complications worth the trouble? Well, they make the system 15%
11422 * faster on a 5MHz 8088, and make task debugging much easier since there are
11423 * no task switches on an inactive system.
11424 */
11425
11426 register struct proc *rp;
11427 register unsigned ticks;
11428 clock_t now;
11429
11430 if (ps_mca) {
11431 /* Acknowledge the PS/2 clock interrupt. */
11432 out_byte(PORT_B, in_byte(PORT_B) | CLOCK_ACK_BIT);
11433 }
11434
11435 /* Update user and system accounting times.
11436 * First charge the current process for user time.
11437 * If the current process is not the billable process (usually because it
11438 * is a task), charge the billable process for system time as well.
11439 * Thus the unbillable tasks' user time is the billable users' system time.
11440 */
11441 if (k_reenter != 0)
11442 rp = proc_addr(HARDWARE);
11443 else
11444 rp = proc_ptr;
11445 ticks = lost_ticks + 1;
11446 lost_ticks = 0;
11447 rp->user_time += ticks;
11448 if (rp != bill_ptr && rp != proc_addr(IDLE)) bill_ptr->sys_time += ticks;
11449
11450 pending_ticks += ticks;
11451 now = realtime + pending_ticks;
11452 if (tty_timeout <= now) tty_wakeup(now); /* possibly wake up TTY */
11453 pr_restart(); /* possibly restart printer */
11454
11455 if (next_alarm <= now ||
11456 sched_ticks == 1 &&
11457 bill_ptr == prev_ptr &&
11458 rdy_head[USER_Q] != NIL_PROC) {
11459 interrupt(CLOCK);
11460 return 1; /* Reenable interrupts */
11461 }
11462
11463 if (--sched_ticks == 0) {
11464 /* If bill_ptr == prev_ptr, no ready users so don't need sched(). */
11465 sched_ticks = SCHED_RATE; /* reset quantum */
11466 prev_ptr = bill_ptr; /* new previous process */
11467 }
11468 return 1; /* Reenable clock interrupt */
11469 }
11471 /*===========================================================================*
11472 * init_clock *
11473 *===========================================================================*/
11474 PRIVATE void init_clock()
11475 {
11476 /* Initialize channel 0 of the 8253A timer to e.g. 60 Hz. */
11477
11478 out_byte(TIMER_MODE, SQUARE_WAVE); /* set timer to run continuously */
11479 out_byte(TIMER0, TIMER_COUNT); /* load timer low byte */
11480 out_byte(TIMER0, TIMER_COUNT >> 8); /* load timer high byte */
11481 put_irq_handler(CLOCK_IRQ, clock_handler); /* set the interrupt handler */
11482 enable_irq(CLOCK_IRQ); /* ready for clock interrupts */
11483 }
11486 /*===========================================================================*
11487 * clock_stop *
11488 *===========================================================================*/
11489 PUBLIC void clock_stop()
11490 {
11491 /* Reset the clock to the BIOS rate. (For rebooting) */
11492
11493 out_byte(TIMER_MODE, 0x36);
11494 out_byte(TIMER0, 0);
11495 out_byte(TIMER0, 0);
11496 }
11499 /*==========================================================================*
11500 * milli_delay *
11501 *==========================================================================*/
11502 PUBLIC void milli_delay(millisec)
11503 unsigned millisec;
11504 {
11505 /* Delay some milliseconds. */
11506
11507 struct milli_state ms;
11508
11509 milli_start(&ms);
11510 while (milli_elapsed(&ms) < millisec) {}
11511 }
11513 /*==========================================================================*
11514 * milli_start *
11515 *==========================================================================*/
11516 PUBLIC void milli_start(msp)
11517 struct milli_state *msp;
11518 {
11519 /* Prepare for calls to milli_elapsed(). */
11520
11521 msp->prev_count = 0;
11522 msp->accum_count = 0;
11523 }
11526 /*==========================================================================*
11527 * milli_elapsed *
11528 *==========================================================================*/
11529 PUBLIC unsigned milli_elapsed(msp)
11530 struct milli_state *msp;
11531 {
11532 /* Return the number of milliseconds since the call to milli_start(). Must be
11533 * polled rapidly.
11534 */
11535 unsigned count;
11536
11537 /* Read the counter for channel 0 of the 8253A timer. The counter
11538 * decrements at twice the timer frequency (one full cycle for each
11539 * half of square wave). The counter normally has a value between 0
11540 * and TIMER_COUNT, but before the clock task has been initialized,
11541 * its maximum value is 65535, as set by the BIOS.
11542 */
11543 out_byte(TIMER_MODE, LATCH_COUNT); /* make chip copy count to latch */
11544 count = in_byte(TIMER0); /* countdown continues during 2-step read */
11545 count |= in_byte(TIMER0) << 8;
11546
11547 /* Add difference between previous and new count unless the counter has
11548 * increased (restarted its cycle). We may lose a tick now and then, but
11549 * microsecond precision is not needed.
11550 */
11551 msp->accum_count += count <= msp->prev_count ? (msp->prev_count - count) : 1;
11552 msp->prev_count = count;
11553
11554 return msp->accum_count / (TIMER_FREQ / 1000);
11555 }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -