4856dda33e068f46479d10f2f3ec62c219594341
[spider.git] / src / sel.c
1 /*
2  * sel.c
3  * 
4  * util routines for do the various select activities
5  * 
6  * Copyright 1996 (c) D-J Koopman
7  * 
8  * $Header$
9  */
10  
11
12 static char rcsid[] = "$Id$";
13
14 #include <sys/time.h>
15 #include <sys/types.h>
16 #include <unistd.h>
17 #include <stdlib.h>
18 #include <time.h>
19 #include <string.h>
20 #include <errno.h>
21
22 #include "chain.h"
23 #include "sel.h"
24
25 sel_t *sel;                                                        /* the array of selectors */
26 int sel_max;                                               /* the maximum no of selectors */
27 int sel_top;                                               /* the last selector in use */
28 int sel_inuse;                                             /* the no of selectors in use */
29 time_t sel_systime;                                        /* the unix time now */
30 struct timeval sel_tv;                             /* the current timeout for select */
31
32 /*
33  * initialise the selector system, no is the no of slots to reserve
34  */
35
36 void sel_init(int no, long sec, long usec)
37 {
38         sel = malloc(sizeof(sel_t) * no);
39         if (!sel)
40                 die("no room in sel_init");
41         memset(sel, 0, sizeof(sel_t) * no);
42         sel_max = no;
43         sel_inuse = sel_top = 0;
44         if (sec == 0 && usec == 0) 
45                 usec = 10000;
46         sel_tv.tv_sec = sec;
47         sel_tv.tv_usec = usec;
48 }
49
50 /*
51  * open and initialise a selector slot, you are expected to deal with the
52  * actual opening and setting up of the device itself
53  */
54
55 sel_t *sel_open(int cnum, void *fcb, char *name, int (*handler)(), int sort, int flags)
56 {
57         int i;
58         sel_t *sp;
59         
60         /* get a free slot */
61         for (i = 0; i < sel_max; ++i) {
62                 sp = &sel[i];
63                 if (sp->sort == 0)
64                         break;
65         }
66         if (i >= sel_max)
67                 die("there are no more sel slots available (max %d)", sel_max);
68         
69         /* fill in the blanks */
70         sp->cnum = cnum;
71         sp->fcb = fcb;
72         sp->name = strdup(name);
73         sp->handler = handler;
74         sp->sort = sort;
75         sp->flags = flags;
76         sp->msgbase = chain_new();
77         sp->err = 0;
78         ++sel_inuse;
79         if (sel_top < (sp - sel) + 1)
80                 sel_top = (sp - sel) + 1;
81         return sp;
82 }
83
84 /*
85  * close (and thus clear down) a slot, it is assumed that you have done whatever
86  * you need to do to close the actual device already
87  */
88
89 void sel_close(sel_t *sp)
90 {
91         if (sp->sort) {
92                 chain_flush(sp->msgbase);
93                 free(sp->msgbase);
94                 free(sp->name);
95                 memset(sp, 0, sizeof(sel_t));
96                 if (sel_top == (sp - sel) + 1)
97                         --sel_top;
98                 --sel_inuse;
99         }
100 }
101
102 /*
103  * this actually runs the (de)multiplexor, it simply listens to the various cnums 
104  * presents the events to the handler which has to deal with them
105  */
106
107 void sel_run()
108 {
109         int i, r, max = 0;
110         struct timeval tv;
111         fd_set infd;
112         fd_set outfd;
113         fd_set errfd;
114         sel_t *sp;
115         
116         /* first set up the parameters for the select according to the slots registered */
117         FD_ZERO(&infd);
118         FD_ZERO(&outfd);
119         FD_ZERO(&errfd);
120         tv = sel_tv;
121         
122         for (i = 0; i < sel_top; ++i) {
123                 sp = &sel[i];
124                 if (sp->sort && !sp->err) {
125                         if (sp->flags & SEL_INPUT)
126                                 FD_SET(sp->cnum, &infd);
127                         if (sp->flags & SEL_OUTPUT)
128                                 FD_SET(sp->cnum, &outfd);
129                         if (sp->flags & SEL_ERROR)
130                                 FD_SET(sp->cnum, &errfd);
131                         if (sp->cnum > max)
132                                 max = sp->cnum;
133                 }
134         }
135         
136         /* now do the select */
137         r = select(max + 1, &infd, &outfd, &errfd, &tv);
138
139         if (r < 0) {
140                 if (errno != EINTR)
141                         die("Error during select (%d)", errno);
142                 return;
143         }
144
145         /* if there is anything to do, pass it on to the appropriate handler */
146         if (r > 0) {
147                 int in, out, err;
148                 int hr;
149                 
150                 for (i = 0; i < sel_top; ++i) {
151                         sp = &sel[i];
152                         if (sp->sort) {
153                                 in = FD_ISSET(sp->cnum, &infd);
154                                 out = FD_ISSET(sp->cnum, &outfd);
155                                 err = FD_ISSET(sp->cnum, &errfd);
156                                 if (in || out || err) {
157                                         hr = (sp->handler)(sp, in, out, err);
158                                         
159                                         /* if this is positive, close this selector */
160                                         if (hr)
161                                                 sel_close(sp);
162                                         else {
163                                                 FD_CLR(sp->cnum, &infd);
164                                                 FD_CLR(sp->cnum, &outfd);
165                                                 FD_CLR(sp->cnum, &errfd);
166                                         }
167                                 }
168                         }
169                 }
170         }
171         
172         time(&sel_systime);                                /* note the time, for general purpuse use */
173 }
174
175 /*
176  * get/set error flag - -1 simply gets the flag, 0 or 1 sets the flag
177  * 
178  * in all cases the old setting of the flag is returned
179  */
180
181 int sel_error(sel_t *sp, int err)
182 {
183         int r = sp->err;
184         if (err >= 0)
185                 sp->err = err;
186         return r;
187 }
188
189 /*
190  * $Log$
191  * Revision 1.4  2000-07-20 14:16:00  minima
192  * can use Sourceforge now!
193  * added user->qra cleaning
194  * added 4 digit qra to user broadcast dxspots if available
195  *
196  * Revision 1.3  2000/03/30 22:51:14  djk
197  * fixed connect code in client.pl so it doesn't falsely recognise /spider
198  * /src/client as a 'client' directive.
199  * Tidied up the C client a bit
200  *
201  * Revision 1.2  2000/03/26 14:22:59  djk
202  * removed some irrelevant log info
203  *
204  * Revision 1.1  2000/03/26 00:03:30  djk
205  * first cut of client
206  *
207  * Revision 1.1  1997/01/03 23:44:31  djk
208  * initial workings
209  *
210  *
211  */