📄 etimer.c
字号:
/* * Copyright 2000-2005 Wind River Systems, Inc. * All rights reserved. Provided under license only. * Distribution or other use of this software is only * permitted pursuant to the terms of a license agreement * from Wind River Systems (and is otherwise prohibited). * Refer to that license agreement for terms of use. *//* * Copyright 1995-1997 Epilogue Technology Corporation. * Copyright 1998 Integrated Systems, Inc. * All rights reserved. *//* * $Log: etimer.c,v $ * Revision 1.4 2003/01/15 14:05:04 josh * directory structure shifting * * Revision 1.3 2001/11/06 21:50:47 josh * second (and hopefully final) pass of new path hacking * * Revision 1.2 2001/11/06 21:20:09 josh * revised new path hacking * * Revision 1.1.1.1 2001/11/05 17:47:42 tneale * Tornado shuffle * * Revision 9.2 2001/01/19 22:22:21 paul * Update copyright. * * Revision 9.1 2000/03/17 00:19:05 meister * Update copyright message * * Revision 9.0 1998/10/16 22:11:26 sar * Update version stamp to match release * * Revision 8.4 1998/08/12 04:44:01 sar * Move the initialization routines around some in order to minimize * the amount of code that gets pulled in for init purposes. * * Revision 8.3 1998/06/19 20:13:51 sar * make sure all files include asn1conf.h and snmp.h to pick up all of * the common code * * Revision 8.2 1998/02/25 15:21:30 sra * Finish moving types.h, bug.h, and bugdef.h to common/h/. * * Revision 8.1 1998/02/25 04:51:48 sra * Update copyrights. * * Revision 8.0 1997/11/18 00:56:49 sar * Updated revision to 8.0 * * Revision 7.4 1997/10/22 03:10:27 sar * Modified the installation options for agentx and the older sub agent scheme * * Also moved the allocation of the locks into envoy_init (env_init.c), * so they can be initialized if necessary. * * Revision 7.3 1997/10/16 00:45:51 sar * Updated for agentx support, with most of the work in mibutils.c to deal * with interior leaves and the pdu processors to deal with agentx leaves, * especially their reference counts. * * Add a bug macro into the get_{read write}_lock calls to give the user * a chance if things start going wrong. * * Fixed a potential problem int the proxy code where we were trying to * stuff a 32 bit quantity into a pointer which may or may not work depending * on the platform. * * Revision 7.2 1997/03/20 06:48:55 sra * DFARS-safe copyright text. Zap! * * Revision 7.1 1997/02/25 10:49:26 sra * Update copyright notice, dust under the bed. * * Revision 7.0 1996/03/18 20:01:11 sar * Updated revision to 7.0 and copyright to 96 * * Revision 6.0 1995/05/31 21:47:23 sra * Release 6.0. * * Revision 1.4 1995/05/02 23:34:50 sar * Copied sra's newest code (so basically the file is new). * * Revision 1.3 1995/04/28 23:13:36 sar * Modified one of the loops to use the next field instead of the current * entry. * * Revision 1.2 1995/04/18 21:19:26 sar * Use the new lock macros and modfiy the code to set a timer to take into * account any time that has elapsed since the first timer was put on the * list. * * Revision 1.1 1995/03/21 00:09:23 sar * Initial revision * * *//* [clearcase]modification history-------------------01b,18apr05,job update copyright notices01a,24nov03,job update copyright information*/#include <wrn/wm/common/types.h>#include <wrn/wm/snmp/engine/asn1conf.h>#include <wrn/wm/snmp/engine/snmp.h>#include <wrn/wm/snmp/engine/etimer.h>#include <wrn/wm/common/bug.h>/* This code was adapted from the attache timer code for use in the Envoy product, the major difference is the addition of if defs to use the envoy locking scheme if it is installed *//* Timers are stored in an ordered linked list. Each timer has a field, t->expire, which indicates when it will expire. The expire field is set to the number of milliseconds it will expire after its predecessor. The first time in the list is set to the number of milliseconds it was originally set to. successive timers that are all set to expire at the same time have t->expire set to 0. The timer code calls ENVOY_CALL_TIMER() to set the one timer provided by the OS; it tells the OS to call envoy_timer_exp() within a certain number of milliseconds. envoy_timer_exp() processes the first timer on the list, and all others after it with t->expire set to 0 until it finds a non-0 timer. envoy_tm_cancel() attempts to clear a timer and remove it from the list, if it fails (can't get the lock) it returns 1, in this case the user should not free the timer block. They may try to cancel the timer later and then free the timer block. we can tell whether a timer is currently in use by checking its expire field. This field is NOT_IN_USE when the timer is not in use. */static void envoy_timer_exp(void);static void envoy_timer_update(void);#define NOT_IN_USE 0xFFFFFFFFL#define IN_USE(tm) ((tm)->expire != NOT_IN_USE)/* * Initialize a timer to a known state (ie, mark timer as not in use). */void envoy_tm_init (ENVOY_TIMER_T *tm){tm->expire = NOT_IN_USE;}/* * Bring the expire times of all timers currently in the queue up to date. * ALL code that modifies the timer queue MUST call this function FIRST! * They must also acquire the write lock for the timer code. */static void envoy_timer_update(void){static bits32_t envoy_last_update;bits32_t now = ENVOY_NOW();bits32_t elapsed = now - envoy_last_update;ENVOY_TIMER_T *t = envoy_timer_list;while (t && elapsed > t->expire) { elapsed -= t->expire; t->expire = 0; t = t->link; }if (t && elapsed > 0) t->expire -= elapsed;envoy_last_update = now;}/* * This function is called when the OS timer fires. This code presumes * that we will not be called until we should have been, and then, * precisely once. [This may no longer be true, but let's be paranoid....] * * We have to be able to deal with the timer list changing as we run through * it, so we loop bringing the expire times up to date and processing the * first timer on the queue if we're reached its expire time. If there's * anything left on the queue when we finish processing expired timers, * we schedule the OS timer to wake us up when it's time to resume processing. * * Processing a timer means dequeuing it and calling its handler. */static void envoy_timer_exp(void){ENVOY_TIMER_T *t;void (*handler)(ENVOY_TIMER_T *, void *);void *cookie;while(1) {#if INSTALL_ENVOY_SNMP_LOCK /* We don't have any good options if we can't get the lock. So we require the user to not do that, if they do we generate a bug report and if they don't handle that we reschedule the timer for a short time in the future which is the the least bad thing to do. */ if (ENVOY_SNMP_GET_WRITE_LOCK(SNMP_TimerLock)) { BUG(BUG_ENVOY_LOCKING, BUG_FATAL, 0, (BUG_OUT, "envoy_timer_exp(): timer lock is broken", 0)); ENVOY_CALL_TIMER(100, envoy_timer_exp); return; }#endif envoy_timer_update(); if (envoy_timer_list && envoy_timer_list->expire == 0) { t = envoy_timer_list; envoy_timer_list = t->link; t->expire = NOT_IN_USE; handler = t->handler; cookie = t->cookie; } else { if (envoy_timer_list) ENVOY_CALL_TIMER(envoy_timer_list->expire, envoy_timer_exp); ENVOY_SNMP_RELEASE_WRITE_LOCK(SNMP_TimerLock); return; } ENVOY_SNMP_RELEASE_WRITE_LOCK(SNMP_TimerLock); handler(t, cookie); }}/* * Set a timer to expire "when" milliseconds from now, canceling it first * if it was already set. We won't queue a timer that has no handler. * * For fairness, if there are other timers already queued that will * expire at the same time as this one, we put this one at the end of * the group so the others will get to run first. * * If, when we're done with the insertion, this timer is the new head * of the queue, we reset the OS timer accordingly. */int envoy_tm_set (ENVOY_TIMER_T *tm, bits32_t when){register ENVOY_TIMER_T **tt;if (!tm || !tm->handler) return(1);if (IN_USE(tm)) if (envoy_tm_cancel(tm)) return(1);#if INSTALL_ENVOY_SNMP_LOCKif (ENVOY_SNMP_GET_WRITE_LOCK(SNMP_TimerLock)) { BUG(BUG_ENVOY_LOCKING, BUG_CONTINUABLE, 0, (BUG_OUT, "envoy_tm_set: timer lock broken", 0)); return(1); }#endifenvoy_timer_update();/* Skip down the queue looking for the right place to insert, adjusting the relative expire time as we go. */tm->expire = when;for (tt = &envoy_timer_list; *tt && (*tt)->expire <= tm->expire; tt = &(*tt)->link) tm->expire -= (*tt)->expire;/* Insert the timer, and adjust the relative expiration time of the timer immediately following it, if there is one. */tm->link = *tt;*tt = tm;if (tm->link) tm->link->expire -= tm->expire;/* If we inserted at the front of the queue, set the OS timer. */if (tm == envoy_timer_list) ENVOY_CALL_TIMER(envoy_timer_list->expire, envoy_timer_exp);ENVOY_SNMP_RELEASE_WRITE_LOCK(SNMP_TimerLock);return(0);}/* * Cancel a timer. We have to adjust the relative expiration time * of the timer immediately following the one we're canceling. * If we're canceling the first timer and the adjusted expiration time * of the new head of the queue is still in the future, we reset the OS * timer. We don't need to reset the OS timer if we're not canceling * the head of the queue. We don't want to reset the OS timer if * the OS is already running behind schedule, because we expect the OS * timer we've already scheduled to expire Real Soon Now. */int envoy_tm_cancel (ENVOY_TIMER_T *tm){register ENVOY_TIMER_T **tt;boolean_t was_first;if (!tm || !IN_USE(tm)) return(0);#if INSTALL_ENVOY_SNMP_LOCKif (ENVOY_SNMP_GET_WRITE_LOCK(SNMP_TimerLock)) { BUG(BUG_ENVOY_LOCKING, BUG_CONTINUABLE, 0, (BUG_OUT, "envoy_tm_cancel: timer lock broken", 0)); return(1); }#endiftt = &envoy_timer_list;was_first = (tm == envoy_timer_list);envoy_timer_update();if (tm->link) tm->link->expire += tm->expire;while (*tt && *tt != tm) tt = &(*tt)->link;if (*tt) *tt = tm->link;tm->expire = NOT_IN_USE;if (was_first && envoy_timer_list && envoy_timer_list->expire > 0) ENVOY_CALL_TIMER(envoy_timer_list->expire, envoy_timer_exp);ENVOY_SNMP_RELEASE_WRITE_LOCK(SNMP_TimerLock);return(0);}#ifdef PRINTFvoid envoy_tm_print(void){ENVOY_TIMER_T *t; if (ENVOY_SNMP_GET_READ_LOCK(SNMP_TimerLock)) { PRINTF("Unable to get read lock for timer list\n"); return; }PRINTF("Timer List:");for (t = envoy_timer_list; t; t = t->link) PRINTF(" %lx(%lu)", (unsigned long) t, (unsigned long) (t->expire));PRINTF("\n");ENVOY_SNMP_RELEASE_READ_LOCK(SNMP_TimerLock);}#endif /* PRINTF */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -