⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 clock.c

📁 MINIX2.0操作系统源码 MINIX2.0操作系统源码
💻 C
📖 第 1 页 / 共 2 页
字号:
int proc_nr;			/* which process wants the alarm */
long delta_ticks;		/* in how many clock ticks does he want it? */
watchdog_t function;		/* function to call (0 if cause_sig is
				 * to be called */
{
/* Finish up work of do_set_alarm and do_setsyn_alrm.  Record an alarm
 * request and check to see if it is the next alarm needed.
 */

  register struct proc *rp;

  rp = proc_addr(proc_nr);
  rp->p_alarm = (delta_ticks == 0 ? 0 : realtime + delta_ticks);
  watch_dog[proc_nr+NR_TASKS] = function;

  /* Which alarm is next? */
  next_alarm = LONG_MAX;
  for (rp = BEG_PROC_ADDR; rp < END_PROC_ADDR; rp++)
	if(rp->p_alarm != 0 && rp->p_alarm < next_alarm)next_alarm=rp->p_alarm;

}


/*===========================================================================*
 *				cause_alarm				     *
 *===========================================================================*/
PRIVATE void cause_alarm()
{
/* Routine called if a timer goes off and the process requested a synchronous
 * alarm. The process number is in the global variable watchdog_proc (HACK).
 */
  message mess;

  syn_table[watchdog_proc + NR_TASKS]= TRUE;
  if (!syn_al_alive) send (SYN_ALRM_TASK, &mess);
}


/*===========================================================================*
 *				syn_alrm_task				     *
 *===========================================================================*/
PUBLIC void syn_alrm_task()
{
/* Main program of the synchronous alarm task.
 * This task receives messages only from cause_alarm in the clock task.
 * It sends a CLOCK_INT message to a process that requested a syn_alrm.
 * Synchronous alarms are so called because, unlike a signals or the
 * activation of a watchdog, a synchronous alarm is received by a process
 * when it is in a known part of its code, that is, when it has issued
 * a call to receive a message.
 */

  message mess;
  int work_done;	/* ready to sleep ? */
  int *al_ptr;		/* pointer in syn_table */
  int i;

  syn_al_alive= TRUE;
  for (i= 0, al_ptr= syn_table; i<NR_TASKS+NR_PROCS; i++, al_ptr++)
	*al_ptr= FALSE;

  while (TRUE) {
	work_done= TRUE;
	for (i= 0, al_ptr= syn_table; i<NR_TASKS+NR_PROCS; i++, al_ptr++)
		if (*al_ptr) {
			*al_ptr= FALSE;
			mess.m_type= CLOCK_INT;
			send (i-NR_TASKS, &mess);
			work_done= FALSE;
		}
	if (work_done) {
		syn_al_alive= FALSE;
		receive (CLOCK, &mess);
		syn_al_alive= TRUE;
	}
  }
}


/*===========================================================================*
 *				clock_handler				     *
 *===========================================================================*/
PRIVATE int clock_handler(irq)
int irq;
{
/* This executes on every clock tick (i.e., every time the timer chip
 * generates an interrupt). It does a little bit of work so the clock
 * task does not have to be called on every tick.
 *
 * Switch context to do_clocktick if an alarm has gone off.
 * Also switch there to reschedule if the reschedule will do something.
 * This happens when
 *	(1) quantum has expired
 *	(2) current process received full quantum (as clock sampled it!)
 *	(3) something else is ready to run.
 * Also call TTY and PRINTER and let them do whatever is necessary.
 *
 * Many global global and static variables are accessed here.  The safety
 * of this must be justified.  Most of them are not changed here:
 *	k_reenter:
 *		This safely tells if the clock interrupt is nested.
 *	proc_ptr, bill_ptr:
 *		These are used for accounting.  It does not matter if proc.c
 *		is changing them, provided they are always valid pointers,
 *		since at worst the previous process would be billed.
 *	next_alarm, realtime, sched_ticks, bill_ptr, prev_ptr,
 *	rdy_head[USER_Q]:
 *		These are tested to decide whether to call interrupt().  It
 *		does not matter if the test is sometimes (rarely) backwards
 *		due to a race, since this will only delay the high-level
 *		processing by one tick, or call the high level unnecessarily.
 * The variables which are changed require more care:
 *	rp->user_time, rp->sys_time:
 *		These are protected by explicit locks in system.c.  They are
 *		not properly protected in dmp.c (the increment here is not
 *		atomic) but that hardly matters.
 *	pending_ticks:
 *		This is protected by explicit locks in clock.c.  Don't
 *		update realtime directly, since there are too many
 *		references to it to guard conveniently.
 *	lost_ticks:
 *		Clock ticks counted outside the clock task.
 *	sched_ticks, prev_ptr:
 *		Updating these competes with similar code in do_clocktick().
 *		No lock is necessary, because if bad things happen here
 *		(like sched_ticks going negative), the code in do_clocktick()
 *		will restore the variables to reasonable values, and an
 *		occasional missed or extra sched() is harmless.
 *
 * Are these complications worth the trouble?  Well, they make the system 15%
 * faster on a 5MHz 8088, and make task debugging much easier since there are
 * no task switches on an inactive system.
 */

  register struct proc *rp;
  register unsigned ticks;
  clock_t now;

  if (ps_mca) {
	/* Acknowledge the PS/2 clock interrupt. */
	out_byte(PORT_B, in_byte(PORT_B) | CLOCK_ACK_BIT);
  }

  /* Update user and system accounting times.
   * First charge the current process for user time.
   * If the current process is not the billable process (usually because it
   * is a task), charge the billable process for system time as well.
   * Thus the unbillable tasks' user time is the billable users' system time.
   */
  if (k_reenter != 0)
	rp = proc_addr(HARDWARE);
  else
	rp = proc_ptr;
  ticks = lost_ticks + 1;
  lost_ticks = 0;
  rp->user_time += ticks;
  if (rp != bill_ptr && rp != proc_addr(IDLE)) bill_ptr->sys_time += ticks;

  pending_ticks += ticks;
  now = realtime + pending_ticks;
  if (tty_timeout <= now) tty_wakeup(now);	/* possibly wake up TTY */
#if (CHIP != M68000)
  pr_restart();					/* possibly restart printer */
#endif
#if (CHIP == M68000)
  kb_timer();					/* keyboard repeat */
  if (sched_ticks == 1) fd_timer();		/* floppy deselect */
#endif

  if (next_alarm <= now ||
      sched_ticks == 1 &&
      bill_ptr == prev_ptr &&
#if (SHADOWING == 0)
      rdy_head[USER_Q] != NIL_PROC) {
#else
      (rdy_head[USER_Q] != NIL_PROC || rdy_head[SHADOW_Q] != NIL_PROC)) {
#endif
	interrupt(CLOCK);
	return 1;	/* Reenable interrupts */
  }

  if (--sched_ticks == 0) {
	/* If bill_ptr == prev_ptr, no ready users so don't need sched(). */
	sched_ticks = SCHED_RATE;	/* reset quantum */
	prev_ptr = bill_ptr;		/* new previous process */
  }
  return 1;	/* Reenable clock interrupt */
}

