ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/hybrid-ircservices-1/timeout.c
Revision: 1194
Committed: Sat Aug 20 18:25:54 2011 UTC (14 years, 11 months ago) by michael
Content type: text/x-csrc
Original Path: extended-ircservices-1/timeout.c
File size: 4876 byte(s)
Log Message:
- add new Extended IRC Services project. Successor of the discontinued
  ircservices project by Andrew Church.

File Contents

# User Rev Content
1 michael 1194 /* Routines for time-delayed actions.
2     *
3     * IRC Services is copyright (c) 1996-2009 Andrew Church.
4     * E-mail: <achurch@achurch.org>
5     * Parts written by Andrew Kempe and others.
6     * This program is free but copyrighted software; see the file GPL.txt for
7     * details.
8     */
9    
10     #include "services.h"
11     #define IN_TIMEOUT_C
12     #include "timeout.h"
13    
14     /*************************************************************************/
15    
16     static Timeout *timeouts = NULL;
17     static int checking_timeouts = 0;
18    
19     /*************************************************************************/
20    
21     #ifdef DEBUG_COMMANDS
22    
23     /* Send the timeout list to the given user. */
24    
25     void send_timeout_list(User *u)
26     {
27     Timeout *to;
28     uint32 now = time_msec();
29    
30     notice(ServerName, u->nick, "Now: %u.%03u", now/1000, now%1000);
31     LIST_FOREACH (to, timeouts) {
32     notice(ServerName, u->nick, "%p: %u.%03u: %p (%p)",
33     to, to->timeout/1000, to->timeout%1000, to->code, to->data);
34     }
35     }
36    
37     #endif /* DEBUG_COMMANDS */
38    
39     /*************************************************************************/
40    
41     /* Check the timeout list for any pending actions. */
42    
43     void check_timeouts(void)
44     {
45     Timeout *to, *to2;
46     uint32 now = time_msec();
47    
48     if (checking_timeouts)
49     fatal("check_timeouts() called recursively!");
50     checking_timeouts = 1;
51     log_debug(2, "Checking timeouts at time_msec = %u.%03u",
52     now/1000, now%1000);
53    
54     LIST_FOREACH_SAFE (to, timeouts, to2) {
55     if (to->timeout) {
56     if ((int32)(to->timeout - now) > 0)
57     continue;
58     log_debug(3, "Running timeout %p (code=%p repeat=%d)",
59     to, to->code, to->repeat);
60     to->code(to);
61     if (to->repeat) {
62     to->timeout = now + to->repeat;
63     if (!to->timeout) /* watch out for zero! */
64     to->timeout++;
65     continue;
66     }
67     }
68     LIST_REMOVE(to, timeouts);
69     free(to);
70     }
71    
72     log_debug(2, "Finished timeout list");
73     checking_timeouts = 0;
74     }
75    
76     /*************************************************************************/
77    
78     /* Add a timeout to the list to be triggered in `delay' seconds. If
79     * `repeat' is nonzero, do not delete the timeout after it is triggered.
80     * This must maintain the property that timeouts added from within a
81     * timeout routine do not get checked during that run of the timeout list.
82     */
83    
84     Timeout *add_timeout(int delay, void (*code)(Timeout *), int repeat)
85     {
86     if (delay < 0) {
87     log("add_timeout(): called with a negative delay! (%d)", delay);
88     return NULL;
89     }
90     if (!code) {
91     log("add_timeout(): called with code==NULL!");
92     return NULL;
93     }
94     if (delay > 2147483) { /* 2^31/1000 (watch out for difference overflow) */
95     log("add_timeout(): delay (%ds) too long, shortening to 2147483s",
96     delay);
97     delay = 2147483;
98     }
99     return add_timeout_ms((uint32)delay*1000, code, repeat);
100     }
101    
102     /*************************************************************************/
103    
104     /* The same thing, but using milliseconds instead of seconds. */
105    
106     Timeout *add_timeout_ms(uint32 delay, void (*code)(Timeout *), int repeat)
107     {
108     Timeout *t;
109    
110     if (!code) {
111     log("add_timeout_ms(): called with code==NULL!");
112     return NULL;
113     }
114     if (delay > 2147483647) {
115     log("add_timeout_ms(): delay (%dms) too long, shortening to"
116     " 2147483647ms", delay);
117     delay = 2147483647;
118     }
119     t = malloc(sizeof(Timeout));
120     if (!t)
121     return NULL;
122     t->settime = time(NULL);
123     t->timeout = time_msec() + delay;
124     /* t->timeout==0 is used to signal that the timeout should be deleted;
125     * if the timeout value just happens to wrap around to 0, lengthen it
126     * by a millisecond. */
127     if (!t->timeout)
128     t->timeout++;
129     t->code = code;
130     t->data = NULL;
131     t->repeat = repeat ? delay : 0;
132     LIST_INSERT(t, timeouts);
133     return t;
134     }
135    
136     /*************************************************************************/
137    
138     /* Remove a timeout from the list (if it's there). */
139    
140     void del_timeout(Timeout *t)
141     {
142     Timeout *ptr;
143    
144     if (!t) {
145     log("del_timeout(): called with t==NULL!");
146     return;
147     }
148     LIST_FOREACH (ptr, timeouts) {
149     if (ptr == t)
150     break;
151     }
152     if (!ptr) {
153     log("del_timeout(): attempted to remove timeout %p (not on list)", t);
154     return;
155     }
156     if (checking_timeouts) {
157     t->timeout = 0; /* delete it when we hit it in the list */
158     return;
159     }
160     LIST_REMOVE(t, timeouts);
161     free(t);
162     }
163    
164     /*************************************************************************/
165    
166     /*
167     * Local variables:
168     * c-file-style: "stroustrup"
169     * c-file-offsets: ((case-label . *) (statement-case-intro . *))
170     * indent-tabs-mode: nil
171     * End:
172     *
173     * vim: expandtab shiftwidth=4:
174     */