1 /***********************************************************************
3 * This software is part of the ast package *
4 * Copyright (c) 1982-2009 AT&T Intellectual Property *
5 * and is licensed under the *
6 * Common Public License, Version 1.0 *
7 * by AT&T Intellectual Property *
9 * A copy of the License is available at *
10 * http://www.opensource.org/licenses/cpl1.0.txt *
11 * (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) *
13 * Information and Software Systems Research *
17 * Roland Mainz <roland.mainz@nrubsig.org> *
19 ***********************************************************************/
31 # define SH_DICT "libshell"
38 #define sh_contexttoshb(context) ((Shbltin_t*)(context))
39 #define sh_contexttoshell(context) ((context)?(sh_contexttoshb(context)->shp):(NULL))
41 static const char sh_optpoll
[] =
42 "[-?\n@(#)$Id: poll (AT&T Labs Research) 2009-05-14 $\n]"
43 "[-author?Roland Mainz <roland.mainz@nrubsig.org]"
44 "[-license?http://www.opensource.org/licenses/cpl1.0.txt]"
45 "[+NAME? poll - input/output multiplexing]"
46 "[+DESCRIPTION?The poll command provides applications with a mechanism "
47 "for multiplexing input/output over a set of file descriptors. "
48 "For each member of the array variable \bvar\b, "
49 "poll examines the given file descriptor in the subscript \b.fd\b "
50 "for the event(s) specified in the subscript \b.events\b."
51 "The poll command identifies those file descriptors on which an "
52 "application can read or write data, or on which certain events have "
54 "[+?The \bvar\b argument specifies the file descriptors to be examined "
55 "and the events of interest for each file descriptor. "
56 "It is a array of structured variables with one member for each open "
57 "file descriptor of interest. The array's members contain the following "
59 "[+?\b.fd\b # file descriptor]"
60 "[+?\b.events\b # requested events]"
61 "[+?\b.revents\b # returned event]"
63 "[+?The \bfd\b variable specifies an open file descriptor and the "
64 "\bevents\b and \brevents\b members are strings constructed from "
65 "a concaternation of the following event flags, seperated by '|':]"
67 "[+POLLIN?Data other than high priority data may be "
68 "read without blocking. For STREAMS, this "
69 "flag is set in revents even if the message "
71 "[+POLLRDNORM?Normal data (priority band equals 0) may be "
72 "read without blocking. For STREAMS, this "
73 "flag is set in revents even if the message "
75 "[+POLLRDBAND?Data from a non-zero priority band may be "
76 "read without blocking. For STREAMS, this "
77 "flag is set in revents even if the message "
79 "[+POLLPRI?High priority data may be received without "
80 "blocking. For STREAMS, this flag is set in "
81 "revents even if the message is of zero "
83 "[+POLLOUT?Normal data (priority band equals 0) may be "
84 "written without blocking.]"
85 "[+POLLWRNORM?The same as POLLOUT.]"
86 "[+POLLWRBAND?Priority data (priority band > 0) may be "
87 "written. This event only examines bands "
88 "that have been written to at least once.]"
89 "[+POLLERR?An error has occurred on the device or "
90 "stream. This flag is only valid in the "
91 "revents bitmask; it is not used in the "
93 "[+POLLHUP?A hangup has occurred on the stream. This "
94 "event and POLLOUT are mutually exclusive; a "
95 "stream can never be writable if a hangup has "
96 "occurred. However, this event and POLLIN, "
97 ", POLLRDBAND, or POLLPRI are not "
98 "mutually exclusive. This flag is only valid "
99 "in the revents bitmask; it is not used in "
100 "the events member.]"
101 "[+POLLNVAL?The specified fd value does not belong to an "
102 "open file. This flag is only valid in the "
103 "revents member; it is not used in the events "
108 "[+?If the value fd is less than 0, events is ignored and "
109 "revents is set to 0 in that entry on return from poll.]"
111 "[+?The results of the poll query are stored in the revents "
112 "member in the \bvar\b structure. POLL*-strings are set in the \brevents\b "
113 "variable to indicate which of the requested events are true. "
114 "If none are true, the \brevents\b will be an empty string when "
115 "the poll command returns. The event flags "
116 "POLLHUP, POLLERR, and POLLNVAL are always set in \brevents\b "
117 "if the conditions they indicate are true; this occurs even "
118 "though these flags were not present in events.]"
120 "[+?If none of the defined events have occurred on any selected "
121 "file descriptor, poll waits at least timeout milliseconds "
122 "for an event to occur on any of the selected file descriptors. "
123 "On a computer where millisecond timing accuracy is not "
124 "available, timeout is rounded up to the nearest legal value "
125 "available on that system. If the value timeout is 0, poll "
126 "returns immediately. If the value of timeout is -1, poll "
127 "blocks until a requested event occurs or until the call is "
130 "[+?The poll function supports regular files, terminal and "
131 "pseudo-terminal devices, STREAMS-based files, FIFOs and "
132 "pipes. The behavior of poll on elements of fds that refer "
133 "to other types of file is unspecified.]"
135 "[+?The poll function supports sockets.]"
137 "[+?A file descriptor for a socket that is listening for connections "
138 "will indicate that it is ready for reading, once connections "
139 "are available. A file descriptor for a socket that "
140 "is connecting asynchronously will indicate that it is ready "
141 "for writing, once a connection has been established.]"
143 "[+?Regular files always poll TRUE for reading and writing.]"
145 "[e:eventarray]:[fdcount?Upon successful completion, an indexed array "
146 "of strings is returned which contains a list of array subscripts "
147 "in the poll array which received events.]"
148 "[t:timeout]:[seconds?Timeout in seconds. If the value timeout is 0, "
149 "poll returns immediately. If the value of timeout is -1, poll "
150 "blocks until a requested event occurs or until the call is "
152 "[T:mtimeout]:[milliseconds?Timeout in milliseconds. If the value timeout is 0, "
153 "poll returns immediately. If the value of timeout is -1, poll "
154 "blocks until a requested event occurs or until the call is "
161 "[+>0?An error occurred.]"
163 "[+SEE ALSO?\bopen\b(1),\btmpfile\b(1),\bdup\b(1),\bclose\b(1),\bpoll\b(2)]"
167 * |mystpcpy| - like |strcpy()| but returns the end of the buffer
169 * Copy string s2 to s1. s1 must be large enough.
170 * return s1-1 (position of string terminator ('\0') in destnation buffer).
173 char *mystpcpy(char *s1
, const char *s2
)
175 while (*s1
++ = *s2
++)
181 Namval_t
*nv_open_fmt(Dt_t
*dict
, int flags
, const char *namefmt
, ...)
183 char varnamebuff
[PATH_MAX
];
186 va_start(ap
, namefmt
);
187 vsnprintf(varnamebuff
, sizeof(varnamebuff
), namefmt
, ap
);
190 return nv_open(varnamebuff
, dict
, flags
);
194 int poll_strtoevents(const char *str
)
198 if (strstr(str
, "POLLIN")) events
|= POLLIN
;
199 if (strstr(str
, "POLLRDNORM")) events
|= POLLRDNORM
;
200 if (strstr(str
, "POLLRDBAND")) events
|= POLLRDBAND
;
201 if (strstr(str
, "POLLPRI")) events
|= POLLPRI
;
202 if (strstr(str
, "POLLOUT")) events
|= POLLOUT
;
203 if (strstr(str
, "POLLWRNORM")) events
|= POLLWRNORM
;
204 if (strstr(str
, "POLLWRBAND")) events
|= POLLWRBAND
;
205 if (strstr(str
, "POLLERR")) events
|= POLLERR
;
206 if (strstr(str
, "POLLHUP")) events
|= POLLHUP
;
207 if (strstr(str
, "POLLNVAL")) events
|= POLLNVAL
;
214 void poll_eventstostr(char *s
, int events
)
220 if (events
& POLLIN
) s
=mystpcpy(s
, "POLLIN|");
221 if (events
& POLLRDNORM
) s
=mystpcpy(s
, "POLLRDNORM|");
222 if (events
& POLLRDBAND
) s
=mystpcpy(s
, "POLLRDBAND|");
223 if (events
& POLLPRI
) s
=mystpcpy(s
, "POLLPRI|");
224 if (events
& POLLOUT
) s
=mystpcpy(s
, "POLLOUT|");
225 if (events
& POLLWRNORM
) s
=mystpcpy(s
, "POLLWRNORM|");
226 if (events
& POLLWRBAND
) s
=mystpcpy(s
, "POLLWRBAND|");
227 if (events
& POLLERR
) s
=mystpcpy(s
, "POLLERR|");
228 if (events
& POLLHUP
) s
=mystpcpy(s
, "POLLHUP|");
229 if (events
& POLLNVAL
) s
=mystpcpy(s
, "POLLNVAL|");
231 /* Remove trailling '|' */
238 #define getconf(x) strtol(astconf(x,NiL,NiL),NiL,0)
240 extern int b_poll(int argc
, char *argv
[], void *extra
)
243 Shell_t
*shp
= sh_contexttoshell(extra
);
247 nfds_t numpollfd
= 0;
250 double timeout
= -1.;
251 char buff
[PATH_MAX
*2+1]; /* enogth to hold two variable names */
252 char *eventarrayname
= NULL
;
254 while (n
= optget(argv
, sh_optpoll
)) switch (n
)
259 timeout
= strtod(opt_info
.arg
, (char **)NULL
);
261 errormsg(SH_DICT
, ERROR_system(1), "%s: invalid timeout", opt_info
.arg
);
263 /* -t uses seconds, -T milliseconds */
268 eventarrayname
= opt_info
.arg
;
271 errormsg(SH_DICT
, 2, "%s", opt_info
.arg
);
274 errormsg(SH_DICT
, ERROR_usage(2), "%s", opt_info
.arg
);
277 argc
-= opt_info
.index
;
278 argv
+= opt_info
.index
;
280 errormsg(SH_DICT
, ERROR_usage(2), optusage((char*)0));
284 Namval_t
*array_np
, *array_np_sub
;
287 array_np
= nv_open(varname
, shp
->var_tree
, NV_NOFAIL
|NV_NOADD
);
289 errormsg(SH_DICT
, ERROR_system(1), "cannot find array variable %s", varname
);
290 if(!nv_isattr(array_np
, NV_ARRAY
))
291 errormsg(SH_DICT
, ERROR_system(1), "variable %s is not an array", varname
);
293 /* Count number of array elememts. We need to do it "manually" to
294 * handle sparse indexed and associative arrays */
295 nv_putsub(array_np
, NULL
, ARRAY_SCAN
);
296 array_np_sub
= array_np
;
299 if (!(subname
=nv_getsub(array_np_sub
)))
302 } while( array_np_sub
&& nv_nextsub(array_np_sub
) );
306 * Allocate stack space via |alloca()| for gcc builds since ctfconvert
307 * is unable to handle VLAs from gcc. We need this until CR #6379193
310 struct pollfd
*pollfd
= alloca(sizeof(struct pollfd
)*(numpollfd
+1));
312 /* We must allocate one more entry with VLA with zero elements do not work with all compilers */
313 struct pollfd pollfd
[numpollfd
+1];
314 #endif /* __GNUC__ */
316 nv_putsub(array_np
, NULL
, ARRAY_SCAN
);
317 array_np_sub
= array_np
;
321 if (!(subname
=nv_getsub(array_np_sub
)))
324 np
= nv_open_fmt(shp
->var_tree
, NV_NOFAIL
|NV_NOADD
, "%s[%s].fd", varname
, subname
);
326 errormsg(SH_DICT
, ERROR_system(1), "missing pollfd %s[%s].fd", varname
, subname
);
327 fd
= (int)nv_getnum(np
);
328 if (fd
< 0 || fd
> OPEN_MAX
)
329 errormsg(SH_DICT
, ERROR_system(1), "invalid pollfd fd %d", fd
);
333 np
= nv_open_fmt(shp
->var_tree
, NV_NOFAIL
|NV_NOADD
, "%s[%s].events", varname
, subname
);
335 errormsg(SH_DICT
, ERROR_system(1), "missing pollfd %s[%s].events", varname
, subname
);
339 errormsg(SH_DICT
, ERROR_system(1), "missing pollfd events value");
340 pollfd
[i
].events
= poll_strtoevents(s
);
343 pollfd
[i
].revents
= 0;
346 } while( array_np_sub
&& nv_nextsub(array_np_sub
) );
348 n
= poll(pollfd
, numpollfd
, timeout
);
349 /* FixMe: EGAIN and EINTR may require extra handling */
351 errormsg(SH_DICT
, ERROR_system(1), "failure");
355 np
= nv_open_fmt(shp
->var_tree
, NV_VARNAME
|NV_ARRAY
|NV_NOFAIL
, "%s", eventarrayname
);
357 errormsg(SH_DICT
, ERROR_system(1), "couldn't create poll count variable %s", eventarrayname
);
361 nv_putsub(array_np
, NULL
, ARRAY_SCAN
);
362 array_np_sub
= array_np
;
366 if (!(subname
=nv_getsub(array_np_sub
)))
369 np
= nv_open_fmt(shp
->var_tree
, NV_NOFAIL
, "%s[%s].revents", varname
, subname
);
371 errormsg(SH_DICT
, ERROR_system(1), "couldn't create pollfd %s[%s].revents", varname
, subname
);
373 poll_eventstostr(buff
, pollfd
[i
].revents
);
375 nv_putval(np
, buff
, 0);
378 if (eventarrayname
&& pollfd
[i
].revents
)
380 sprintf(buff
, "%s+=( '%s' )", eventarrayname
, subname
);
385 } while( array_np_sub
&& nv_nextsub(array_np_sub
) );