📄 clock.c
字号:
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
src/kernel/clock.c
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
11000 /* This file contains the code and data for the clock task. The clock task
11001 * accepts six message types:
11002 *
11003 * HARD_INT: a clock interrupt has occurred
11004 * GET_UPTIME: get the time since boot in ticks
11005 * GET_TIME: a process wants the real time in seconds
11006 * SET_TIME: a process wants to set the real time in seconds
11007 * SET_ALARM: a process wants to be alerted after a specified interval
11008 * SET_SYN_AL: set the sync alarm
11009 *
11010 *
11011 * The input message is format m6. The parameters are as follows:
11012 *
11013 * m_type CLOCK_PROC FUNC NEW_TIME
11014 * ---------------------------------------------
11015 * | HARD_INT | | | |
11016 * |------------+----------+---------+---------|
11017 * | GET_UPTIME | | | |
11018 * |------------+----------+---------+---------|
11019 * | GET_TIME | | | |
11020 * |------------+----------+---------+---------|
11021 * | SET_TIME | | | newtime |
11022 * |------------+----------+---------+---------|
11023 * | SET_ALARM | proc_nr |f to call| delta |
11024 * |------------+----------+---------+---------|
11025 * | SET_SYN_AL | proc_nr | | delta |
11026 * ---------------------------------------------
11027 * NEW_TIME, DELTA_CLICKS, and SECONDS_LEFT all refer to the same field in
11028 * the message, depending upon the message type.
11029 *
11030 * Reply messages are of type OK, except in the case of a HARD_INT, to
11031 * which no reply is generated. For the GET_* messages the time is returned
11032 * in the NEW_TIME field, and for the SET_ALARM and SET_SYN_AL the time
11033 * in seconds remaining until the alarm is returned is returned in the same
11034 * field.
11035 *
11036 * When an alarm goes off, if the caller is a user process, a SIGALRM signal
11037 * is sent to it. If it is a task, a function specified by the caller will
11038 * be invoked. This function may, for example, send a message, but only if
11039 * it is certain that the task will be blocked when the timer goes off. A
11040 * synchronous alarm sends a message to the synchronous alarm task, which
11041 * in turn can dispatch a message to another server. This is the only way
11042 * to send an alarm to a server, since servers cannot use the function-call
11043 * mechanism available to tasks and servers cannot receive signals.
11044 */
11045
11046 #include "kernel.h"
11047 #include <signal.h>
11048 #include <minix/callnr.h>
11049 #include <minix/com.h>
11050 #include "proc.h"
11051
11052 /* Constant definitions. */
11053 #define MILLISEC 100 /* how often to call the scheduler (msec) */
11054 #define SCHED_RATE (MILLISEC*HZ/1000) /* number of ticks per schedule */
11055
11056 /* Clock parameters. */
11057 #define COUNTER_FREQ (2*TIMER_FREQ) /* counter frequency using sqare wave*/
11058 #define LATCH_COUNT 0x00 /* cc00xxxx, c = channel, x = any */
11059 #define SQUARE_WAVE 0x36 /* ccaammmb, a = access, m = mode, b = BCD */
11060 /* 11x11, 11 = LSB then MSB, x11 = sq wave */
11061 #define TIMER_COUNT ((unsigned) (TIMER_FREQ/HZ)) /* initial value for counter*/
11062 #define TIMER_FREQ 1193182L /* clock frequency for timer in PC and AT */
11063
11064 #define CLOCK_ACK_BIT 0x80 /* PS/2 clock interrupt acknowledge bit */
11065
11066 /* Clock task variables. */
11067 PRIVATE clock_t realtime; /* real time clock */
11068 PRIVATE time_t boot_time; /* time in seconds of system boot */
11069 PRIVATE clock_t next_alarm; /* probable time of next alarm */
11070 PRIVATE message mc; /* message buffer for both input and output */
11071 PRIVATE int watchdog_proc; /* contains proc_nr at call of *watch_dog[]*/
11072 PRIVATE watchdog_t watch_dog[NR_TASKS+NR_PROCS];
11073
11074 /* Variables used by both clock task and synchronous alarm task */
11075 PRIVATE int syn_al_alive= TRUE; /* don't wake syn_alrm_task before inited*/
11076 PRIVATE int syn_table[NR_TASKS+NR_PROCS]; /* which tasks get CLOCK_INT*/
11077
11078 /* Variables changed by interrupt handler */
11079 PRIVATE clock_t pending_ticks; /* ticks seen by low level only */
11080 PRIVATE int sched_ticks = SCHED_RATE; /* counter: when 0, call scheduler */
11081 PRIVATE struct proc *prev_ptr; /* last user process run by clock task */
11082
11083 FORWARD _PROTOTYPE( void common_setalarm, (int proc_nr,
11084 long delta_ticks, watchdog_t fuction) );
11085 FORWARD _PROTOTYPE( void do_clocktick, (void) );
11086 FORWARD _PROTOTYPE( void do_get_time, (void) );
11087 FORWARD _PROTOTYPE( void do_getuptime, (void) );
11088 FORWARD _PROTOTYPE( void do_set_time, (message *m_ptr) );
11089 FORWARD _PROTOTYPE( void do_setalarm, (message *m_ptr) );
11090 FORWARD _PROTOTYPE( void init_clock, (void) );
11091 FORWARD _PROTOTYPE( void cause_alarm, (void) );
11092 FORWARD _PROTOTYPE( void do_setsyn_alrm, (message *m_ptr) );
11093 FORWARD _PROTOTYPE( int clock_handler, (int irq) );
11094
11095 /*===========================================================================*
11096 * clock_task *
11097 *===========================================================================*/
11098 PUBLIC void clock_task()
11099 {
11100 /* Main program of clock task. It corrects realtime by adding pending
11101 * ticks seen only by the interrupt service, then it determines which
11102 * of the 6 possible calls this is by looking at 'mc.m_type'. Then
11103 * it dispatches.
11104 */
11105
11106 int opcode;
11107
11108 init_clock(); /* initialize clock task */
11109
11110 /* Main loop of the clock task. Get work, process it, sometimes reply. */
11111 while (TRUE) {
11112 receive(ANY, &mc); /* go get a message */
11113 opcode = mc.m_type; /* extract the function code */
11114
11115 lock();
11116 realtime += pending_ticks; /* transfer ticks from low level handler */
11117 pending_ticks = 0; /* so we don't have to worry about them */
11118 unlock();
11119
11120 switch (opcode) {
11121 case HARD_INT: do_clocktick(); break;
11122 case GET_UPTIME: do_getuptime(); break;
11123 case GET_TIME: do_get_time(); break;
11124 case SET_TIME: do_set_time(&mc); break;
11125 case SET_ALARM: do_setalarm(&mc); break;
11126 case SET_SYNC_AL:do_setsyn_alrm(&mc); break;
11127 default: panic("clock task got bad message", mc.m_type);
11128 }
11129
11130 /* Send reply, except for clock tick. */
11131 mc.m_type = OK;
11132 if (opcode != HARD_INT) send(mc.m_source, &mc);
11133 }
11134 }
11137 /*===========================================================================*
11138 * do_clocktick *
11139 *===========================================================================*/
11140 PRIVATE void do_clocktick()
11141 {
11142 /* Despite its name, this routine is not called on every clock tick. It
11143 * is called on those clock ticks when a lot of work needs to be done.
11144 */
11145
11146 register struct proc *rp;
11147 register int proc_nr;
11148
11149 if (next_alarm <= realtime) {
11150 /* An alarm may have gone off, but proc may have exited, so check. */
11151 next_alarm = LONG_MAX; /* start computing next alarm */
11152 for (rp = BEG_PROC_ADDR; rp < END_PROC_ADDR; rp++) {
11153 if (rp->p_alarm != 0) {
11154 /* See if this alarm time has been reached. */
11155 if (rp->p_alarm <= realtime) {
11156 /* A timer has gone off. If it is a user proc,
11157 * send it a signal. If it is a task, call the
11158 * function previously specified by the task.
11159 */
11160 proc_nr = proc_number(rp);
11161 if (watch_dog[proc_nr+NR_TASKS]) {
11162 watchdog_proc= proc_nr;
11163 (*watch_dog[proc_nr+NR_TASKS])();
11164 }
11165 else
11166 cause_sig(proc_nr, SIGALRM);
11167 rp->p_alarm = 0;
11168 }
11169
11170 /* Work on determining which alarm is next. */
11171 if (rp->p_alarm != 0 && rp->p_alarm < next_alarm)
11172 next_alarm = rp->p_alarm;
11173 }
11174 }
11175 }
11176
11177 /* If a user process has been running too long, pick another one. */
11178 if (--sched_ticks == 0) {
11179 if (bill_ptr == prev_ptr) lock_sched(); /* process has run too long */
11180 sched_ticks = SCHED_RATE; /* reset quantum */
11181 prev_ptr = bill_ptr; /* new previous process */
11182 }
11183 }
11186 /*===========================================================================*
11187 * do_getuptime *
11188 *===========================================================================*/
11189 PRIVATE void do_getuptime()
11190 {
11191 /* Get and return the current clock uptime in ticks. */
11192
11193 mc.NEW_TIME = realtime; /* current uptime */
11194 }
11197 /*===========================================================================*
11198 * get_uptime *
11199 *===========================================================================*/
11200 PUBLIC clock_t get_uptime()
11201 {
11202 /* Get and return the current clock uptime in ticks. This function is
11203 * designed to be called from other tasks, so they can get uptime without
11204 * the overhead of messages. It has to be careful about pending_ticks.
11205 */
11206
11207 clock_t uptime;
11208
11209 lock();
11210 uptime = realtime + pending_ticks;
11211 unlock();
11212 return(uptime);
11213 }
11216 /*===========================================================================*
11217 * do_get_time *
11218 *===========================================================================*/
11219 PRIVATE void do_get_time()
11220 {
11221 /* Get and return the current clock time in seconds. */
11222
11223 mc.NEW_TIME = boot_time + realtime/HZ; /* current real time */
11224 }
11227 /*===========================================================================*
11228 * do_set_time *
11229 *===========================================================================*/
11230 PRIVATE void do_set_time(m_ptr)
11231 message *m_ptr; /* pointer to request message */
11232 {
11233 /* Set the real time clock. Only the superuser can use this call. */
11234
11235 boot_time = m_ptr->NEW_TIME - realtime/HZ;
11236 }
11239 /*===========================================================================*
11240 * do_setalarm *
11241 *===========================================================================*/
11242 PRIVATE void do_setalarm(m_ptr)
11243 message *m_ptr; /* pointer to request message */
11244 {
11245 /* A process wants an alarm signal or a task wants a given watch_dog function
11246 * called after a specified interval.
11247 */
11248
11249 register struct proc *rp;
11250 int proc_nr; /* which process wants the alarm */
11251 long delta_ticks; /* in how many clock ticks does he want it? */
11252 watchdog_t function; /* function to call (tasks only) */
11253
11254 /* Extract the parameters from the message. */
11255 proc_nr = m_ptr->CLOCK_PROC_NR; /* process to interrupt later */
11256 delta_ticks = m_ptr->DELTA_TICKS; /* how many ticks to wait */
11257 function = (watchdog_t) m_ptr->FUNC_TO_CALL;
11258 /* function to call (tasks only) */
11259 rp = proc_addr(proc_nr);
11260 mc.SECONDS_LEFT = (rp->p_alarm == 0 ? 0 : (rp->p_alarm - realtime)/HZ );
11261 if (!istaskp(rp)) function= 0; /* user processes get signaled */
11262 common_setalarm(proc_nr, delta_ticks, function);
11263 }
11266 /*===========================================================================*
11267 * do_setsyn_alrm *
11268 *===========================================================================*/
11269 PRIVATE void do_setsyn_alrm(m_ptr)
11270 message *m_ptr; /* pointer to request message */
11271 {
11272 /* A process wants a synchronous alarm.
11273 */
11274
11275 register struct proc *rp;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -