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

📄 time.c

📁 Simple Operating Systems (简称SOS)是一个可以运行在X86平台上(包括QEMU
💻 C
字号:
/* Copyright (C) 2004 David Decotigny   This program is free software; you can redistribute it and/or   modify it under the terms of the GNU General Public License   as published by the Free Software Foundation; either version 2   of the License, or (at your option) any later version.      This program is distributed in the hope that it will be useful,   but WITHOUT ANY WARRANTY; without even the implied warranty of   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the   GNU General Public License for more details.      You should have received a copy of the GNU General Public License   along with this program; if not, write to the Free Software   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,   USA. */#include <sos/assert.h>#include <sos/klibc.h>#include <hwcore/irq.h>#include <sos/list.h>#include "time.h"/** * Number of nanoseconds in 1 second */#define NS_IN_SEC 1000000000UL/** * The list of timeout actions waiting for a timeout. The timeout * actions are stored in the list in increasing initial timeout * order. Actually, the "timeout" field won't reflect this initial * timeout: for each element in the list, it stores the timeout * _difference_ between the timeout action and the previous in the * list. */static struct sos_timeout_action *timeout_action_list;/** * Current resolution of a time tick */static struct sos_time tick_resolution;/** * Time elapsed between boot and last timer tick * * @note No 'volatile' here because the tick value is NEVER modified * while in any of the functions below: it is modified only out of * these functions by the IRQ timer handler because these functions * are protected against timer IRQ and are "one shot" (no busy waiting * for a change in the tick's value). */static struct sos_time last_tick_time;sos_ret_t sos_time_inc(struct sos_time *dest,		       const struct sos_time *to_add){  /* nanosec is always < 1e9 so that their sum is always < 2e9, which     is smaller than 2^32-1 */  sos_ui32_t sigma_ns = dest->nanosec + to_add->nanosec;    dest->sec     += to_add->sec;  dest->sec     += sigma_ns / NS_IN_SEC;  dest->nanosec  = sigma_ns % NS_IN_SEC;  return SOS_OK;}sos_ret_t sos_time_dec(struct sos_time *dest,		       const struct sos_time *to_dec){  /* nanosec is always < 1e9 so that their difference is always in     (-1e9, 1e9), which is compatible with the (-2^31, 2^31 - 1)     cpacity of a signed dword */  sos_si32_t diff_ns = ((sos_si32_t)dest->nanosec)			- ((sos_si32_t)to_dec->nanosec);  /* Make sure substraction is possible */  SOS_ASSERT_FATAL(dest->sec >= to_dec->sec);  if (dest->sec == to_dec->sec)    SOS_ASSERT_FATAL(dest->nanosec >= to_dec->nanosec);  dest->sec     -= to_dec->sec;  if (diff_ns > 0)    dest->sec     += diff_ns / NS_IN_SEC;  else    dest->sec     -= ((-diff_ns) / NS_IN_SEC);  dest->nanosec  = (NS_IN_SEC + diff_ns) % NS_IN_SEC;  if (diff_ns < 0)    dest->sec --;  return SOS_OK;}int sos_time_cmp(const struct sos_time *t1,		 const struct sos_time *t2){  /* Compare seconds */  if (t1->sec < t2->sec)    return -1;  else if (t1->sec > t2->sec)    return 1;  /* seconds are equal => compare nanoseconds */  else if (t1->nanosec < t2->nanosec)    return -1;  else if (t1->nanosec > t2->nanosec)    return 1;  /* else: sec and nanosecs are equal */  return 0;}sos_bool_t sos_time_is_zero(const struct sos_time *tm){  return ( (0 == tm->sec) && (0 == tm->nanosec) );}sos_ret_t sos_time_subsysem_setup(const struct sos_time *initial_resolution){  timeout_action_list = NULL;  last_tick_time = (struct sos_time) { .sec = 0, .nanosec = 0 };  memcpy(& tick_resolution, initial_resolution, sizeof(struct sos_time));  return SOS_OK;}sos_ret_t sos_time_get_tick_resolution(struct sos_time *resolution){  sos_ui32_t flags;  sos_disable_IRQs(flags);  memcpy(resolution, & tick_resolution, sizeof(struct sos_time));  sos_restore_IRQs(flags);  return SOS_OK; }sos_ret_t sos_time_set_tick_resolution(const struct sos_time *resolution){  sos_ui32_t flags;  sos_disable_IRQs(flags);  memcpy(& tick_resolution, resolution, sizeof(struct sos_time));  sos_restore_IRQs(flags);  return SOS_OK;}sos_ret_t sos_time_get_now(struct sos_time *now){  sos_ui32_t flags;  sos_disable_IRQs(flags);  memcpy(now, & last_tick_time, sizeof(struct sos_time));  sos_restore_IRQs(flags);  return SOS_OK;  }/** * Helper routine to add the action in the list. MUST be called with * interrupts disabled ! */static sos_ret_t _add_action(struct sos_timeout_action *act,			     const struct sos_time *due_date,			     sos_bool_t is_relative_due_date,			     sos_timeout_routine_t *routine,			     void *routine_data){  struct sos_timeout_action *other, *insert_before;  int nb_act;  /* Delay must be specified */  if (due_date == NULL)    return -SOS_EINVAL;  /* Action container MUST be specified */  if (act == NULL)    return -SOS_EINVAL;  /* Refuse to add an empty action */  if (NULL == routine)    return -SOS_EINVAL;  /* Refuse to add the action if it is already added */  if (NULL != act->tmo_next)    return -SOS_EBUSY;  /* Compute action absolute due date */  if (is_relative_due_date)    {      /* The provided due_date is relative to the current time */      memcpy(& act->timeout, & last_tick_time, sizeof(struct sos_time));      sos_time_inc(& act->timeout, due_date);    }  else    {      /* The provided due_date is absolute (ie relative to the system	 boot instant) */      if (sos_time_cmp(due_date, & last_tick_time) < 0)	/* Refuse to add a past action ! */	return -SOS_EINVAL;      memcpy(& act->timeout, due_date, sizeof(struct sos_time));    }      /* Prepare the action data structure */  act->routine      = routine;  act->routine_data = routine_data;  /* Find the right place in the list of the timeout action. */  insert_before = NULL;  list_foreach_forward_named(timeout_action_list,			     other, nb_act,			     tmo_prev, tmo_next)    {      if (sos_time_cmp(& act->timeout, & other->timeout) < 0)	{	  insert_before = other;	  break;	}      /* Loop over to next timeout */    }  /* Now insert the action in the list */  if (insert_before != NULL)    list_insert_before_named(timeout_action_list, insert_before, act,			    tmo_prev, tmo_next);  else    list_add_tail_named(timeout_action_list, act,			tmo_prev, tmo_next);  return SOS_OK;  }sos_ret_tsos_time_register_action_relative(struct sos_timeout_action *act,				  const struct sos_time *delay,				  sos_timeout_routine_t *routine,				  void *routine_data){  sos_ui32_t flags;  sos_ret_t retval;  sos_disable_IRQs(flags);  retval = _add_action(act, delay, TRUE, routine, routine_data);  sos_restore_IRQs(flags);  return retval;}sos_ret_tsos_time_register_action_absolute(struct sos_timeout_action *act,				  const struct sos_time *date,				  sos_timeout_routine_t *routine,				  void *routine_data){  sos_ui32_t flags;  sos_ret_t retval;  sos_disable_IRQs(flags);  retval = _add_action(act, date, FALSE, routine, routine_data);  sos_restore_IRQs(flags);  return retval;}/** * Helper routine to remove the action from the list. MUST be called * with interrupts disabled ! */static sos_ret_t _remove_action(struct sos_timeout_action *act){  /* Don't do anything if action is not in timeout list */  if (NULL == act->tmo_next)    return -SOS_EINVAL;  /* Update the action's remaining timeout */  if (sos_time_cmp(& act->timeout, & last_tick_time) <= 0)    act->timeout = (struct sos_time){ .sec=0, .nanosec=0 };  else    sos_time_dec(& act->timeout, & last_tick_time);  /* Actually remove the action from the list */  list_delete_named(timeout_action_list, act,		    tmo_prev, tmo_next);  act->tmo_prev = act->tmo_next = NULL;  return SOS_OK;  }sos_ret_t sos_time_unregister_action(struct sos_timeout_action *act){  sos_ret_t retval;  sos_ui32_t flags;  sos_disable_IRQs(flags);  retval = _remove_action(act);  sos_restore_IRQs(flags);  return SOS_OK;  }sos_ret_t sos_time_do_tick(){  sos_ui32_t flags;    sos_disable_IRQs(flags);  /* Update kernel time */  sos_time_inc(& last_tick_time, & tick_resolution);  while (! list_is_empty_named(timeout_action_list, tmo_prev, tmo_next))    {      struct sos_timeout_action *act;      act = list_get_head_named(timeout_action_list, tmo_prev, tmo_next);      /* Did we go too far in the actions' list ? */      if (sos_time_cmp(& last_tick_time, & act->timeout) < 0)	{	  /* Yes: No need to look further. */	  break;	}      /* Remove the action from the list */      _remove_action(act);      /* Call the action's routine */      act->routine(act);    }  sos_restore_IRQs(flags);  return SOS_OK;}

⌨️ 快捷键说明

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