Discussion:
[ast-developers] poll(1) update...
Roland Mainz
2013-09-16 22:58:59 UTC
Permalink
Hi!

----

Attached (as "astksh_20130913_poll1_update004.diff.txt") is the (long
awaited) update for the poll(1) builtin.

* Changes:
- Mostly code cleanup
- use of "bool" in the "events" variable is now mandatory to simplify some code
- poll(1) now has a -s option (similar to sleep(1)) to exit when
poll(2) was interupted by a signal or similar event. poll(1) (like
poll(2)) will return an error, but with exit code 2 instead of exit
code 1 as for normal errors

Comments/rants/etc. welcome...

----

Bye,
Roland
--
__ . . __
(o.\ \/ /.o) roland.mainz at nrubsig.org
\__\/\/__/ MPEG specialist, C&&JAVA&&Sun&&Unix programmer
/O /==\ O\ TEL +49 641 3992797
(;O/ \/ \O;)
-------------- next part --------------
diff -r -u original/src/cmd/ksh93/bltins/poll.c build_poll/src/cmd/ksh93/bltins/poll.c
--- src/cmd/ksh93/bltins/poll.c 2013-04-11 21:48:39.000000000 +0200
+++ src/cmd/ksh93/bltins/poll.c 2013-09-16 23:52:21.140525532 +0200
@@ -1,7 +1,7 @@
/***********************************************************************
* *
* This software is part of the ast package *
-* Copyright (c) 2007-2012 AT&T Intellectual Property *
+* Copyright (c) 2012-2013 AT&T Intellectual Property *
* and is licensed under the *
* Eclipse Public License, Version 1.0 *
* by AT&T Intellectual Property *
@@ -40,7 +40,7 @@

static
const char sh_optpoll[] =
-"[-?\n@(#)$Id: poll (AT&T Labs Research) 2012-08-16 $\n]"
+"[-?\n@(#)$Id: poll (AT&T Labs Research) 2013-09-14 $\n]"
"[-author?Roland Mainz <roland.mainz at nrubsig.org>]"
"[-license?http://www.eclipse.org/org/documents/epl-v10.html]"
"[+NAME? poll - input/output multiplexing]"
@@ -110,7 +110,7 @@
"This flag is only valid in the \brevents\b compound "
"variable; it is not used in the \bevents\b "
"compound variable.]"
- "}"
+ "}"
"]"

"[+?If the value fd is less than 0, events is ignored and "
@@ -146,17 +146,17 @@
"to other types of file is unspecified.]"

"[+?The poll utility supports sockets.]"
-#ifdef __SunOS
-"[+?The poll utility may be used on Solaris on directory fds of "
+
+"[+?The poll utility may be used on Solaris/Illumos on directory fds of "
"/proc/$pid/ to get a \bpollhup='true'\b when the process quits.]"
-#endif
+
"[+?A file descriptor for a socket that is listening for connections "
"will indicate that it is ready for reading, once connections "
"are available. A file descriptor for a socket that "
"is connecting asynchronously will indicate that it is ready "
"for writing, once a connection has been established.]"

-"[+?Regular files always poll TRUE for reading and writing.]"
+"[+?Regular files always poll 'true' for reading and writing.]"

"[e:eventarray]:[fdcount?Upon successful completion, an indexed array "
"of strings is returned which contains a list of array "
@@ -164,7 +164,8 @@
"[S!:pollsfio?Look into sfio streams for buffered information and set "
"pollin/pollout to reflect sfio stream state.]"
"[R:pollttyraw?Put tty connections into raw mode when polling. The "
- "fd is returned to tty cooked mode before poll(1) exits.]"
+ "fd is returned to tty cooked mode before \bpoll\b(1) exits.]"
+"[s:sleep?Sleep until a signal, poll event or a timeout is received.]"
"[t:timeout]:[seconds?Timeout in seconds. If the value timeout is 0, "
"poll returns immediately. If the value of timeout is -1, "
"poll blocks until a requested event occurs or until the "
@@ -185,6 +186,10 @@
"may appear in the \brevents\b compound variable even if "
"they were not requested in \bevents\b.]"

+ "[+?It is recommended to use the \bbool\b type for the \bevents\b "
+ "variables (it can currently not be enforced for "
+ "backwards-compatibility reasons but may be done in the future).]"
+
"[+?Using the value of variables in \brevents\b which are "
"not set in \bevents\b can be done by putting a '-' suffix "
"after the variable name, e.g. use "
@@ -192,19 +197,30 @@
"\bar[x]].revents.pollhup\b or an empty string if the variable "
"was not set.]"

+ "[+?If any of the \bpoll*\b variables in \bevents\b uses the "
+ "\b_Bool\b type all \bpoll*\b variables in \revents\b will be "
+ "of type \b_Bool\b, too.]"
+
"[+?Like \bpoll\b(2) it is legal to poll on the same fd in "
"multiple entries, for exanple to listen for different events "
"or to allow multiple callers to pool their poll lists "
"together into one \bpoll\b(1) call.]"
"}"

+"[+KNOWN BUGS?]{"
+ "[+?Multidimensional (typeset -a ar=( [4]][16]]=... )) indexed "
+ "arrays are currently not supported.]"
+"}"
+
/* quoting: ']' must be quoted as "]]" and '?' must be quoted as "//" */
"[+EXAMPLES?]{"
"[+?The following example will wait for 10 seconds for input "
"on fd 0, variable \bp[fd0]].revents.pollin\b will be 'true' "
"or 'false' depening on whether the stream 0 is ready for "
"reading:]{"
- "[+?compound -A p=( [fd0]]=( fd=0 events=( pollin='true' ) ) ) ; poll -t10 p ; print -v p]"
+ "[+?compound -A p=( [fd0]]=( integer fd=0 ; compound events=( bool pollin='true' ) ) ) ; "
+ "poll -t10 p ; "
+ "print -v p]"
"}"

