1. 回调结构体定义

struct  callout {
struct timeval c_time; /* time at which to call routine */
void *c_arg; /* argument to routine */
void (*c_func) __P((void *)); /* routine */
struct callout *c_next;
};

2. 添加超时调度

/*
* timeout - Schedule a timeout.
*/
void
timeout(func, arg, secs, usecs)
void (*func) __P((void *));
void *arg;
int secs, usecs;
{
struct callout *newp, *p, **pp;

/*
* Allocate timeout.
*/
if ((newp = (struct callout *) malloc(sizeof(struct callout))) == NULL)
fatal("Out of memory in timeout()!");
newp->c_arg = arg;
newp->c_func = func;
gettimeofday(&timenow, NULL);
newp->c_time.tv_sec = timenow.tv_sec + secs;
newp->c_time.tv_usec = timenow.tv_usec + usecs;
if (newp->c_time.tv_usec >= 1000000) {
newp->c_time.tv_sec += newp->c_time.tv_usec / 1000000;
newp->c_time.tv_usec %= 1000000;
}

/*
* Find correct place and link it in.
*/
for (pp = &callout; (p = *pp); pp = &p->c_next)
if (newp->c_time.tv_sec < p->c_time.tv_sec
|| (newp->c_time.tv_sec == p->c_time.tv_sec
&& newp->c_time.tv_usec < p->c_time.tv_usec))
break;
newp->c_next = p;
*pp = newp;
}

3. 删除超时调度

/*
* untimeout - Unschedule a timeout.
*/
void
untimeout(func, arg)
void (*func) __P((void *));
void *arg;
{
struct callout **copp, *freep;

/*
* Find first matching timeout and remove it from the list.
*/
for (copp = &callout; (freep = *copp); copp = &freep->c_next)
if (freep->c_func == func && freep->c_arg == arg) {
*copp = freep->c_next;
free((char *) freep);
break;
}
}

4. 执行超时调度

/*
* calltimeout - Call any timeout routines which are now due.
*/
static void
calltimeout()
{
struct callout *p;

while (callout != NULL) {
p = callout;

if (gettimeofday(&timenow, NULL) < 0)
fatal("Failed to get time of day: %m");
if (!(p->c_time.tv_sec < timenow.tv_sec
|| (p->c_time.tv_sec == timenow.tv_sec
&& p->c_time.tv_usec <= timenow.tv_usec)))
break; /* no, it's not time yet */

callout = p->c_next;
(*p->c_func)(p->c_arg);

free((char *) p);
}
}

5. 用例

a. 增加调度函数到队列中

timeout(lcp_delayed_up, f, 0, listen_time * 1000); // lcp_delayed_up()发送数据

其中lcp_delayed_up函数为:

static void
lcp_delayed_up(arg)
void *arg;
{
fsm *f = arg;

if (f->flags & DELAYED_UP) {
f->flags &= ~DELAYED_UP;
fsm_lowerup(f); //发送数据
}
}

即通过第2点的timeout()函数完成了超时函数调度的添加。

b. 轮询调度函数

calltimeout(); //查询超时函数处理