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

📄 clock.c

📁 MINIX2.0操作系统源码 MINIX2.0操作系统源码
💻 C
📖 第 1 页 / 共 2 页
字号:
/* This file contains the code and data for the clock task.  The clock task
 * accepts six message types:
 *
 *   HARD_INT:    a clock interrupt has occurred
 *   GET_UPTIME:  get the time since boot in ticks
 *   GET_TIME:    a process wants the real time in seconds
 *   SET_TIME:    a process wants to set the real time in seconds
 *   SET_ALARM:   a process wants to be alerted after a specified interval
 *   SET_SYN_AL:  set the sync alarm
 *
 *
 * The input message is format m6.  The parameters are as follows:
 *
 *     m_type    CLOCK_PROC   FUNC    NEW_TIME
 * ---------------------------------------------
 * | HARD_INT   |          |         |         |
 * |------------+----------+---------+---------|
 * | GET_UPTIME |          |         |         |
 * |------------+----------+---------+---------|
 * | GET_TIME   |          |         |         |
 * |------------+----------+---------+---------|
 * | SET_TIME   |          |         | newtime |
 * |------------+----------+---------+---------|
 * | SET_ALARM  | proc_nr  |f to call|  delta  |
 * |------------+----------+---------+---------|
 * | SET_SYN_AL | proc_nr  |         |  delta  |
 * ---------------------------------------------
 * NEW_TIME, DELTA_CLICKS, and SECONDS_LEFT all refer to the same field in
 * the message, depending upon the message type.
 *
 * Reply messages are of type OK, except in the case of a HARD_INT, to
 * which no reply is generated. For the GET_* messages the time is returned
 * in the NEW_TIME field, and for the SET_ALARM and SET_SYN_AL the time
 * in seconds remaining until the alarm is returned is returned in the same
 * field.
 *
 * When an alarm goes off, if the caller is a user process, a SIGALRM signal
 * is sent to it.  If it is a task, a function specified by the caller will
 * be invoked.  This function may, for example, send a message, but only if
 * it is certain that the task will be blocked when the timer goes off. A
 * synchronous alarm sends a message to the synchronous alarm task, which
 * in turn can dispatch a message to another server. This is the only way
 * to send an alarm to a server, since servers cannot use the function-call
 * mechanism available to tasks and servers cannot receive signals.
 */

#include "kernel.h"
#include <signal.h>
#include <minix/callnr.h>
#include <minix/com.h>
#include "proc.h"

/* Constant definitions. */
#define MILLISEC         100	/* how often to call the scheduler (msec) */
#define SCHED_RATE (MILLISEC*HZ/1000)	/* number of ticks per schedule */

/* Clock parameters. */
#if (CHIP == INTEL)
#define COUNTER_FREQ (2*TIMER_FREQ)	/* counter frequency using sqare wave*/
#define LATCH_COUNT     0x00	/* cc00xxxx, c = channel, x = any */
#define SQUARE_WAVE     0x36	/* ccaammmb, a = access, m = mode, b = BCD */
				/*   11x11, 11 = LSB then MSB, x11 = sq wave */
#define TIMER_COUNT ((unsigned) (TIMER_FREQ/HZ)) /* initial value for counter*/
#define TIMER_FREQ  1193182L	/* clock frequency for timer in PC and AT */

#define CLOCK_ACK_BIT	0x80	/* PS/2 clock interrupt acknowledge bit */
#endif

#if (CHIP == M68000)
#define TIMER_FREQ  2457600L	/* timer 3 input clock frequency */
#endif

/* Clock task variables. */
PRIVATE clock_t realtime;	/* real time clock */
PRIVATE time_t boot_time;	/* time in seconds of system boot */
PRIVATE clock_t next_alarm;	/* probable time of next alarm */
PRIVATE message mc;		/* message buffer for both input and output */
PRIVATE int watchdog_proc;	/* contains proc_nr at call of *watch_dog[]*/
PRIVATE watchdog_t watch_dog[NR_TASKS+NR_PROCS];

/* Variables used by both clock task and synchronous alarm task */
PRIVATE int syn_al_alive= TRUE; /* don't wake syn_alrm_task before inited*/
PRIVATE int syn_table[NR_TASKS+NR_PROCS]; /* which tasks get CLOCK_INT*/

/* Variables changed by interrupt handler */
PRIVATE clock_t pending_ticks;	/* ticks seen by low level only */
PRIVATE int sched_ticks = SCHED_RATE;	/* counter: when 0, call scheduler */
PRIVATE struct proc *prev_ptr;	/* last user process run by clock task */

FORWARD _PROTOTYPE( void common_setalarm, (int proc_nr,
		long delta_ticks, watchdog_t fuction) );
FORWARD _PROTOTYPE( void do_clocktick, (void) );
FORWARD _PROTOTYPE( void do_get_time, (void) );
FORWARD _PROTOTYPE( void do_getuptime, (void) );
FORWARD _PROTOTYPE( void do_set_time, (message *m_ptr) );
FORWARD _PROTOTYPE( void do_setalarm, (message *m_ptr) );
FORWARD _PROTOTYPE( void init_clock, (void) );
FORWARD _PROTOTYPE( void cause_alarm, (void) );
FORWARD _PROTOTYPE( void do_setsyn_alrm, (message *m_ptr) );
FORWARD _PROTOTYPE( int clock_handler, (int irq) );

/*===========================================================================*
 *				clock_task				     *
 *===========================================================================*/
PUBLIC void clock_task()
{
/* Main program of clock task.  It corrects realtime by adding pending
 * ticks seen only by the interrupt service, then it determines which
 * of the 6 possible calls this is by looking at 'mc.m_type'.  Then
 * it dispatches.
 */

  int opcode;

  init_clock();			/* initialize clock task */

  /* Main loop of the clock task.  Get work, process it, sometimes reply. */
  while (TRUE) {
     receive(ANY, &mc);		/* go get a message */
     opcode = mc.m_type;	/* extract the function code */

     lock();
     realtime += pending_ticks;	/* transfer ticks from low level handler */
     pending_ticks = 0;		/* so we don't have to worry about them */
     unlock();

     switch (opcode) {
	case HARD_INT:   do_clocktick();	break;
	case GET_UPTIME: do_getuptime();	break;
	case GET_TIME:	 do_get_time();		break;
	case SET_TIME:	 do_set_time(&mc);	break;
	case SET_ALARM:	 do_setalarm(&mc);	break;
	case SET_SYNC_AL:do_setsyn_alrm(&mc);	break;
	default: panic("clock task got bad message", mc.m_type);
     }

    /* Send reply, except for clock tick. */
    mc.m_type = OK;
    if (opcode != HARD_INT) send(mc.m_source, &mc);
  }
}


/*===========================================================================*
 *				do_clocktick				     *
 *===========================================================================*/
PRIVATE void do_clocktick()
{
/* Despite its name, this routine is not called on every clock tick. It
 * is called on those clock ticks when a lot of work needs to be done.
 */

  register struct proc *rp;
  register int proc_nr;

  if (next_alarm <= realtime) {
	/* An alarm may have gone off, but proc may have exited, so check. */
	next_alarm = LONG_MAX;	/* start computing next alarm */
	for (rp = BEG_PROC_ADDR; rp < END_PROC_ADDR; rp++) {
		if (rp->p_alarm != 0) {
			/* See if this alarm time has been reached. */
			if (rp->p_alarm <= realtime) {
				/* A timer has gone off.  If it is a user proc,
				 * send it a signal.  If it is a task, call the
				 * function previously specified by the task.
				 */
				proc_nr = proc_number(rp);
				if (watch_dog[proc_nr+NR_TASKS]) {
					watchdog_proc= proc_nr;
					(*watch_dog[proc_nr+NR_TASKS])();
				}
				else
					cause_sig(proc_nr, SIGALRM);
				rp->p_alarm = 0;
			}

			/* Work on determining which alarm is next. */
			if (rp->p_alarm != 0 && rp->p_alarm < next_alarm)
				next_alarm = rp->p_alarm;
		}
	}
  }

  /* If a user process has been running too long, pick another one. */
  if (--sched_ticks == 0) {
	if (bill_ptr == prev_ptr) lock_sched();	/* process has run too long */
	sched_ticks = SCHED_RATE;		/* reset quantum */
	prev_ptr = bill_ptr;			/* new previous process */
  }
#if (SHADOWING == 1)
  if (rdy_head[SHADOW_Q]) unshadow(rdy_head[SHADOW_Q]);
#endif
}


