diff options
Diffstat (limited to 'libslang/modules/select-module.c')
-rw-r--r-- | libslang/modules/select-module.c | 238 |
1 files changed, 238 insertions, 0 deletions
diff --git a/libslang/modules/select-module.c b/libslang/modules/select-module.c new file mode 100644 index 0000000..f085152 --- /dev/null +++ b/libslang/modules/select-module.c @@ -0,0 +1,238 @@ +/* Copyright (c) 2001 John E. Davis + * This file is part of the S-Lang library. + * + * You may distribute under the terms of either the GNU General Public + * License or the Perl Artistic 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) +{ + unsigned int 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; + unsigned int i, num; + SLFile_FD_Type **f; + + 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++; + } + } + + at = SLang_create_array (SLANG_INT_TYPE, 0, NULL, &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) +{ + char *field_names [4]; + unsigned char field_types[4]; + VOID_STAR field_values [4]; + SLang_Array_Type *iread, *iwrite, *iexcept; + + 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. */ + return SLstruct_create_struct (4, field_names, field_types, field_values); +} + + +/* 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; + 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) +{ +} |