#if (CHIP == INTEL)

/*===========================================================================*
 *				init_clock				     *
 *===========================================================================*/
PRIVATE void init_clock()
{
/* Initialize channel 0 of the 8253A timer to e.g. 60 Hz. */

  out_byte(TIMER_MODE, SQUARE_WAVE);	/* set timer to run continuously */
  out_byte(TIMER0, TIMER_COUNT);	/* load timer low byte */
  out_byte(TIMER0, TIMER_COUNT >> 8);	/* load timer high byte */
  put_irq_handler(CLOCK_IRQ, clock_handler);	/* set the interrupt handler */
  enable_irq(CLOCK_IRQ);		/* ready for clock interrupts */
}


/*===========================================================================*
 *				clock_stop				     *
 *===========================================================================*/
PUBLIC void clock_stop()
{
/* Reset the clock to the BIOS rate. (For rebooting) */

  out_byte(TIMER_MODE, 0x36);
  out_byte(TIMER0, 0);
  out_byte(TIMER0, 0);
}


/*==========================================================================*
 *				milli_delay				    *
 *==========================================================================*/
PUBLIC void milli_delay(millisec)
unsigned millisec;
{
/* Delay some milliseconds. */

  struct milli_state ms;

  milli_start(&ms);
  while (milli_elapsed(&ms) < millisec) {}
}

/*==========================================================================*
 *				milli_start				    *
 *==========================================================================*/
PUBLIC void milli_start(msp)
struct milli_state *msp;
{
/* Prepare for calls to milli_elapsed(). */

  msp->prev_count = 0;
  msp->accum_count = 0;
}


/*==========================================================================*
 *				milli_elapsed				    *
 *==========================================================================*/
PUBLIC unsigned milli_elapsed(msp)
struct milli_state *msp;
{
/* Return the number of milliseconds since the call to milli_start().  Must be
 * polled rapidly.
 */
  unsigned count;

  /* Read the counter for channel 0 of the 8253A timer.  The counter
   * decrements at twice the timer frequency (one full cycle for each
   * half of square wave).  The counter normally has a value between 0
   * and TIMER_COUNT, but before the clock task has been initialized,
   * its maximum value is 65535, as set by the BIOS.
   */
  out_byte(TIMER_MODE, LATCH_COUNT);	/* make chip copy count to latch */
  count = in_byte(TIMER0);	/* countdown continues during 2-step read */
  count |= in_byte(TIMER0) << 8;

  /* Add difference between previous and new count unless the counter has
   * increased (restarted its cycle).  We may lose a tick now and then, but
   * microsecond precision is not needed.
   */
  msp->accum_count += count <= msp->prev_count ? (msp->prev_count - count) : 1;
  msp->prev_count = count;

  return msp->accum_count / (TIMER_FREQ / 1000);
}
#endif /* (CHIP == INTEL) */


#if (CHIP == M68000)
#include "staddr.h"
#include "stmfp.h"

/*===========================================================================*
 *				init_clock				     *
 *===========================================================================*/
PRIVATE void init_clock()
{
/* Initialize the timer C in the MFP 68901.
 * Reducing to HZ is not possible by hardware.  The resulting interrupt
 * rate is further reduced by software with a factor of 4.
 * Note that the expression below works for both HZ=50 and HZ=60.
 */
  do {
	MFP->mf_tcdr = TIMER_FREQ/(64*4*HZ);
  } while ((MFP->mf_tcdr & 0xFF) != TIMER_FREQ/(64*4*HZ));
  MFP->mf_tcdcr |= (T_Q064<<4);
}
#endif /* (CHIP == M68000) */

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -