chiark / gitweb /
Describe installation of manpages.
[mLib] / sel.c
1 /* -*-c-*-
2  *
3  * $Id: sel.c,v 1.3 1999/05/21 22:13:59 mdw Exp $
4  *
5  * I/O multiplexing support
6  *
7  * (c) 1999 Straylight/Edgeware
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 $
33  * Revision 1.3  1999/05/21 22:13:59  mdw
34  * Use new `tv' macros.  Fix ordering bug for timeout selectors.
35  *
36  * Revision 1.2  1999/05/15 10:33:32  mdw
37  * Fix copyright notices.
38  *
39  * Revision 1.1  1999/05/14 21:01:14  mdw
40  * Integrated `select' handling bits from the background resolver project.
41  *
42  */
43
44 /*----- Header files ------------------------------------------------------*/
45
46 #include <stdio.h>
47 #include <stdlib.h>
48 #include <string.h>
49
50 #include <sys/types.h>
51 #include <sys/time.h>
52 #include <unistd.h>
53
54 #include "sel.h"
55 #include "tv.h"
56
57 /*----- Main code ---------------------------------------------------------*/
58
59 /* --- @sel_init@ --- *
60  *
61  * Arguments:   @sel_state *s@ = pointer to a state block to initialize
62  *
63  * Returns:     ---
64  *
65  * Use:         Initializes a select state block.
66  */
67
68 void sel_init(sel_state *s)
69 {
70   s->files = 0;
71   s->timers = 0;
72   FD_ZERO(&s->fd[SEL_READ]);
73   FD_ZERO(&s->fd[SEL_WRITE]);
74   FD_ZERO(&s->fd[SEL_EXC]);
75 }
76
77 /* --- @sel_initfile@ --- *
78  *
79  * Arguments:   @sel_state *s@ = select state to attach to
80  *              @sel_file *f@ = pointer to a file block to initialize
81  *              @int fd@ = the file descriptor to listen to
82  *              @unsigned mode@ = what to listen for
83  *              @void (*func)(int fd, unsigned mode, void *p)@ = handler
84  *              @void *p@ = argument to pass to handler
85  *
86  * Returns:     ---
87  *
88  * Use:         Initializes a file block ready for use.  The file block
89  *              isn't added to the list of things to do until a call to
90  *              @sel_addfile@.
91  */
92
93 void sel_initfile(sel_state *s, sel_file *f,
94                   int fd, unsigned mode,
95                   void (*func)(int /*fd*/, unsigned /*mode*/, void */*p*/),
96                   void *p)
97 {
98   f->s = s;
99   f->fd = fd;
100   f->mode = mode;
101   f->func = func;
102   f->p = p;
103 }
104
105 /* --- @sel_addfile@ --- *
106  *
107  * Arguments:   @sel_file *f@ = pointer to a file block
108  *
109  * Returns:     ---
110  *
111  * Use:         Adds a file block into the list of things to listen to.
112  */
113
114 void sel_addfile(sel_file *f)
115 {
116   sel_file **ff = &f->s->files;
117
118   /* --- This little dance looks like line-noise, but it does the job --- */
119
120   while (*ff && (*ff)->fd > f->fd)
121     ff = &(*ff)->next;
122   f->next = *ff;
123   f->prev = (sel_file *)ff;
124   if (*ff)
125     (*ff)->prev = f;
126   *ff = f;
127   FD_SET(f->fd, f->s->fd + f->mode);
128 }
129
130 /* --- @sel_rmfile@ --- *
131  *
132  * Arguments:   @sel_file *f@ = pointer to a file block
133  *
134  * Returns:     ---
135  *
136  * Use:         Removes a file block from the list of things to listen to.
137  */
138
139 void sel_rmfile(sel_file *f)
140 {
141   f->prev->next = f->next;
142   if (f->next)
143     f->next->prev = f->prev;
144   FD_CLR(f->fd, f->s->fd + f->mode);
145 }
146
147 /* --- @sel_addtimer@ --- *
148  *
149  * Arguments:   @sel_state *s@ = pointer to a state block
150  *              @sel_timer *t@ = pointer to a timer block
151  *              @struct timeval *tv@ = pointer to time to activate
152  *              @void (*func)(struct timeval *tv, void *p)@ = handler
153  *              @void *p@ = argument for handler function
154  *
155  * Returns:     ---
156  *
157  * Use:         Registers and sets up a timer.
158  */
159
160 void sel_addtimer(sel_state *s, sel_timer *t,
161                   struct timeval *tv,
162                   void (*func)(struct timeval */*tv*/, void */*p*/),
163                   void *p)
164 {
165   sel_timer **tt = &s->timers;
166
167   /* --- Set up the timer block --- */
168
169   t->tv = *tv;
170   t->func = func;
171   t->p = p;
172
173   /* --- More line noise --- */
174   
175   while (*tt && TV_CMP(&(*tt)->tv, <, tv))
176     tt = &(*tt)->next;
177   t->next = *tt;
178   t->prev = (sel_timer *)tt;
179   if (*tt)
180     (*tt)->prev = t;
181   *tt = t;
182 }
183
184 /* --- @sel_rmtimer@ --- *
185  *
186  * Arguments:   @sel_timer *t@ = pointer to timer block
187  *
188  * Returns:     ---
189  *
190  * Use:         Removes a timer from the list of timers.
191  */
192
193 void sel_rmtimer(sel_timer *t)
194 {
195   t->prev->next = t->next;
196   if (t->next)
197     t->next->prev = t->prev;
198 }
199
200 /* --- @sel_select@ --- *
201  *
202  * Arguments:   @sel_state *s@ = pointer to state block
203  *
204  * Returns:     Zero if all OK, -1 on error.
205  *
206  * Use:         Does a @select@ call (or equivalent @poll@).
207  */
208
209 int sel_select(sel_state *s)
210 {
211   fd_set fd[SEL_MODES];
212   struct timeval tv;
213   int err;
214
215   memcpy(fd, s->fd, sizeof(s->fd));
216   if (s->timers) {
217     struct timeval now;
218     gettimeofday(&now, 0);
219     TV_SUB(&tv, &s->timers->tv, &now);
220     err = select(s->files ? s->files->fd + 1 : 0,
221                  fd + SEL_READ, fd + SEL_WRITE, fd + SEL_EXC,
222                  &tv);
223     gettimeofday(&tv, 0);
224   } else
225     err = select(s->files ? s->files->fd + 1 : 0,
226                  fd + SEL_READ, fd + SEL_WRITE, fd + SEL_EXC,
227                  0);
228
229   if (err < 0)
230     return (err);
231
232   {
233     sel_timer *t, *tt;
234     for (t = s->timers; t && TV_CMP(&t->tv, <=, &tv); t = tt) {
235       tt = t->next;
236       t->next = t->prev = t;
237       t->func(&tv, t->p);
238     }
239     s->timers = t;
240     if (t)
241       t->prev = (sel_timer *)&s->timers;
242   }
243
244   {
245     sel_file *f, *ff;
246     for (f = s->files; f; f = ff) {
247       ff = f->next;
248       if (FD_ISSET(f->fd, fd + f->mode))
249         f->func(f->fd, f->mode, f->p);
250     }
251   }
252
253   return (0);
254 }
255
256 /*----- That's all, folks -------------------------------------------------*/