"[+?The following example will wait for 2 seconds for input "
@@ -212,7 +228,11 @@
"\bp[0]].revents.pollhup\b will be 'true' after polling ends "
"because there is both input data available and the end of "
"the stream was reached:]{"
- "[+?printf '\\n' | ksh -c 'compound -a p=( ( fd=0 events=( pollin=\"true\" pollhup=\"true\" ) ) ) ; poll -t2 p ; print -v p']"
+ "[+?printf '\\n' | "
+ "ksh -c 'compound -a p=( ( integer fd=0 ; "
+ "compound events=( bool pollin=\"true\" pollhup=\"true\" ) ) ) ; "
+ "poll -t2 p ; "
+ "print -v p']"
"}"
"}"

@@ -231,9 +251,39 @@
vsnprintf(varnamebuff, sizeof(varnamebuff), namefmt, ap);
va_end(ap);

- return nv_open(varnamebuff, dict, flags);
+ return(nv_open(varnamebuff, dict, flags));
+}
+
+
+static
+bool nv_is_bool_t(Namval_t *np)
+{
+ Namval_t *nv;
+ const char *np_tn; /* type name */
+
+ nv=nv_type(np);
+ if (!nv)
+ return(false);
+ np_tn=nv->nvname;
+ if (!np_tn)
+ return(false);
+ if (strcmp(np_tn, "_Bool"))
+ return(false);
+ return(true);
+}
+
+
+static
+Namval_t *nv_get_bool_t(Shell_t *shp)
+{
+ Namval_t *b;
+ b = nv_search("_Bool", shp->bltin_tree,0);
+ if (!b)
+ return(NULL);
+ return(nv_type(b));
}

+
/* Name/value mapping table for POLL*-flags */
struct pollflagnamemap
{
@@ -300,9 +350,19 @@
int eventvar_found;
};

+typedef struct State_s /* program state */
+{
+ Shbltin_t *context;
+ Shell_t *shp;
+ Namval_t *bool_t; /* handle to the _Bool type */
+ bool eagain;
+ int poll_errno; /* errno returned by |poll()| */
+} State_t;
+
+
/* poll on given |fds| data and retry after EINTR/EAGAIN while adjusting timeout */
static
-int poll_loop(Shbltin_t* context, struct pollfd *fds, nfds_t nfds, int timeout)
+int poll_loop(State_t *state, struct pollfd *fds, nfds_t nfds, int timeout)
{
/* nanoseconds to milliseconds */
#define TIME_NS2MS(t) ((t)/(1000UL*1000UL))
@@ -324,98 +384,109 @@
do
{
while(((n = poll(fds, nfds, timeout)) < 0) &&
- ((errno == EINTR) || (errno == EAGAIN)) &&
- (!context->sigset))
- errno=0;
-
- timeout_ns=timeout_ns-(tmxgettime()-starttime);
- timeout=TIME_NS2MS(timeout_ns);
- } while((timeout > 0) && (!context->sigset));
+ (((errno == EINTR) || (errno == EAGAIN)) && state->eagain) &&
+ (!state->context->sigset))
+ errno = 0;
+ state->poll_errno = errno;
+
+ timeout_ns = timeout_ns-(tmxgettime()-starttime);
+ timeout = TIME_NS2MS(timeout_ns);
+ } while((timeout > 0) && (!state->context->sigset));
}
else
{
while(((n = poll(fds, nfds, timeout)) < 0) &&
- ((errno == EINTR) || (errno == EAGAIN)) &&
- (!context->sigset))
- errno=0;
+ (((errno == EINTR) || (errno == EAGAIN)) && state->eagain) &&
+ (!state->context->sigset))
+ errno = 0;
+ state->poll_errno = errno;
}
- return n;
+ return(n);
}


