2086
|
1 /* -*- Mode: C; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
|
2
|
|
3 /*
|
|
4 * $Id: timeout.c 2096 2001-07-31 01:00:39Z warmenhoven $
|
|
5 *
|
|
6 * Copyright (C) 1998-2001, Denis V. Dmitrienko <denis@null.net> and
|
|
7 * Bill Soudan <soudan@kde.org>
|
|
8 *
|
|
9 * This program is free software; you can redistribute it and/or modify
|
|
10 * it under the terms of the GNU General Public License as published by
|
|
11 * the Free Software Foundation; either version 2 of the License, or
|
|
12 * (at your option) any later version.
|
|
13 *
|
|
14 * This program is distributed in the hope that it will be useful,
|
|
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
17 * GNU General Public License for more details.
|
|
18 *
|
|
19 * You should have received a copy of the GNU General Public License
|
|
20 * along with this program; if not, write to the Free Software
|
|
21 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
|
22 *
|
|
23 */
|
|
24
|
|
25 #include <stdlib.h>
|
|
26
|
|
27 #include "timeout.h"
|
|
28
|
|
29 icq_Timeout *icq_CurrentTimeout = NULL;
|
|
30 icq_List *icq_TimeoutList = NULL;
|
|
31
|
|
32 void (*icq_SetTimeout)(long length);
|
|
33
|
|
34 int icq_TimeoutCompare(icq_Timeout *t1, icq_Timeout *t2)
|
|
35 {
|
|
36 return (t1->expire_time - t2->expire_time);
|
|
37 }
|
|
38
|
|
39 icq_Timeout *icq_TimeoutNew(int length, icq_TimeoutHandler handler,
|
|
40 void *data)
|
|
41 {
|
|
42 icq_Timeout *t = (icq_Timeout *)malloc(sizeof(icq_Timeout));
|
|
43
|
|
44 if (t)
|
|
45 {
|
|
46 int count = icq_TimeoutList->count;
|
|
47
|
|
48 t->length = length;
|
|
49 t->handler = handler;
|
|
50 t->data = data;
|
|
51 t->expire_time = time(NULL) + length;
|
|
52 t->single_shot = 1;
|
|
53
|
|
54 icq_ListInsertSorted(icq_TimeoutList, t);
|
|
55
|
|
56 if (count == 0)
|
|
57 icq_TimeoutDoNotify();
|
|
58 }
|
|
59
|
|
60 return t;
|
|
61 }
|
|
62
|
|
63 void icq_TimeoutDelete(icq_Timeout *timeout)
|
|
64 {
|
|
65 icq_ListRemove(icq_TimeoutList, timeout);
|
|
66
|
|
67 /* if this was the timeout we were currently waiting on, move on
|
|
68 * to the next */
|
|
69 if (icq_CurrentTimeout == timeout)
|
|
70 {
|
|
71 icq_CurrentTimeout = NULL;
|
|
72 icq_TimeoutDoNotify();
|
|
73 }
|
|
74
|
|
75 free(timeout);
|
|
76 }
|
|
77
|
|
78 int _icq_HandleTimeout1(void *p, va_list data)
|
|
79 {
|
|
80 icq_Timeout *t = p;
|
|
81 int complete = 0;
|
|
82 time_t current_time = va_arg(data, time_t);
|
|
83 icq_List *expired_timeouts = va_arg(data, icq_List *);
|
|
84 (void)data;
|
|
85
|
|
86 if (t->expire_time <= current_time)
|
|
87 icq_ListEnqueue(expired_timeouts, t);
|
|
88 else
|
|
89 /* traversal is complete when we reach an expire time in the future */
|
|
90 complete = 1;
|
|
91
|
|
92 return complete;
|
|
93 }
|
|
94
|
|
95 int _icq_HandleTimeout2(void *p, va_list data)
|
|
96 {
|
|
97 icq_Timeout *t = p;
|
|
98 (void)data;
|
|
99
|
|
100 /* maybe a previously executed timeout caused us to be deleted, so
|
|
101 * make sure we're still around */
|
|
102 if (icq_ListFind(icq_TimeoutList, t))
|
|
103 (t->handler)(t->data);
|
|
104
|
|
105 return 0; /* traverse entire list */
|
|
106 }
|
|
107
|
|
108 int _icq_HandleTimeout3(void *p, va_list data)
|
|
109 {
|
|
110 icq_Timeout *t = p;
|
|
111 int complete = 0;
|
|
112 time_t current_time = va_arg(data, time_t);
|
|
113
|
|
114 if (t->expire_time <= current_time)
|
|
115 {
|
|
116 if (t->single_shot)
|
|
117 icq_TimeoutDelete(t);
|
|
118 else
|
|
119 t->expire_time = current_time + t->length;
|
|
120 }
|
|
121 else
|
|
122 /* traversal is complete when we reach an expire time in the future */
|
|
123 complete = 1;
|
|
124
|
|
125 return complete;
|
|
126 }
|
|
127
|
|
128 void icq_HandleTimeout()
|
|
129 {
|
|
130 time_t current_time = time(NULL);
|
|
131 icq_List *expired_timeouts = icq_ListNew();
|
|
132
|
|
133 icq_CurrentTimeout = NULL;
|
|
134
|
|
135 /* these three operations must be split up for the case where a
|
|
136 * timeout function causes timers to be deleted - this ensures
|
|
137 * we don't try to free any timers that have already been removed
|
|
138 * or corrupt the list traversal process */
|
|
139
|
|
140 /* determine which timeouts that have expired */
|
|
141 icq_ListTraverse(icq_TimeoutList, _icq_HandleTimeout1, current_time,
|
|
142 expired_timeouts);
|
|
143
|
|
144 /* call handler function for expired timeouts */
|
|
145 icq_ListTraverse(expired_timeouts, _icq_HandleTimeout2);
|
|
146
|
|
147 /* delete any expired timeouts */
|
|
148 icq_ListTraverse(icq_TimeoutList, _icq_HandleTimeout3, current_time);
|
|
149
|
|
150 /* if there's any timeouts left, notify the library client */
|
|
151 if (icq_TimeoutList->count)
|
|
152 icq_TimeoutDoNotify();
|
|
153
|
|
154 icq_ListDelete(expired_timeouts, NULL);
|
|
155 }
|
|
156
|
|
157 void icq_TimeoutDoNotify()
|
|
158 {
|
|
159 time_t length, current_time = time(NULL);
|
|
160
|
|
161 if (!icq_TimeoutList->count)
|
|
162 {
|
|
163 if (icq_SetTimeout)
|
|
164 (*icq_SetTimeout)(0);
|
|
165 return;
|
|
166 }
|
|
167
|
|
168 icq_CurrentTimeout = (icq_Timeout *)icq_ListFirst(icq_TimeoutList);
|
|
169 length = icq_CurrentTimeout->expire_time - current_time;
|
|
170
|
|
171 if (icq_SetTimeout)
|
|
172 (*icq_SetTimeout)(length);
|
|
173 }
|