/*===========================================================================*
 *				do_getuptime				     *
 *===========================================================================*/
PRIVATE void do_getuptime()
{
/* Get and return the current clock uptime in ticks. */

  mc.NEW_TIME = realtime;	/* current uptime */
}


/*===========================================================================*
 *				get_uptime				     *
 *===========================================================================*/
PUBLIC clock_t get_uptime()
{
/* Get and return the current clock uptime in ticks.  This function is
 * designed to be called from other tasks, so they can get uptime without
 * the overhead of messages. It has to be careful about pending_ticks.
 */

  clock_t uptime;

  lock();
  uptime = realtime + pending_ticks;
  unlock();
  return(uptime);
}


/*===========================================================================*
 *				do_get_time				     *
 *===========================================================================*/
PRIVATE void do_get_time()
{
/* Get and return the current clock time in seconds. */

  mc.NEW_TIME = boot_time + realtime/HZ;	/* current real time */
}


/*===========================================================================*
 *				do_set_time				     *
 *===========================================================================*/
PRIVATE void do_set_time(m_ptr)
message *m_ptr;			/* pointer to request message */
{
/* Set the real time clock.  Only the superuser can use this call. */

  boot_time = m_ptr->NEW_TIME - realtime/HZ;
}


/*===========================================================================*
 *				do_setalarm				     *
 *===========================================================================*/
PRIVATE void do_setalarm(m_ptr)
message *m_ptr;			/* pointer to request message */
{
/* A process wants an alarm signal or a task wants a given watch_dog function
 * called after a specified interval.
 */

  register struct proc *rp;
  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 (tasks only) */

  /* Extract the parameters from the message. */
  proc_nr = m_ptr->CLOCK_PROC_NR;	/* process to interrupt later */
  delta_ticks = m_ptr->DELTA_TICKS;	/* how many ticks to wait */
  function = (watchdog_t) m_ptr->FUNC_TO_CALL;
					/* function to call (tasks only) */
  rp = proc_addr(proc_nr);
  mc.SECONDS_LEFT = (rp->p_alarm == 0 ? 0 : (rp->p_alarm - realtime)/HZ );
  if (!istaskp(rp)) function= 0;	/* user processes get signaled */
  common_setalarm(proc_nr, delta_ticks, function);
}


/*===========================================================================*
 *				do_setsyn_alrm				     *
 *===========================================================================*/
PRIVATE void do_setsyn_alrm(m_ptr)
message *m_ptr;			/* pointer to request message */
{
/* A process wants a synchronous alarm.
 */

  register struct proc *rp;
  int proc_nr;			/* which process wants the alarm */
  long delta_ticks;		/* in how many clock ticks does he want it? */

  /* Extract the parameters from the message. */
  proc_nr = m_ptr->CLOCK_PROC_NR;	/* process to interrupt later */
  delta_ticks = m_ptr->DELTA_TICKS;	/* how many ticks to wait */
  rp = proc_addr(proc_nr);
  mc.SECONDS_LEFT = (rp->p_alarm == 0 ? 0 : (rp->p_alarm - realtime)/HZ );
  common_setalarm(proc_nr, delta_ticks, cause_alarm);
}


/*===========================================================================*
 *				common_setalarm				     *
 *===========================================================================*/
PRIVATE void common_setalarm(proc_nr, delta_ticks, function)

⌨️ 快捷键说明

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