/* get ".poll*"-variables in "ar[i].events" and store data in |currpollfd| and |currps| */
static
-bool get_compound_revents(Shell_t *shp, const char *parrayname, struct pollstat *currps, struct pollfd *currpollfd)
+bool get_compound_revents(State_t *state, const char *parrayname, struct pollstat *currps, struct pollfd *currpollfd)
{
- const char *subname=currps->array_subscript;
+ const char *subname = currps->array_subscript;
Namval_t *np;
int fd;
int pi;
+ bool success = true;

- np = nv_open_fmt(shp->var_tree, NV_VARNAME|NV_NOFAIL|NV_NOADD, "%s[%s].fd", parrayname, subname);
+ np = nv_open_fmt(state->shp->var_tree, NV_VARNAME|NV_NOFAIL|NV_NOADD, "%s[%s].fd", parrayname, subname);
if (!np)
{
errormsg(SH_DICT, ERROR_ERROR, "missing pollfd %s[%s].fd", parrayname, subname);
- return false;
+ return(false);
}
fd = (int)nv_getnum(np);
nv_close(np);
+
+ /* fd==-1 means "ignore entry" */
if ((fd < -1) || (fd > OPEN_MAX))
{
errormsg(SH_DICT, ERROR_ERROR, "invalid pollfd %s[%s].fd %d", parrayname, subname, fd);
- return false;
+ return(false);
}
currpollfd->fd = fd;

- np = nv_open_fmt(shp->var_tree, NV_VARNAME|NV_COMVAR|NV_NOFAIL|NV_NOADD, "%s[%s].events", parrayname, subname);
+ np = nv_open_fmt(state->shp->var_tree, NV_VARNAME|NV_COMVAR|NV_NOFAIL|NV_NOADD, "%s[%s].events", parrayname, subname);
if (!np)
{
errormsg(SH_DICT, ERROR_ERROR, "missing pollfd %s[%s].events", parrayname, subname);
- return false;
+ return(false);
}
nv_close(np);

- currpollfd->events=0;
- currpollfd->revents=0;
- currps->eventvar_found=0;
+ currpollfd->events = 0;
+ currpollfd->revents = 0;
+ currps->eventvar_found = 0;
+
for (pi=0 ; pfnm[pi].name != NULL ; pi++)
{
- const char *s;
-
- np = nv_open_fmt(shp->var_tree, NV_VARNAME|NV_NOFAIL|NV_NOADD, "%s[%s].events.%s", parrayname, subname, pfnm[pi].name);
+ np = nv_open_fmt(state->shp->var_tree, NV_VARNAME|NV_NOFAIL|NV_NOADD, "%s[%s].events.%s", parrayname, subname, pfnm[pi].name);
if (!np)
+ {
+ /* ignore this, it may be a sparse array */
continue;
+ }

- currps->eventvar_found |= pfnm[pi].flag;
- s=nv_getval(np);
- if (s != NULL)
+ if (nv_is_bool_t(np))
{
- if (!strcmp(s, "true"))
+ currps->eventvar_found |= pfnm[pi].flag;
+ if (((bool)nv_getnum(np)) == true)
currpollfd->events |= pfnm[pi].flag;
- else if (!strcmp(s, "false"))
- ;
- else
- errormsg(SH_DICT, ERROR_ERROR, "invalid boolean value % in variable %s[%s].events", s, parrayname, subname);
+
}
+ else
+ {
+ errormsg(SH_DICT, ERROR_ERROR, "%s[%s].events.%s is not of type _Bool", parrayname, subname, pfnm[pi].name);
+ success = false;
+ }
+
nv_close(np);
}

- return true;
+ return(success);
}

+
/* set ".poll*"-variables in "ar[i].revents" per data in |currpollfd| and |currps| */
static
-void set_compound_revents(Shell_t *shp, const char *parrayname, struct pollstat *currps, struct pollfd *currpollfd)
+bool set_compound_revents(State_t *state, const char *parrayname, struct pollstat *currps, struct pollfd *currpollfd)
{
- const char *subname=currps->array_subscript;
- Namval_t *np;
- int pi;
+ const char *subname = currps->array_subscript;
+ Namval_t *np;
+ int pi;
+ bool success = true;

- np = nv_open_fmt(shp->var_tree, NV_VARNAME|NV_NOFAIL|NV_COMVAR, "%s[%s].revents", parrayname, subname);
+ np = nv_open_fmt(state->shp->var_tree, NV_VARNAME|NV_NOFAIL|NV_COMVAR, "%s[%s].revents", parrayname, subname);
if (!np)
{
errormsg(SH_DICT, ERROR_ERROR, "could not create pollfd %s[%s].revents", parrayname, subname);
- return;
+ return(false);
}
nv_setvtree(np); /* make "revents" really a compound variable */
nv_close(np);
@@ -429,21 +500,29 @@
if ((currps->eventvar_found & pfnm[pi].flag) ||
((currpollfd->revents & (POLLHUP|POLLNVAL|POLLERR)) & pfnm[pi].flag))
{
- np = nv_open_fmt(shp->var_tree, NV_VARNAME|NV_NOFAIL, "%s[%s].revents.%s", parrayname, subname, pfnm[pi].name);
+ np = nv_open_fmt(state->shp->var_tree, NV_VARNAME|NV_NOFAIL, "%s[%s].revents.%s", parrayname, subname, pfnm[pi].name);
if (!np)
+ {
+ success = false;
continue;
+ }

+ nv_settype(np, state->bool_t, 0);
nv_putval(np, ((currpollfd->revents & pfnm[pi].flag)?"true":"false"), 0);
+
nv_close(np);
}
}
+
+ return(success);
}

+
/* |main()| for poll(1) builtin */
extern
int b_poll(int argc, char *argv[], Shbltin_t* context)
{
- Shell_t *shp = sh_contexttoshell(context);
+ State_t state;
Namval_t *np,
*array_np,
*array_np_sub;
@@ -453,7 +532,7 @@
*subname, /* current subscript */
*s;
int n;
- nfds_t numpollfd = 0; /* number of entries to poll */
+ nfds_t numpollfd = 0; /* number of entries to poll */
int i,
j;
double timeout = -1.;
@@ -467,6 +546,11 @@
*currps; /* current |pollstat| we are working on */
int retval = 0; /* return value of builtin */

+ state.context = context;
+ state.shp = sh_contexttoshell(context);
+ state.eagain = true;
+ state.poll_errno = 0;
+
while (n = optget(argv, sh_optpoll)) switch (n)
{
case 't':
@@ -476,12 +560,15 @@
errormsg(SH_DICT, ERROR_system(1), "%s: invalid timeout", opt_info.arg);

/* -t uses seconds */
- if (timeout >=0)
+ if (timeout >= 0)
timeout *= 1000.;
break;
case 'e':
eventarrayname = opt_info.arg;
break;
+ case 's':
+ state.eagain=opt_info.num?false:true;
+ break;
case 'S':
pollsfio=opt_info.num?true:false;
break;
@@ -502,11 +589,15 @@

parrayname = argv[0];

+ state.bool_t = nv_get_bool_t(state.shp);
+ if (!state.bool_t)
+ errormsg(SH_DICT, ERROR_system(1), "internal error: _Bool type not found");
+
strstk = stkopen(0);
if (!strstk)
errormsg(SH_DICT, ERROR_system(1), e_nospace);

- array_np = nv_open(parrayname, shp->var_tree, NV_VARNAME|NV_NOFAIL|NV_NOADD);
+ array_np = nv_open(parrayname, state.shp->var_tree, NV_VARNAME|NV_NOFAIL|NV_NOADD);
if (!array_np)
{
stkclose(strstk);
@@ -551,7 +642,7 @@
i = 0;
do
{
- if (!(subname=nv_getsub(array_np_sub)))
+ if (!(subname = nv_getsub(array_np_sub)))
break;

pollstat[i].array_subscript=stkcopy(strstk, subname);
@@ -561,14 +652,14 @@
goto done_error;
}

- if (!get_compound_revents(shp, parrayname, &pollstat[i], &pollfd[i]))
+ if (!get_compound_revents(&state, parrayname, &pollstat[i], &pollfd[i]))
goto done_error;

i++;
} while(array_np_sub && nv_nextsub(array_np_sub));

nv_close(array_np);
- array_np=NULL;
+ array_np = NULL;

/*
* If sfio handles fds we need to check whether there are
@@ -592,11 +683,11 @@

for (i=0 ; i < numpollfd ; i++)
{
- currps=&pollstat[i];
- fd=pollfd[i].fd;
+ currps = &pollstat[i];
+ fd = pollfd[i].fd;

- currps->sfio.sfd=(fd>=0)?sh_fd2sfio(shp, fd):NULL;
- currps->sfio.flags=0;
+ currps->sfio.sfd = (fd>=0)?sh_fd2sfio(state.shp, fd):NULL;
+ currps->sfio.flags = 0;
if (currps->sfio.sfd!=NULL)
{
/* Only add |currps->sfio.sfd| to the
@@ -618,7 +709,7 @@
break;
}
if (j == num_sfd)
- sfd[num_sfd++]=currps->sfio.sfd;
+ sfd[num_sfd++] = currps->sfio.sfd;
}
}

@@ -640,7 +731,7 @@
for (j=0 ; j < numpollfd ; j++)
{
if (pollstat[j].sfio.sfd == sfd[i])
- pollstat[j].sfio.flags=sfpoll_flags;
+ pollstat[j].sfio.flags = sfpoll_flags;
}
}
}
@@ -651,7 +742,7 @@
*/
if (eventarrayname)
{
- np = nv_open_fmt(shp->var_tree, NV_VARNAME|NV_ARRAY|NV_NOFAIL, "%s", eventarrayname);
+ np = nv_open_fmt(state.shp->var_tree, NV_VARNAME|NV_ARRAY|NV_NOFAIL, "%s", eventarrayname);
if (!np)
{
errormsg(SH_DICT, ERROR_ERROR, "could not create eventarray variable %s", eventarrayname);
@@ -659,6 +750,10 @@
}

nv_close(np);
+
+ /* Clear array */
+ sfsprintf(buff, sizeof(buff), "%s=()", eventarrayname);
+ sh_trap(state.shp, buff, 0);
}

/*
@@ -670,8 +765,8 @@

for (i=0 ; i < numpollfd ; i++)
{
- fd=pollfd[i].fd;
- if ((fd >=0) && (shp->fdstatus[fd]&IOTTY))
+ fd = pollfd[i].fd;
+ if ((fd >= 0) && (state.shp->fdstatus[fd]&IOTTY))
tty_raw(fd, 1);
}
}
@@ -679,7 +774,7 @@
/*
* ... then poll for events...
*/
- n = poll_loop(context, pollfd, numpollfd, timeout);
+ n = poll_loop(&state, pollfd, numpollfd, timeout);

/*
* ... and restore the tty's to "cooked" mode
@@ -690,17 +785,19 @@

for (i=0 ; i < numpollfd ; i++)
{
- fd=pollfd[i].fd;
- if ((fd >=0) && (shp->fdstatus[fd]&IOTTY))
+ fd = pollfd[i].fd;
+ if ((fd >= 0) && (state.shp->fdstatus[fd]&IOTTY))
tty_cooked(fd);
}
}

if (n < 0)
{
+ retval = (state.poll_errno==EAGAIN || state.poll_errno==EINTR)?2:1;
+ errno = state.poll_errno;
/* |ERROR_system(0)| won't quit the builtin */
errormsg(SH_DICT, ERROR_system(0), "poll(2) failure");
- retval=1;
+
}

/*
@@ -717,20 +814,21 @@
pollfd[i].revents |= POLLOUT;
}

- set_compound_revents(shp, parrayname, &pollstat[i], &pollfd[i]);
+ if (!set_compound_revents(&state, parrayname, &pollstat[i], &pollfd[i]))
+ retval = 1;

/* Add array index to eventarray if this pollfd entry had any events */
if (eventarrayname && pollfd[i].revents)
{
sfsprintf(buff, sizeof(buff), "%s+=( '%s' )", eventarrayname, pollstat[i].array_subscript);
- sh_trap(shp, buff, 0);
+ sh_trap(state.shp, buff, 0);
}
}

goto done;

done_error:
- retval=1;
+ retval = 1;
done:
if (array_np)
nv_close(array_np);
diff -r -u original/src/cmd/ksh93/tests/builtin_poll.sh build_poll/src/cmd/ksh93/tests/builtin_poll.sh
--- src/cmd/ksh93/tests/builtin_poll.sh 2013-05-11 22:23:48.000000000 +0200
+++ src/cmd/ksh93/tests/builtin_poll.sh 2013-09-16 22:32:11.545232157 +0200
@@ -1,26 +1,7 @@
########################################################################
# #
# This software is part of the ast package #
-# Copyright (c) 1982-2013 AT&T Intellectual Property #
-# and is licensed under the #
-# Eclipse Public License, Version 1.0 #
-# by AT&T Intellectual Property #
-# #
-# A copy of the License is available at #
-# http://www.eclipse.org/org/documents/epl-v10.html #
-# (with md5 checksum b35adb5213ca9657e911e9befb180842) #
-# #
-# Information and Software Systems Research #
-# AT&T Research #
-# Florham Park NJ #
-# #
-# David Korn <dgk at research.att.com> #
-# #
-########################################################################
-########################################################################
-# #
-# This software is part of the ast package #
-# Copyright (c) 2009-2012 Roland Mainz #
+# Copyright (c) 2009-2013 Roland Mainz #
# and is licensed under the #
# Eclipse Public License, Version 1.0 #
# by AT&T Intellectual Property #
@@ -35,7 +16,7 @@
########################################################################

