📄 timerlib.c
字号:
/* timerLib.c - timer library (POSIX) *//* Copyright 1991-2002 Wind River Systems, Inc. */#include "copyright_wrs.h"/*modification history--------------------02w,09may02,wsl add definition of timespec to nanosleep comments; SPR 2608602v,08aug00,jgn move alarm from sigLib to timerLib02u,17jul00,jgn merge DOT-4 pthreads code02t,19oct01,dcb Fix the routine title line to match the coding conventions.02s,21sep99,cno check return from wdDelete (SPR20611)02r,15sep99,pfl fixed compile error02q,09jul99,cno timer_settime returns timer_gettime remaining time (SPR27189)02p,21feb99,jdi doc: listed errnos.02o,05feb96,dbt added a test in timer_settime to detect if the time has already passed (SPR #7463).02n,30oct96,dgp doc: change INTERNAL comment to external for timer_settime per SPR #652502m,09oct06,dgp doc: correct timer_settime() reference per SPR 7323 & 361202l,28mar95,kdl return timer reload value during timer_gettime() (SPR #3299).02k,20jan95,jdi doc cleanup, including new number for POSIX standard.02j,08apr94,dvs added check for disarmed timer in timer_gettime() (SPR #3100).02i,08dec93,dvs added fix of timer_gettime() for interval timer as well.02h,06dec93,dvs timer_gettime() now returns amt of time remaining on the timer (SPR #2673)02g,29nov93,dvs brought up to POSIX draft 14 specification02f,14mar93,jdi fixed typo in code example for timer_connect().02e,11feb93,gae clockLibInit() installed before using timers (#1834). made sure wdStart() not invoked with 0 delay when interval less than clock resolution (#2006).02d,02oct92,jdi documentation cleanup.02c,23sep92,kdl changed include to private/timerLibP.h; deleted signal function prototypes, now in sigLibP.h.02b,19aug92,gae fixed nanosleep() to return correct amount of underrun.02a,22jul92,gae Draft 12 revision. fixed timer_getoverrun(), nanosleep(). Removed timerLibInit() and timer_object_create(). Got rid of objects.01d,25jul92,smb changed time.h to timers.h01d,26may92,rrr the tree shuffle01c,30apr92,rrr some preparation for posix signals.01b,04feb92,gae fixed copyright include; revised according to DEC review. added ability to delete timers from exiting tasks; timer_create() tests for valid signal number; timer_getoverrun() always returns -1 as no support; timer_settime() no longer arms timer with 0 delay. nanosleep() no longer returns +1 on "success"; documentation touchup.01a,16oct91,gae written.*//*DESCRIPTIONThis library provides a timer interface, as defined in the IEEE standard,POSIX 1003.1b.Timers are mechanisms by which tasks signal themselves after a designatedinterval. Timers are built on top of the clock and signal facilities. Theclock facility provides an absolute time-base. Standard timer functionssimply consist of creation, deletion and setting of a timer. When a timerexpires, sigaction() (see sigLib) must be in place in order for the userto handle the event. The "high resolution sleep" facility, nanosleep(),allows sub-second sleeping to the resolution of the clock.The clockLib library should be installed and clock_settime() setbefore the use of any timer routines.ADDITIONSTwo non-POSIX functions are provided for user convenience: timer_cancel() quickly disables a timer by calling timer_settime(). timer_connect() easily hooks up a user routine by calling sigaction().CLARIFICATIONSThe task creating a timer with timer_create() will receive thesignal no matter which task actually arms the timer.When a timer expires and the task has previously exited, logMsg()indicates the expected task is not present. Similarly, logMsg() indicateswhen a task arms a timer without installing a signal handler. Timers maybe armed but not created or deleted at interrupt level.IMPLEMENTATIONThe actual clock resolution is hardware-specific and in many cases is1/60th of a second. This is less than _POSIX_CLOCKRES_MIN, which isdefined as 20 milliseconds (1/50th of a second).INTERNAL1. The <timespec> key calculation is limited by the amount of timerepresented (years?) and the resolution of the clock (1/1000's?).2. Request for option of timer deletion when task is deleted.However, the task that created the timer is not necessarily thetask that is going to receive it (set in timer_settime()).This could be cleared up, if the task calling timer_create()was the task to receive the signal.INCLUDE FILES: timers.hSEE ALSO: clockLib, sigaction(), POSIX 1003.1b documentation,.pG "Basic\ OS"*/#include "vxWorks.h"#include "errno.h"#include "memLib.h"#include "logLib.h"#include "stdio.h"#include "stdlib.h"#include "string.h"#include "taskLib.h"#include "wdLib.h"#include "intLib.h"#include "time.h"#include "tickLib.h"#include "private/sigLibP.h"#include "private/timerLibP.h"#define __PTHREAD_SRC#include "pthread.h"extern int clockLibInit ();int timerLibLog = TRUE; /* log warning messages from wd handler */#define TIMER_RELTIME (~TIMER_ABSTIME) /* relative time *//********************************************************************************* timer_cancel - cancel a timer** This routine is a shorthand method of invoking timer_settime(), which stops* a timer.** NOTE* Non-POSIX.** RETURNS: 0 (OK), or -1 (ERROR) if <timerid> is invalid.** ERRNO: EINVAL*/int timer_cancel ( timer_t timerid /* timer ID */ ) { struct itimerspec value; bzero ((char*)&value, sizeof (value)); return (timer_settime (timerid, TIMER_RELTIME, &value, NULL)); }/********************************************************************************* timerConHandler - default 'connect' timer handler** User routine wrapper called from timerWdHandler().** RETURNS: N/A*/LOCAL void timerConHandler ( int sig, /* caught signal */ timer_t timerid, /* "int code" */ struct sigcontext *pContext /* unused */ ) { if (timerid == NULL) { /* sometimes caused by a pended signal ('code' lost when unblocked) */ if (timerLibLog) { logMsg ("timerConHandler: bad timer %#x, signal %d\n", (int)timerid, sig, 0, 0, 0, 0); } } else if (timerid->routine == NULL) { if (timerLibLog) { logMsg ("timerConHandler: expired %#x, signal %d\n", (int)timerid, sig, 0, 0, 0, 0); } } else { (*timerid->routine) (timerid, timerid->arg); } }/********************************************************************************* timer_connect - connect a user routine to the timer signal** This routine sets the specified <routine> to be invoked with <arg> when* fielding a signal indicated by the timer's <evp> signal number, or* if <evp> is NULL, when fielding the default signal (SIGALRM).** The signal handling routine should be declared as:* .ne 5* .CS* void my_handler* (* timer_t timerid, /@ expired timer ID @/* int arg /@ user argument @/* )* .CE** NOTE* Non-POSIX.** RETURNS: 0 (OK), or -1 (ERROR) if the timer is invalid or cannot bind the * signal handler.** ERRNO: EINVAL*/int timer_connect ( timer_t timerid, /* timer ID */ VOIDFUNCPTR routine, /* user routine */ int arg /* user argument */ ) { static struct sigaction timerSig; if (timerSig.sa_handler == 0) { /* just the first time */ timerSig.sa_handler = (void (*)(int))timerConHandler; (void) sigemptyset (&timerSig.sa_mask); timerSig.sa_flags = 0; /* !SA_SIGINFO: cause timerid to be passed */ } if (intContext ()) return (ERROR); if (timerid == NULL) { errno = EINVAL; return (ERROR); } timerid->routine = routine; timerid->arg = arg; timerid->sevent.sigev_signo = SIGALRM; timerid->sevent.sigev_value.sival_ptr = timerid; /* !SA_SIGINFO */ if (sigaction (SIGALRM, &timerSig, NULL) == ERROR) return (ERROR); else return (OK); }/********************************************************************************* timer_create - allocate a timer using the specified clock for a timing base (POSIX)** This routine returns a value in <pTimer> that identifies the timer * in subsequent timer requests. The <evp> argument, if non-NULL, points to * a `sigevent' structure, which is allocated by the application and defines * the signal number and application-specific data to be sent to the task when * the timer expires. If <evp> is NULL, a default signal (SIGALRM) is queued * to the task, and the signal data is set to the timer ID. Initially, the * timer is disarmed.** RETURNS:* 0 (OK), or -1 (ERROR) if too many timers already are allocated or the signal * number is invalid.** ERRNO: EMTIMERS, EINVAL, ENOSYS, EAGAIN, S_memLib_NOT_ENOUGH_MEMORY** SEE ALSO: timer_delete()*/int timer_create ( clockid_t clock_id, /* clock ID (always CLOCK_REALTIME) */ struct sigevent *evp, /* user event handler */ timer_t * pTimer /* ptr to return value */ ) { timer_t timerid; struct sigevent sevp; if (intContext ()) return (ERROR); (void)clockLibInit (); /* make sure clock "running" */ timerid = (timer_t) calloc (1, sizeof(*timerid)); if (timerid == NULL) { /* errno = EMTIMERS; * S_memLib_NOT_ENOUGH_MEMORY will be lost */ return (ERROR); } if ((timerid->wdog = wdCreate ()) == NULL) { free ((char *) timerid); return (ERROR); } timerid->active = FALSE; timerid->taskId = taskIdSelf (); timerid->clock_id = clock_id; /* should check for known clock_id? */ if (evp == NULL) { sevp.sigev_signo = SIGALRM; /* remember value possibly set in timer_connect() */ /* XXX sevp.sigev_value.sival_int = timerid->sevent.sigev_value.sival_int; */ sevp.sigev_value.sival_ptr = timerid; } else { if (evp->sigev_signo < 1 || evp->sigev_signo > _NSIGS) { errno = EINVAL; return (ERROR); } sevp = *evp; } timerid->sevent = sevp; timerid->sigpend.sigp_info.si_signo = sevp.sigev_signo; timerid->sigpend.sigp_info.si_code = SI_TIMER; timerid->sigpend.sigp_info.si_value = sevp.sigev_value; sigPendInit (&timerid->sigpend); TV_ZERO(timerid->exp.it_interval); TV_ZERO(timerid->exp.it_value); *pTimer = timerid; return (OK); }/********************************************************************************* timer_delete - remove a previously created timer (POSIX)** This routine removes a timer.** RETURNS: 0 (OK), or -1 (ERROR) if <timerid> is invalid.** ERRNO: EINVAL** SEE ALSO: timer_create()*/int timer_delete ( timer_t timerid /* timer ID */ ) { if (intContext ()) return (ERROR); if (timerid == NULL) { errno = EINVAL; return (ERROR); } if (timer_cancel (timerid) != 0) return (ERROR); if (wdDelete (timerid->wdog) != OK) return (ERROR); (void)sigPendDestroy (&timerid->sigpend); free ((char *) timerid); return (OK); }/********************************************************************************* timer_gettime - get the remaining time before expiration and the reload value (POSIX)** This routine gets the remaining time and reload value of a specified timer.* Both values are copied to the <value> structure.** RETURNS: 0 (OK), or -1 (ERROR) if <timerid> is invalid.** ERRNO: EINVAL*/int timer_gettime ( timer_t timerid, /* timer ID */ struct itimerspec *value /* where to return remaining time */ ) { struct timespec now; /* current time */ struct timespec timerExpire; /* absolute time that timer will go off */ if (timerid == NULL || value == NULL) { errno = EINVAL; return (ERROR); } if (timerid->clock_id != CLOCK_REALTIME) { errno = EINVAL; return (ERROR); } /* if timer is disarmed simply set value to 0 */ if (timerid->active == FALSE) { value->it_value.tv_sec = 0; value->it_value.tv_nsec = 0; value->it_interval.tv_sec = 0; value->it_interval.tv_nsec = 0; return (OK); } /* get current time */ if (clock_gettime (CLOCK_REALTIME, &now) == ERROR) return (ERROR);; /* use time stamp and get absolute time that timer will go off */ timerExpire.tv_sec = timerid->timeStamp.tv_sec + timerid->exp.it_value.tv_sec; timerExpire.tv_nsec = timerid->timeStamp.tv_nsec + timerid->exp.it_value.tv_nsec; TV_NORMALIZE (timerExpire); /* compute difference using current time */ value->it_value.tv_sec = timerExpire.tv_sec - now.tv_sec; value->it_value.tv_nsec = timerExpire.tv_nsec - now.tv_nsec; TV_NORMALIZE (value->it_value); /* get reload value */ value->it_interval.tv_sec = timerid->exp.it_interval.tv_sec; value->it_interval.tv_nsec = timerid->exp.it_interval.tv_nsec; TV_NORMALIZE (value->it_interval); return (OK); }/********************************************************************************* timer_getoverrun - return the timer expiration overrun (POSIX)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -