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

📄 clock.c

📁 一个简单的操作系统minix的核心代码
💻 C
📖 第 1 页 / 共 2 页
字号:
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 + -