244 строки
5.3 KiB
C
244 строки
5.3 KiB
C
/* Copyright (c) 2010-2017,2018 John E. Davis
|
|
* This file is part of the S-Lang library.
|
|
*
|
|
* You may distribute under the terms of the GNU General Public
|
|
* License.
|
|
*/
|
|
#include <stdio.h>
|
|
#include <slang.h>
|
|
|
|
#include <sys/time.h>
|
|
#include <sys/types.h>
|
|
#include <unistd.h>
|
|
#include <string.h>
|
|
#include <errno.h>
|
|
|
|
SLANG_MODULE(select);
|
|
|
|
static int pop_fd_set (SLang_Array_Type **ats,
|
|
fd_set **fd_set_p, fd_set *fd_set_buf,
|
|
int *max_n)
|
|
{
|
|
SLuindex_Type num, i;
|
|
SLang_Array_Type *at;
|
|
SLFile_FD_Type **f;
|
|
|
|
*ats = NULL;
|
|
*fd_set_p = NULL;
|
|
|
|
if (SLang_peek_at_stack () == SLANG_NULL_TYPE)
|
|
return SLang_pop_null ();
|
|
|
|
if (-1 == SLang_pop_array_of_type (&at, SLANG_FILE_FD_TYPE))
|
|
return -1;
|
|
|
|
FD_ZERO(fd_set_buf);
|
|
*fd_set_p = fd_set_buf;
|
|
|
|
*ats = at;
|
|
num = at->num_elements;
|
|
f = (SLFile_FD_Type **) at->data;
|
|
|
|
for (i = 0; i < num; i++)
|
|
{
|
|
int fd;
|
|
|
|
if (-1 == SLfile_get_fd (f[i], &fd))
|
|
continue;
|
|
|
|
if (fd > *max_n)
|
|
*max_n = fd;
|
|
|
|
FD_SET(fd, fd_set_buf);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static SLang_Array_Type *do_fdisset (int nready, SLang_Array_Type *fds, fd_set *fdset)
|
|
{
|
|
SLang_Array_Type *at;
|
|
int i, num;
|
|
SLFile_FD_Type **f;
|
|
SLindex_Type ind_nready;
|
|
|
|
if (fds == NULL)
|
|
nready = 0;
|
|
|
|
if (nready)
|
|
{
|
|
nready = 0;
|
|
num = fds->num_elements;
|
|
f = (SLFile_FD_Type **) fds->data;
|
|
for (i = 0; i < num; i++)
|
|
{
|
|
int fd;
|
|
|
|
if (-1 == SLfile_get_fd (f[i], &fd))
|
|
continue;
|
|
|
|
if (FD_ISSET(fd, fdset))
|
|
nready++;
|
|
}
|
|
}
|
|
|
|
ind_nready = (SLindex_Type) nready;
|
|
at = SLang_create_array (SLANG_INT_TYPE, 0, NULL, &ind_nready, 1);
|
|
if (at == NULL)
|
|
return NULL;
|
|
|
|
if (nready)
|
|
{
|
|
int *indx = (int *) at->data;
|
|
f = (SLFile_FD_Type **) fds->data;
|
|
num = fds->num_elements;
|
|
for (i = 0; i < num; i++)
|
|
{
|
|
int fd;
|
|
|
|
if (-1 == SLfile_get_fd (f[i], &fd))
|
|
continue;
|
|
|
|
if (FD_ISSET(fd, fdset))
|
|
*indx++ = (int) i;
|
|
}
|
|
}
|
|
|
|
return at;
|
|
}
|
|
|
|
static int 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)
|
|
{
|
|
SLFUTURE_CONST char *field_names [4];
|
|
SLtype field_types[4];
|
|
VOID_STAR field_values [4];
|
|
SLang_Array_Type *iread, *iwrite, *iexcept;
|
|
int status;
|
|
|
|
iread = iwrite = iexcept = NULL;
|
|
|
|
field_names[0] = "nready";
|
|
field_names[1] = "iread";
|
|
field_names[2] = "iwrite";
|
|
field_names[3] = "iexcept";
|
|
field_types[0] = SLANG_INT_TYPE;
|
|
field_types[1] = SLANG_ARRAY_TYPE;
|
|
field_types[2] = SLANG_ARRAY_TYPE;
|
|
field_types[3] = SLANG_ARRAY_TYPE;
|
|
field_values[0] = #
|
|
|
|
if ((NULL == (iread = do_fdisset (num, at_read, readfs)))
|
|
|| (NULL == (iwrite = do_fdisset (num, at_write, writefds)))
|
|
|| (NULL == (iexcept = do_fdisset (num, at_except, exceptfds))))
|
|
{
|
|
SLang_free_array (iread);
|
|
SLang_free_array (iwrite);
|
|
return -1;
|
|
}
|
|
|
|
field_values[1] = &iread;
|
|
field_values[2] = &iwrite;
|
|
field_values[3] = &iexcept;
|
|
|
|
/* Note: This function call pushes the struct and frees it upon error. */
|
|
status = SLstruct_create_struct (4, field_names, field_types, field_values);
|
|
SLang_free_array (iexcept);
|
|
SLang_free_array (iwrite);
|
|
SLang_free_array (iread);
|
|
return status;
|
|
}
|
|
|
|
/* Usage: Struct_Type select (R[],W[],E[],TIME) */
|
|
|
|
static void select_intrin (double *secsp)
|
|
{
|
|
SLang_Array_Type *at_read, *at_write, *at_except;
|
|
fd_set readfs_buf, writefds_buf, exceptfds_buf;
|
|
fd_set readfs_save_buf, writefds_save_buf, exceptfds_save_buf;
|
|
fd_set *readfs, *writefds, *exceptfds;
|
|
struct timeval tv, *tv_ptr;
|
|
double secs;
|
|
int ret, n;
|
|
|
|
secs = *secsp;
|
|
if (secs < 0.0) tv_ptr = NULL;
|
|
else
|
|
{
|
|
tv.tv_sec = (unsigned long) secs;
|
|
tv.tv_usec = (unsigned long) ((secs - tv.tv_sec) * 1e6);
|
|
tv_ptr = &tv;
|
|
}
|
|
|
|
n = 0;
|
|
if (-1 == pop_fd_set (&at_except, &exceptfds, &exceptfds_buf, &n))
|
|
return;
|
|
if (-1 == pop_fd_set (&at_write, &writefds, &writefds_buf, &n))
|
|
{
|
|
SLang_free_array (at_except);
|
|
return;
|
|
}
|
|
if (-1 == pop_fd_set (&at_read, &readfs, &readfs_buf, &n))
|
|
goto free_return;
|
|
|
|
readfs_save_buf = readfs_buf;
|
|
writefds_save_buf = writefds_buf;
|
|
exceptfds_save_buf = exceptfds_buf;
|
|
|
|
n += 1;
|
|
while (-1 == (ret = select (n, readfs, writefds, exceptfds, tv_ptr)))
|
|
{
|
|
#ifdef EINTR
|
|
if (errno == EINTR)
|
|
{
|
|
readfs_buf = readfs_save_buf;
|
|
writefds_buf = writefds_save_buf;
|
|
exceptfds_buf = exceptfds_save_buf;
|
|
if (0 == SLang_handle_interrupt ())
|
|
continue;
|
|
}
|
|
#endif
|
|
(void) SLerrno_set_errno (errno);
|
|
break;
|
|
}
|
|
|
|
if (ret == -1)
|
|
(void) SLang_push_null ();
|
|
else
|
|
(void) push_select_struct (ret, at_read, at_write, at_except,
|
|
readfs, writefds, exceptfds);
|
|
|
|
free_return:
|
|
SLang_free_array (at_read);
|
|
SLang_free_array (at_write);
|
|
SLang_free_array (at_except);
|
|
}
|
|
|
|
static SLang_Intrin_Fun_Type Select_Intrinsics [] =
|
|
{
|
|
MAKE_INTRINSIC_1("select", select_intrin, SLANG_VOID_TYPE, SLANG_DOUBLE_TYPE),
|
|
SLANG_END_INTRIN_FUN_TABLE
|
|
};
|
|
|
|
int init_select_module_ns (char *ns_name)
|
|
{
|
|
SLang_NameSpace_Type *ns;
|
|
|
|
ns = SLns_create_namespace (ns_name);
|
|
if (ns == NULL)
|
|
return -1;
|
|
|
|
if (-1 == SLns_add_intrin_fun_table (ns, Select_Intrinsics, "__SELECT__"))
|
|
return -1;
|
|
|
|
return 0;
|
|
}
|
|
|
|
/* This function is optional */
|
|
void deinit_select_module (void)
|
|
{
|
|
}
|