#
-# Copyright (c) 2009, 2012, Roland Mainz. All rights reserved.
+# Copyright (c) 2009, 2013, Roland Mainz. All rights reserved.
#

#
@@ -70,8 +51,8 @@
{
compound d1=(
compound -A u=(
- [y]=( integer fd=5 ; compound events=( pollin='true' ) revents=() )
- [x]=( integer fd=5 ; compound events=( pollin='true' ) revents=() )
+ [y]=( integer fd=5 ; compound events=( bool pollin='true' ) revents=() )
+ [x]=( integer fd=5 ; compound events=( bool pollin='true' ) revents=() )
)
)

@@ -88,7 +69,7 @@

# test 2:
unset d1.res
- d1.u[z]=( integer fd=5 ; compound events=( pollout='true' ) revents=() )
+ d1.u[z]=( integer fd=5 ; compound events=( bool pollout='true' ) revents=() )

print -C d1 >'testdata.cpv'
$SHELL -o errexit -c 'builtin poll ; read -C <"testdata.cpv" d1 ; { poll -e d1.res -t 5. d1.u ; } 5<"/dev/null" 5>"/dev/null" ; print -C d1 >"testdata.cpv"' >'log.txt' 2>&1 || err_exit "poll returned non-zero exit code $?"
@@ -120,19 +101,19 @@
$'integer i maxfd=$(getconf "OPEN_MAX")\n'
$'(( maxfd-=10 )) # space for stdin/stdout/stderr/dirfd\n'
$'for (( i=0 ; i < maxfd ; i++ )) ; do\n'
- $' pl[$((i*17))]=( fd=0 events=( pollin=true ) )\n'
+ $' pl[$((i*17))]=( fd=0 events=( bool pollin=true ) )\n'
$'done\n'
$'poll -R -t2 pl\n'
$'print -v pl\n'
$'print "OK"\n'
)
- expected_output_pattern='~(E)([[:space:]]*?\([[:space:]]*?\[.+\]=\([[:space:]]*?events=\([[:space:]]*?pollin=true[[:space:]]*?\)[[:space:]]*?fd=0[[:space:]]*?revents=\([[:space:]]*?pollhup=true[[:space:]]*?pollin=true[[:space:]]*?\)[[:space:]]*?\)[[:space:]]*?\)[[:space:]]*?)+OK'
+ expected_output_pattern='~(E)([[:space:]]*?\([[:space:]]*?\[.+\]=\([[:space:]]*?events=\([[:space:]]*?(_Bool|)[[:space:]]*?pollin=true[[:space:]]*?\)[[:space:]]*?fd=0[[:space:]]*?revents=\([[:space:]]*?(_Bool|)[[:space:]]*?pollhup=true[[:space:]]*?(_Bool|)[[:space:]]*?pollin=true[[:space:]]*?\)[[:space:]]*?\)[[:space:]]*?\)[[:space:]]*?)+OK'
)
(
name='sparse_type_array1'
typeset -r -a script=(
$'builtin poll\n'
- $'typeset -T p_t=( typeset -l -i fd ; \n'
+ $'typeset -T p_t=( typeset fd=-1 ; \n' # fixme: This should be "integer fd=-1" but ast-ksh.2013-09-13 crashes
# fixme: In theory we only have to list the events we want
# in the compound variable "events" ... and the same events
# plus pollerr, pollnval and pollup in "revents" (since
@@ -141,8 +122,8 @@
# which triggers fatal errors in case we try to read a
# non-existing type variable member - see
# http://marc.info/?l=ast-developers&m=134526131905059&w=2
- $' compound events=( typeset pollin=false pollpri=false pollout=false pollrdnorm=false pollwrnorm=false pollrdband=false pollwrband=false pollmsg=false pollremove=false pollrdhup=false pollerr=false pollhup=false pollnval=false ; )\n'
- $' compound revents=( typeset pollin=false pollpri=false pollout=false pollrdnorm=false pollwrnorm=false pollrdband=false pollwrband=false pollmsg=false pollremove=false pollrdhup=false pollerr=false pollhup=false pollnval=false ; )\n'
+ $' compound events=( bool pollin=false pollpri=false pollout=false pollrdnorm=false pollwrnorm=false pollrdband=false pollwrband=false pollmsg=false pollremove=false pollrdhup=false pollerr=false pollhup=false pollnval=false ; )\n'
+ $' compound revents=( bool pollin=false pollpri=false pollout=false pollrdnorm=false pollwrnorm=false pollrdband=false pollwrband=false pollmsg=false pollremove=false pollrdhup=false pollerr=false pollhup=false pollnval=false ; )\n'
$' function pinit { _.fd=$1 ; _.events.pollin=true ; } ;\n'
$')\n'
$'compound c ; p_t -a c.pl\n'
@@ -158,13 +139,13 @@
$'print -v c\n'
$'print "OK"\n'
)
- expected_output_pattern='~(Xlr)\([[:space:]]+?p_t[[:space:]]+?-a[[:space:]]+?pl=\([[:space:]]+?([[:space:]]+?\[[[:alnum:]]+\]=\([[:space:]]+?typeset[[:space:]]+?-l[[:space:]]+?-i[[:space:]]+?fd=0[[:space:]]+?events=\((([^\x28\x29]+?pollin=true[^\x28\x29]+?)&([^\x28\x29]+?pollhup=false[^\x28\x29]+?))[[:space:]]+?\)[[:space:]]+?revents=\((([^\x28\x29]+?pollin=true[^\x28\x29]+?)&([^\x28\x29]+?pollhup=true[^\x28\x29]+?))\)[[:space:]]+?\)[[:space:]]+?)+?[[:space:]]+?\)[[:space:]]+?\)[[:space:]]+?OK'
+ expected_output_pattern='~(Xlr)\([[:space:]]+?p_t[[:space:]]+?-a[[:space:]]+?pl=\([[:space:]]+?([[:space:]]+?\[[[:alnum:]]+\]=\(([[:space:]]+?typeset[[:space:]]+?-l[[:space:]]+?-i)*?[[:space:]]+?fd=0[[:space:]]+?events=\((([^\x28\x29]+?(_Bool|)[[:space:]]*?pollin=true[^\x28\x29]+?)&([^\x28\x29]+?(_Bool|)[[:space:]]*?pollhup=false[^\x28\x29]+?))[[:space:]]+?\)[[:space:]]+?revents=\((([^\x28\x29]+?(_Bool|)[[:space:]]*?pollin=true[^\x28\x29]+?)&([^\x28\x29]+?(_Bool|)[[:space:]]*?pollhup=true[^\x28\x29]+?))\)[[:space:]]+?\)[[:space:]]+?)+?[[:space:]]+?\)[[:space:]]+?\)[[:space:]]+?OK'
)
(
name='associative_type_array1'
typeset -r -a script=(
$'builtin poll\n'
- $'typeset -T p_t=( typeset -l -i fd ; \n'
+ $'typeset -T p_t=( typeset fd=-1 ; \n' # fixme: This should be "integer fd=-1" but ast-ksh.2013-09-13 crashes
# fixme: In theory we only have to list the events we want
# in the compound variable "events" ... and the same events
# plus pollerr, pollnval and pollup in "revents" (since
@@ -173,8 +154,8 @@
# which triggers fatal errors in case we try to read a
# non-existing type variable member - see
# http://marc.info/?l=ast-developers&m=134526131905059&w=2
- $' compound events=( typeset pollin=false pollpri=false pollout=false pollrdnorm=false pollwrnorm=false pollrdband=false pollwrband=false pollmsg=false pollremove=false pollrdhup=false pollerr=false pollhup=false pollnval=false ; )\n'
- $' compound revents=( typeset pollin=false pollpri=false pollout=false pollrdnorm=false pollwrnorm=false pollrdband=false pollwrband=false pollmsg=false pollremove=false pollrdhup=false pollerr=false pollhup=false pollnval=false ; )\n'
+ $' compound events=( bool pollin=false pollpri=false pollout=false pollrdnorm=false pollwrnorm=false pollrdband=false pollwrband=false pollmsg=false pollremove=false pollrdhup=false pollerr=false pollhup=false pollnval=false ; )\n'
+ $' compound revents=( bool pollin=false pollpri=false pollout=false pollrdnorm=false pollwrnorm=false pollrdband=false pollwrband=false pollmsg=false pollremove=false pollrdhup=false pollerr=false pollhup=false pollnval=false ; )\n'
$' function pinit { _.fd=$1 ; _.events.pollin=true ; } ;\n'
$')\n'
$'compound c ; p_t -A c.pl\n'
@@ -190,7 +171,7 @@
$'print -v c\n'
$'print "OK"\n'
)
- expected_output_pattern='~(Xlr)\([[:space:]]+?p_t[[:space:]]+?-A[[:space:]]+?pl=\([[:space:]]+?([[:space:]]+?\[[[:alnum:]]+\]=\([[:space:]]+?typeset[[:space:]]+?-l[[:space:]]+?-i[[:space:]]+?fd=0[[:space:]]+?events=\((([^\x28\x29]+?pollin=true[^\x28\x29]+?)&([^\x28\x29]+?pollhup=false[^\x28\x29]+?))[[:space:]]+?\)[[:space:]]+?revents=\((([^\x28\x29]+?pollin=true[^\x28\x29]+?)&([^\x28\x29]+?pollhup=true[^\x28\x29]+?))\)[[:space:]]+?\)[[:space:]]+?)+?[[:space:]]+?\)[[:space:]]+?\)[[:space:]]+?OK'
+ expected_output_pattern='~(Xlr)\([[:space:]]+?p_t[[:space:]]+?-A[[:space:]]+?pl=\([[:space:]]+?([[:space:]]+?\[[[:alnum:]]+\]=\(([[:space:]]+?typeset[[:space:]]+?-l[[:space:]]+?-i)*?[[:space:]]+?fd=0[[:space:]]+?events=\((([^\x28\x29]+?(_Bool|)[[:space:]]*?pollin=true[^\x28\x29]+?)&([^\x28\x29]+?(_Bool|)[[:space:]]*?pollhup=false[^\x28\x29]+?))[[:space:]]+?\)[[:space:]]+?revents=\((([^\x28\x29]+?(_Bool|)[[:space:]]*?pollin=true[^\x28\x29]+?)&([^\x28\x29]+?(_Bool|)[[:space:]]*?pollhup=true[^\x28\x29]+?))\)[[:space:]]+?\)[[:space:]]+?)+?[[:space:]]+?\)[[:space:]]+?\)[[:space:]]+?OK'
)
)

@@ -219,17 +200,16 @@
integer i
typeset testname
cat >'poll_circus.sh' <<EOF
+# fixme: add com.kornshell.tests.builtin_poll.fifo_circus1 namespace
+# namespaces unfortunately don't work with "shcomp" from ast-ksh.2013-09-13
typeset -T circus_t=(
typeset fifo_name
- integer in_fd
- integer out_fd
+ integer in_fd=-1
+ integer out_fd=-1

function fifo_init
{
integer pid
- # fixme: we can't assign fd directly because ast-ksh.2012-08-13 has a bug
- # with "redirect"
- integer fd

_.fifo_name="\$1"
rm -f "\${_.fifo_name}"
@@ -241,14 +221,12 @@
{ redirect {dummy}<"\${_.fifo_name}" ; for (( ;; )) ; do sleep 15 ; done ; } &
(( pid=\$! ))

- redirect {fd}>"\${_.fifo_name}"
- (( _.out_fd=fd ))
+ redirect {_.out_fd}>"\${_.fifo_name}"
#printf '%s: outfd=%d\n' "\${_.fifo_name}" _.out_fd

kill \$pid ; wait \$pid 2>'/dev/null'

- redirect {fd}<"\${_.fifo_name}"
- (( _.in_fd=fd ))
+ redirect {_.in_fd}<"\${_.fifo_name}"
#printf '%s: infd=%d\n' "\${_.fifo_name}" _.in_fd

return 0
@@ -278,9 +256,9 @@
compound -A pollfd
for name in "\${!ar[@]}" ; do
subname="fifo_\${name}_in"
- pollfd[\${subname}]=( fd=\${ar[\${name}].in_fd} events=( pollin='true' pollerr='false' pollhup='false' pollnval='false' ) revents=() )
+ pollfd[\${subname}]=( integer fd=\${ar[\${name}].in_fd} ; compound events=( bool pollin='true' pollerr='false' pollhup='false' pollnval='false' ) revents=() )
subname="fifo_\${name}_out"
- pollfd[\${subname}]=( fd=\${ar[\${name}].out_fd} events=( pollout='true' pollerr='false' pollhup='false' pollnval='false' ) revents=() )
+ pollfd[\${subname}]=( integer fd=\${ar[\${name}].out_fd} ; compound events=( bool pollout='true' pollerr='false' pollhup='false' pollnval='false' ) revents=() )
done

# main event loop
@@ -293,36 +271,36 @@
up="\$name"

subname="fifo_\${name}_in"
- if \${pollfd[\${subname}].revents.pollin} ; then printf '%sI+' "\${up}" ; else printf '...' ; fi
- if \${pollfd[\${subname}].revents.pollhup} ; then printf '%sIH' "\${up}" ; else printf '...' ; fi
- if \${pollfd[\${subname}].revents.pollerr} ; then printf '%sIE' "\${up}" ; else printf '...' ; fi
- if \${pollfd[\${subname}].revents.pollnval} ; then printf '%sIN' "\${up}" ; else printf '...' ; fi
+ if (( pollfd[\${subname}].revents.pollin )) ; then printf '%sI+' "\${up}" ; else printf '...' ; fi
+ if (( pollfd[\${subname}].revents.pollhup )) ; then printf '%sIH' "\${up}" ; else printf '...' ; fi
+ if (( pollfd[\${subname}].revents.pollerr )) ; then printf '%sIE' "\${up}" ; else printf '...' ; fi
+ if (( pollfd[\${subname}].revents.pollnval )) ; then printf '%sIN' "\${up}" ; else printf '...' ; fi
subname="fifo_\${name}_out"
- if \${pollfd[\${subname}].revents.pollout} ; then printf '%sO+' "\${up}" ; else printf '...' ; fi
- if \${pollfd[\${subname}].revents.pollhup} ; then printf '%sOH' "\${up}" ; else printf '...' ; fi
- if \${pollfd[\${subname}].revents.pollerr} ; then printf '%sOE' "\${up}" ; else printf '...' ; fi
- if \${pollfd[\${subname}].revents.pollnval} ; then printf '%sON' "\${up}" ; else printf '...' ; fi
+ if (( pollfd[\${subname}].revents.pollout )) ; then printf '%sO+' "\${up}" ; else printf '...' ; fi
+ if (( pollfd[\${subname}].revents.pollhup )) ; then printf '%sOH' "\${up}" ; else printf '...' ; fi
+ if (( pollfd[\${subname}].revents.pollerr )) ; then printf '%sOE' "\${up}" ; else printf '...' ; fi
+ if (( pollfd[\${subname}].revents.pollnval )) ; then printf '%sON' "\${up}" ; else printf '...' ; fi
printf '|'
done
printf '\n'

# pass token around
- if \${pollfd[fifo_a_in].revents.pollin} && \${pollfd[fifo_b_out].revents.pollout}; then
+ if (( pollfd[fifo_a_in].revents.pollin && pollfd[fifo_b_out].revents.pollout )) ; then
if read -u\${pollfd[fifo_a_in].fd} -N1 x ; then
print -u\${pollfd[fifo_b_out].fd} -f "%s" "\$x" 2>'/dev/null'
fi
fi
- if \${pollfd[fifo_b_in].revents.pollin} && \${pollfd[fifo_c_out].revents.pollout}; then
+ if (( pollfd[fifo_b_in].revents.pollin && pollfd[fifo_c_out].revents.pollout )) ; then
if read -u\${pollfd[fifo_b_in].fd} -N1 x ; then
print -u\${pollfd[fifo_c_out].fd} -f "%s" "\$x" 2>'/dev/null'
fi
fi
- if \${pollfd[fifo_c_in].revents.pollin} && \${pollfd[fifo_d_out].revents.pollout}; then
+ if (( pollfd[fifo_c_in].revents.pollin && pollfd[fifo_d_out].revents.pollout )) ; then
if read -u\${pollfd[fifo_c_in].fd} -N1 x ; then
print -u\${pollfd[fifo_d_out].fd} -f "%s" "\$x" 2>'/dev/null'
fi
fi
- if \${pollfd[fifo_d_in].revents.pollin} && \${pollfd[fifo_a_out].revents.pollout}; then
+ if (( pollfd[fifo_d_in].revents.pollin && pollfd[fifo_a_out].revents.pollout )) ; then
if read -u\${pollfd[fifo_d_in].fd} -N1 x ; then
print -u\${pollfd[fifo_a_out].fd} -f "%s" "\$x" 2>'/dev/null'
fi
@@ -331,19 +309,19 @@
# send HUP around
# we explicitly do NOT close the file descriptors here
# to force poll(1) to set revents.pollnval=true
- if \${pollfd[fifo_a_in].revents.pollhup} ; then
+ if (( pollfd[fifo_a_in].revents.pollhup )) ; then
redirect {pollfd[fifo_a_in].fd}<&-;
redirect {pollfd[fifo_b_out].fd}<&-;
fi
- if \${pollfd[fifo_b_in].revents.pollhup} ; then
+ if (( pollfd[fifo_b_in].revents.pollhup )) ; then
redirect {pollfd[fifo_b_in].fd}<&-;
redirect {pollfd[fifo_c_out].fd}<&-;
fi
- if \${pollfd[fifo_c_in].revents.pollhup} ; then
+ if (( pollfd[fifo_c_in].revents.pollhup )) ; then
redirect {pollfd[fifo_c_in].fd}<&-;
redirect {pollfd[fifo_d_out].fd}<&-;
fi
- if \${pollfd[fifo_d_in].revents.pollhup} ; then
+ if (( pollfd[fifo_d_in].revents.pollhup )) ; then
redirect {pollfd[fifo_d_in].fd}<&-;
redirect {pollfd[fifo_a_out].fd}<&-;
fi
@@ -357,23 +335,26 @@
# - real applications may just use something like
# \$ unset pollfd[fifo_a_in] # to remove the whole
# array node
- \${pollfd[fifo_a_in].revents.pollnval} && (( pollfd[fifo_a_in].fd=-1 ))
- \${pollfd[fifo_a_out].revents.pollnval} && (( pollfd[fifo_a_out].fd=-1 ))
- \${pollfd[fifo_b_in].revents.pollnval} && (( pollfd[fifo_b_in].fd=-1 ))
- \${pollfd[fifo_b_out].revents.pollnval} && (( pollfd[fifo_b_out].fd=-1 ))
- \${pollfd[fifo_c_in].revents.pollnval} && (( pollfd[fifo_c_in].fd=-1 ))
- \${pollfd[fifo_c_out].revents.pollnval} && (( pollfd[fifo_c_out].fd=-1 ))
- \${pollfd[fifo_d_in].revents.pollnval} && (( pollfd[fifo_d_in].fd=-1 ))
- \${pollfd[fifo_d_out].revents.pollnval} && (( pollfd[fifo_d_out].fd=-1 ))
+ (( pollfd[fifo_a_in].revents.pollnval && (pollfd[fifo_a_in].fd=-1) ))
+ (( pollfd[fifo_a_out].revents.pollnval && (pollfd[fifo_a_out].fd=-1) ))
+ (( pollfd[fifo_b_in].revents.pollnval && (pollfd[fifo_b_in].fd=-1) ))
+ (( pollfd[fifo_b_out].revents.pollnval && (pollfd[fifo_b_out].fd=-1) ))
+ (( pollfd[fifo_c_in].revents.pollnval && (pollfd[fifo_c_in].fd=-1) ))
+ (( pollfd[fifo_c_out].revents.pollnval && (pollfd[fifo_c_out].fd=-1) ))
+ (( pollfd[fifo_d_in].revents.pollnval && (pollfd[fifo_d_in].fd=-1) ))
+ (( pollfd[fifo_d_out].revents.pollnval && (pollfd[fifo_d_out].fd=-1) ))

# send start token
if (( i==0 )) ; then
# Use the Euro symbol (\u[20ac]) if the locale
- # uses a UTF-8 encoding
- typeset -r utf8_euro_char1=\$'\u[20ac]'
- typeset -r utf8_euro_char2=\$'\342\202\254'
- if (( (\${#utf8_euro_char1} == 1) && (\${#utf8_euro_char2} == 1) )) ; then
- print -u\${pollfd[fifo_a_out].fd} -f '\u[20ac]'
+ # supports it.
+ # \$'\u[20ac-]' (note the trailing '-') returns an
+ # empty string if the unicode codepoint 0x20ac
+ # cannot be represented in the current locle
+ if [[ \$'\u[20ac-]' != '' ]] ; then
+ [[ "\${ wc -C <<<\$'\u[20ac-]' ;}" == ~(Er)[[:space:]]+2 ]] || \
+ print -u2 'ASSERT: Unicode 0x20ac is not a character'
+ print -u\${pollfd[fifo_a_out].fd} -f \$'\u[20ac]'
else
print -u\${pollfd[fifo_a_out].fd} -f 'X'
fi
@@ -398,6 +379,7 @@
builtin mkfifo
builtin poll
builtin rm
+builtin wc

main
exit $?
@@ -445,6 +427,7 @@

# run tests
builtin poll || { err_exit 'poll builtin not found.'; exit 1; }
+builtin rm || { err_exit 'rm builtin not found.'; exit 1; }
builtin rmdir || { err_exit 'rmdir builtin not found.'; exit 1; }

test1
Loading...