1 /* Copyright (c) 2001 John E. Davis
2 * This file is part of the S-Lang library.
3 *
4 * You may distribute under the terms of either the GNU General Public
5 * License or the Perl Artistic License.
6 */
7 #include <stdio.h>
8 #include <slang.h>
9
10 #include <sys/time.h>
11 #include <sys/types.h>
12 #include <unistd.h>
13 #include <string.h>
14 #include <errno.h>
15
16 SLANG_MODULE(select);
17
pop_fd_set(SLang_Array_Type ** ats,fd_set ** fd_set_p,fd_set * fd_set_buf,int * max_n)18 static int pop_fd_set (SLang_Array_Type **ats,
19 fd_set **fd_set_p, fd_set *fd_set_buf,
20 int *max_n)
21 {
22 unsigned int num, i;
23 SLang_Array_Type *at;
24 SLFile_FD_Type **f;
25
26 *ats = NULL;
27 *fd_set_p = NULL;
28
29 if (SLang_peek_at_stack () == SLANG_NULL_TYPE)
30 return SLang_pop_null ();
31
32 if (-1 == SLang_pop_array_of_type (&at, SLANG_FILE_FD_TYPE))
33 return -1;
34
35 FD_ZERO(fd_set_buf);
36 *fd_set_p = fd_set_buf;
37
38 *ats = at;
39 num = at->num_elements;
40 f = (SLFile_FD_Type **) at->data;
41
42 for (i = 0; i < num; i++)
43 {
44 int fd;
45
46 if (-1 == SLfile_get_fd (f[i], &fd))
47 continue;
48
49 if (fd > *max_n)
50 *max_n = fd;
51
52 FD_SET(fd, fd_set_buf);
53 }
54
55 return 0;
56 }
57
do_fdisset(int nready,SLang_Array_Type * fds,fd_set * fdset)58 static SLang_Array_Type *do_fdisset (int nready, SLang_Array_Type *fds, fd_set *fdset)
59 {
60 SLang_Array_Type *at;
61 unsigned int i, num;
62 SLFile_FD_Type **f;
63
64 if (fds == NULL)
65 nready = 0;
66
67 if (nready)
68 {
69 nready = 0;
70 num = fds->num_elements;
71 f = (SLFile_FD_Type **) fds->data;
72 for (i = 0; i < num; i++)
73 {
74 int fd;
75
76 if (-1 == SLfile_get_fd (f[i], &fd))
77 continue;
78
79 if (FD_ISSET(fd, fdset))
80 nready++;
81 }
82 }
83
84 at = SLang_create_array (SLANG_INT_TYPE, 0, NULL, &nready, 1);
85 if (at == NULL)
86 return NULL;
87
88 if (nready)
89 {
90 int *indx = (int *) at->data;
91 f = (SLFile_FD_Type **) fds->data;
92 num = fds->num_elements;
93 for (i = 0; i < num; i++)
94 {
95 int fd;
96
97 if (-1 == SLfile_get_fd (f[i], &fd))
98 continue;
99
100 if (FD_ISSET(fd, fdset))
101 *indx++ = (int) i;
102 }
103 }
104
105 return at;
106 }
107
push_select_struct(int num,SLang_Array_Type * at_read,SLang_Array_Type * at_write,SLang_Array_Type * at_except,fd_set * readfs,fd_set * writefds,fd_set * exceptfds)108 static int push_select_struct (int num,
109 SLang_Array_Type *at_read,
110 SLang_Array_Type *at_write,
111 SLang_Array_Type *at_except,
112 fd_set *readfs, fd_set *writefds, fd_set *exceptfds)
113 {
114 char *field_names [4];
115 unsigned char field_types[4];
116 VOID_STAR field_values [4];
117 SLang_Array_Type *iread, *iwrite, *iexcept;
118
119 iread = iwrite = iexcept = NULL;
120
121 field_names[0] = "nready";
122 field_names[1] = "iread";
123 field_names[2] = "iwrite";
124 field_names[3] = "iexcept";
125 field_types[0] = SLANG_INT_TYPE;
126 field_types[1] = SLANG_ARRAY_TYPE;
127 field_types[2] = SLANG_ARRAY_TYPE;
128 field_types[3] = SLANG_ARRAY_TYPE;
129 field_values[0] = #
130
131 if ((NULL == (iread = do_fdisset (num, at_read, readfs)))
132 || (NULL == (iwrite = do_fdisset (num, at_write, writefds)))
133 || (NULL == (iexcept = do_fdisset (num, at_except, exceptfds))))
134 {
135 SLang_free_array (iread);
136 SLang_free_array (iwrite);
137 return -1;
138 }
139
140 field_values[1] = &iread;
141 field_values[2] = &iwrite;
142 field_values[3] = &iexcept;
143
144 /* Note: This function call pushes the struct and frees it upon error. */
145 return SLstruct_create_struct (4, field_names, field_types, field_values);
146 }
147
148
149 /* Usage: Struct_Type select (R[],W[],E[],TIME) */
150
select_intrin(double * secsp)151 static void select_intrin (double *secsp)
152 {
153 SLang_Array_Type *at_read, *at_write, *at_except;
154 fd_set readfs_buf, writefds_buf, exceptfds_buf;
155 fd_set readfs_save_buf, writefds_save_buf, exceptfds_save_buf;
156 fd_set *readfs, *writefds, *exceptfds;
157 struct timeval tv, *tv_ptr;
158 double secs;
159 int ret, n;
160
161 secs = *secsp;
162 if (secs < 0.0) tv_ptr = NULL;
163 else
164 {
165 tv.tv_sec = (unsigned long) secs;
166 tv.tv_usec = (unsigned long) ((secs - tv.tv_sec) * 1e6);
167 tv_ptr = &tv;
168 }
169
170 n = 0;
171 if (-1 == pop_fd_set (&at_except, &exceptfds, &exceptfds_buf, &n))
172 return;
173 if (-1 == pop_fd_set (&at_write, &writefds, &writefds_buf, &n))
174 {
175 SLang_free_array (at_except);
176 return;
177 }
178 if (-1 == pop_fd_set (&at_read, &readfs, &readfs_buf, &n))
179 goto free_return;
180
181 readfs_save_buf = readfs_buf;
182 writefds_save_buf = writefds_buf;
183 exceptfds_save_buf = exceptfds_buf;
184
185 n += 1;
186 while (-1 == (ret = select (n, readfs, writefds, exceptfds, tv_ptr)))
187 {
188 #ifdef EINTR
189 if (errno == EINTR)
190 {
191 readfs_buf = readfs_save_buf;
192 writefds_buf = writefds_save_buf;
193 exceptfds_buf = exceptfds_save_buf;
194 continue;
195 }
196 #endif
197 (void) SLerrno_set_errno (errno);
198 break;
199 }
200
201 if (ret == -1)
202 (void) SLang_push_null ();
203 else
204 (void) push_select_struct (ret, at_read, at_write, at_except,
205 readfs, writefds, exceptfds);
206
207
208 free_return:
209 SLang_free_array (at_read);
210 SLang_free_array (at_write);
211 SLang_free_array (at_except);
212 }
213
214 static SLang_Intrin_Fun_Type Select_Intrinsics [] =
215 {
216 MAKE_INTRINSIC_1("select", select_intrin, SLANG_VOID_TYPE, SLANG_DOUBLE_TYPE),
217 SLANG_END_INTRIN_FUN_TABLE
218 };
219
220
init_select_module_ns(char * ns_name)221 int init_select_module_ns (char *ns_name)
222 {
223 SLang_NameSpace_Type *ns;
224
225 ns = SLns_create_namespace (ns_name);
226 if (ns == NULL)
227 return -1;
228
229 if (-1 == SLns_add_intrin_fun_table (ns, Select_Intrinsics, "__SELECT__"))
230 return -1;
231
232 return 0;
233 }
234
235 /* This function is optional */
deinit_select_module(void)236 void deinit_select_module (void)
237 {
238 }
239