1 /* Copyright (c) 2010-2017,2018 John E. Davis
2 * This file is part of the S-Lang library.
3 *
4 * You may distribute under the terms of the GNU General Public
5 * 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 SLuindex_Type 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 int i, num;
62 SLFile_FD_Type **f;
63 SLindex_Type ind_nready;
64
65 if (fds == NULL)
66 nready = 0;
67
68 if (nready)
69 {
70 nready = 0;
71 num = fds->num_elements;
72 f = (SLFile_FD_Type **) fds->data;
73 for (i = 0; i < num; i++)
74 {
75 int fd;
76
77 if (-1 == SLfile_get_fd (f[i], &fd))
78 continue;
79
80 if (FD_ISSET(fd, fdset))
81 nready++;
82 }
83 }
84
85 ind_nready = (SLindex_Type) nready;
86 at = SLang_create_array (SLANG_INT_TYPE, 0, NULL, &ind_nready, 1);
87 if (at == NULL)
88 return NULL;
89
90 if (nready)
91 {
92 int *indx = (int *) at->data;
93 f = (SLFile_FD_Type **) fds->data;
94 num = fds->num_elements;
95 for (i = 0; i < num; i++)
96 {
97 int fd;
98
99 if (-1 == SLfile_get_fd (f[i], &fd))
100 continue;
101
102 if (FD_ISSET(fd, fdset))
103 *indx++ = (int) i;
104 }
105 }
106
107 return at;
108 }
109
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)110 static int push_select_struct (int num,
111 SLang_Array_Type *at_read,
112 SLang_Array_Type *at_write,
113 SLang_Array_Type *at_except,
114 fd_set *readfs, fd_set *writefds, fd_set *exceptfds)
115 {
116 SLFUTURE_CONST char *field_names [4];
117 SLtype field_types[4];
118 VOID_STAR field_values [4];
119 SLang_Array_Type *iread, *iwrite, *iexcept;
120 int status;
121
122 iread = iwrite = iexcept = NULL;
123
124 field_names[0] = "nready";
125 field_names[1] = "iread";
126 field_names[2] = "iwrite";
127 field_names[3] = "iexcept";
128 field_types[0] = SLANG_INT_TYPE;
129 field_types[1] = SLANG_ARRAY_TYPE;
130 field_types[2] = SLANG_ARRAY_TYPE;
131 field_types[3] = SLANG_ARRAY_TYPE;
132 field_values[0] = #
133
134 if ((NULL == (iread = do_fdisset (num, at_read, readfs)))
135 || (NULL == (iwrite = do_fdisset (num, at_write, writefds)))
136 || (NULL == (iexcept = do_fdisset (num, at_except, exceptfds))))
137 {
138 SLang_free_array (iread);
139 SLang_free_array (iwrite);
140 return -1;
141 }
142
143 field_values[1] = &iread;
144 field_values[2] = &iwrite;
145 field_values[3] = &iexcept;
146
147 /* Note: This function call pushes the struct and frees it upon error. */
148 status = SLstruct_create_struct (4, field_names, field_types, field_values);
149 SLang_free_array (iexcept);
150 SLang_free_array (iwrite);
151 SLang_free_array (iread);
152 return status;
153 }
154
155 /* Usage: Struct_Type select (R[],W[],E[],TIME) */
156
select_intrin(double * secsp)157 static void select_intrin (double *secsp)
158 {
159 SLang_Array_Type *at_read, *at_write, *at_except;
160 fd_set readfs_buf, writefds_buf, exceptfds_buf;
161 fd_set readfs_save_buf, writefds_save_buf, exceptfds_save_buf;
162 fd_set *readfs, *writefds, *exceptfds;
163 struct timeval tv, *tv_ptr;
164 double secs;
165 int ret, n;
166
167 secs = *secsp;
168 if (secs < 0.0) tv_ptr = NULL;
169 else
170 {
171 tv.tv_sec = (unsigned long) secs;
172 tv.tv_usec = (unsigned long) ((secs - tv.tv_sec) * 1e6);
173 tv_ptr = &tv;
174 }
175
176 n = 0;
177 if (-1 == pop_fd_set (&at_except, &exceptfds, &exceptfds_buf, &n))
178 return;
179 if (-1 == pop_fd_set (&at_write, &writefds, &writefds_buf, &n))
180 {
181 SLang_free_array (at_except);
182 return;
183 }
184 if (-1 == pop_fd_set (&at_read, &readfs, &readfs_buf, &n))
185 goto free_return;
186
187 readfs_save_buf = readfs_buf;
188 writefds_save_buf = writefds_buf;
189 exceptfds_save_buf = exceptfds_buf;
190
191 n += 1;
192 while (-1 == (ret = select (n, readfs, writefds, exceptfds, tv_ptr)))
193 {
194 #ifdef EINTR
195 if (errno == EINTR)
196 {
197 readfs_buf = readfs_save_buf;
198 writefds_buf = writefds_save_buf;
199 exceptfds_buf = exceptfds_save_buf;
200 if (0 == SLang_handle_interrupt ())
201 continue;
202 }
203 #endif
204 (void) SLerrno_set_errno (errno);
205 break;
206 }
207
208 if (ret == -1)
209 (void) SLang_push_null ();
210 else
211 (void) push_select_struct (ret, at_read, at_write, at_except,
212 readfs, writefds, exceptfds);
213
214 free_return:
215 SLang_free_array (at_read);
216 SLang_free_array (at_write);
217 SLang_free_array (at_except);
218 }
219
220 static SLang_Intrin_Fun_Type Select_Intrinsics [] =
221 {
222 MAKE_INTRINSIC_1("select", select_intrin, SLANG_VOID_TYPE, SLANG_DOUBLE_TYPE),
223 SLANG_END_INTRIN_FUN_TABLE
224 };
225
init_select_module_ns(char * ns_name)226 int init_select_module_ns (char *ns_name)
227 {
228 SLang_NameSpace_Type *ns;
229
230 ns = SLns_create_namespace (ns_name);
231 if (ns == NULL)
232 return -1;
233
234 if (-1 == SLns_add_intrin_fun_table (ns, Select_Intrinsics, "__SELECT__"))
235 return -1;
236
237 return 0;
238 }
239
240 /* This function is optional */
deinit_select_module(void)241 void deinit_select_module (void)
242 {
243 }
244