chiark / gitweb /
Make the selector type symbols an enumeration rather than a bunch of
[mLib] / sel.c
CommitLineData
97f65b00 1/* -*-c-*-
2 *
a3ddb778 3 * $Id: sel.c,v 1.2 1999/05/15 10:33:32 mdw Exp $
97f65b00 4 *
5 * I/O multiplexing support
6 *
a3ddb778 7 * (c) 1999 Straylight/Edgeware
97f65b00 8 */
9
10/*----- Licensing notice --------------------------------------------------*
11 *
12 * This file is part of the mLib utilities library.
13 *
14 * mLib is free software; you can redistribute it and/or modify
15 * it under the terms of the GNU Library General Public License as
16 * published by the Free Software Foundation; either version 2 of the
17 * License, or (at your option) any later version.
18 *
19 * mLib is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU Library General Public License for more details.
23 *
24 * You should have received a copy of the GNU Library General Public
25 * License along with mLib; if not, write to the Free
26 * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
27 * MA 02111-1307, USA.
28 */
29
30/*----- Revision history --------------------------------------------------*
31 *
32 * $Log: sel.c,v $
a3ddb778 33 * Revision 1.2 1999/05/15 10:33:32 mdw
34 * Fix copyright notices.
35 *
97f65b00 36 * Revision 1.1 1999/05/14 21:01:14 mdw
37 * Integrated `select' handling bits from the background resolver project.
38 *
39 */
40
41/*----- Header files ------------------------------------------------------*/
42
43#include <stdio.h>
44#include <stdlib.h>
45#include <string.h>
46
47#include <sys/types.h>
48#include <sys/time.h>
49#include <unistd.h>
50
51#include "sel.h"
52#include "tv.h"
53
54/*----- Main code ---------------------------------------------------------*/
55
56/* --- @sel_init@ --- *
57 *
58 * Arguments: @sel_state *s@ = pointer to a state block to initialize
59 *
60 * Returns: ---
61 *
62 * Use: Initializes a select state block.
63 */
64
65void sel_init(sel_state *s)
66{
67 s->files = 0;
68 s->timers = 0;
69 FD_ZERO(&s->fd[SEL_READ]);
70 FD_ZERO(&s->fd[SEL_WRITE]);
71 FD_ZERO(&s->fd[SEL_EXC]);
72}
73
74/* --- @sel_initfile@ --- *
75 *
76 * Arguments: @sel_state *s@ = select state to attach to
77 * @sel_file *f@ = pointer to a file block to initialize
78 * @int fd@ = the file descriptor to listen to
79 * @unsigned mode@ = what to listen for
80 * @void (*func)(int fd, unsigned mode, void *p)@ = handler
81 * @void *p@ = argument to pass to handler
82 *
83 * Returns: ---
84 *
85 * Use: Initializes a file block ready for use. The file block
86 * isn't added to the list of things to do until a call to
87 * @sel_addfile@.
88 */
89
90void sel_initfile(sel_state *s, sel_file *f,
91 int fd, unsigned mode,
92 void (*func)(int /*fd*/, unsigned /*mode*/, void */*p*/),
93 void *p)
94{
95 f->s = s;
96 f->fd = fd;
97 f->mode = mode;
98 f->func = func;
99 f->p = p;
100}
101
102/* --- @sel_addfile@ --- *
103 *
104 * Arguments: @sel_file *f@ = pointer to a file block
105 *
106 * Returns: ---
107 *
108 * Use: Adds a file block into the list of things to listen to.
109 */
110
111void sel_addfile(sel_file *f)
112{
113 sel_file **ff = &f->s->files;
114
115 /* --- This little dance looks like line-noise, but it does the job --- */
116
117 while (*ff && (*ff)->fd > f->fd)
118 ff = &(*ff)->next;
119 f->next = *ff;
120 f->prev = (sel_file *)ff;
121 if (*ff)
122 (*ff)->prev = f;
123 *ff = f;
124 FD_SET(f->fd, f->s->fd + f->mode);
125}
126
127/* --- @sel_rmfile@ --- *
128 *
129 * Arguments: @sel_file *f@ = pointer to a file block
130 *
131 * Returns: ---
132 *
133 * Use: Removes a file block from the list of things to listen to.
134 */
135
136void sel_rmfile(sel_file *f)
137{
138 f->prev->next = f->next;
139 if (f->next)
140 f->next->prev = f->prev;
141 FD_CLR(f->fd, f->s->fd + f->mode);
142}
143
144/* --- @sel_addtimer@ --- *
145 *
146 * Arguments: @sel_state *s@ = pointer to a state block
147 * @sel_timer *t@ = pointer to a timer block
148 * @struct timeval *tv@ = pointer to time to activate
149 * @void (*func)(struct timeval *tv, void *p)@ = handler
150 * @void *p@ = argument for handler function
151 *
152 * Returns: ---
153 *
154 * Use: Registers and sets up a timer.
155 */
156
157void sel_addtimer(sel_state *s, sel_timer *t,
158 struct timeval *tv,
159 void (*func)(struct timeval */*tv*/, void */*p*/),
160 void *p)
161{
162 sel_timer **tt = &s->timers;
163
164 /* --- Set up the timer block --- */
165
166 t->tv = *tv;
167 t->func = func;
168 t->p = p;
169
170 /* --- More line noise --- */
171
172 while (*tt && tv_cmp(&(*tt)->tv, tv) > 0)
173 tt = &(*tt)->next;
174 t->next = *tt;
175 t->prev = (sel_timer *)tt;
176 if (*tt)
177 (*tt)->prev = t;
178 *tt = t;
179}
180
181/* --- @sel_rmtimer@ --- *
182 *
183 * Arguments: @sel_timer *t@ = pointer to timer block
184 *
185 * Returns: ---
186 *
187 * Use: Removes a timer from the list of timers.
188 */
189
190void sel_rmtimer(sel_timer *t)
191{
192 t->prev->next = t->next;
193 if (t->next)
194 t->next->prev = t->prev;
195}
196
197/* --- @sel_select@ --- *
198 *
199 * Arguments: @sel_state *s@ = pointer to state block
200 *
201 * Returns: Zero if all OK, -1 on error.
202 *
203 * Use: Does a @select@ call (or equivalent @poll@).
204 */
205
206int sel_select(sel_state *s)
207{
208 fd_set fd[SEL_MODES];
209 struct timeval tv;
210 int err;
211
212 memcpy(fd, s->fd, sizeof(s->fd));
213 if (s->timers) {
214 struct timeval now;
215 gettimeofday(&now, 0);
216 tv_sub(&tv, &now, &s->timers->tv);
217 err = select(s->files ? s->files->fd + 1 : 0,
218 fd + SEL_READ, fd + SEL_WRITE, fd + SEL_EXC,
219 &tv);
220 gettimeofday(&tv, 0);
221 } else
222 err = select(s->files ? s->files->fd + 1 : 0,
223 fd + SEL_READ, fd + SEL_WRITE, fd + SEL_EXC,
224 0);
225
226 if (err < 0)
227 return (err);
228
229 {
230 sel_timer *t, *tt;
231 for (t = s->timers; t && tv_cmp(&t->tv, &tv) <= 0; t = tt) {
232 tt = t->next;
233 t->next = t->prev = t;
234 t->func(&tv, t->p);
235 }
236 s->timers = t;
237 if (t)
238 t->prev = (sel_timer *)&s->timers;
239 }
240
241 {
242 sel_file *f, *ff;
243 for (f = s->files; f; f = ff) {
244 ff = f->next;
245 if (FD_ISSET(f->fd, fd + f->mode))
246 f->func(f->fd, f->mode, f->p);
247 }
248 }
249
250 return (0);
251}
252
253/*----- That's all, folks -------------------------------------------------*/