| 1 | ?RCS: $Id: nblock_io.U,v 3.0.1.2 1997/02/28 16:17:14 ram Exp $ |
| 2 | ?RCS: |
| 3 | ?RCS: Copyright (c) 1991-1993, Raphael Manfredi |
| 4 | ?RCS: |
| 5 | ?RCS: You may redistribute only under the terms of the Artistic License, |
| 6 | ?RCS: as specified in the README file that comes with the distribution. |
| 7 | ?RCS: You may reuse parts of this distribution only within the terms of |
| 8 | ?RCS: that same Artistic License; a copy of which may be found at the root |
| 9 | ?RCS: of the source tree for dist 3.0. |
| 10 | ?RCS: |
| 11 | ?RCS: $Log: nblock_io.U,v $ |
| 12 | ?RCS: Revision 3.0.1.2 1997/02/28 16:17:14 ram |
| 13 | ?RCS: patch61: simplify here document for shells that can't handle them well |
| 14 | ?RCS: patch61: force use of "startsh" at the head of the generated script |
| 15 | ?RCS: patch61: added new files to the ?F: metalint hint |
| 16 | ?RCS: |
| 17 | ?RCS: Revision 3.0.1.1 1995/07/25 14:13:22 ram |
| 18 | ?RCS: patch56: created |
| 19 | ?RCS: |
| 20 | ?X: |
| 21 | ?X: Simplify here document for shells that can't handle them well. |
| 22 | ?X: (Problem reported on FreeBSD; it's unclear if this helps.) --AD |
| 23 | ?X: |
| 24 | ?MAKE:o_nonblock eagain rd_nodata d_eofnblk: cat rm_try Compile run \ |
| 25 | d_open3 h_sysfile h_fcntl signal_t hint Oldconfig Setvar \ |
| 26 | startsh i_unistd i_string i_fcntl i_stdlib d_fork d_pipe |
| 27 | ?MAKE: -pick add $@ %< |
| 28 | ?S:o_nonblock: |
| 29 | ?S: This variable bears the symbol value to be used during open() or fcntl() |
| 30 | ?S: to turn on non-blocking I/O for a file descriptor. If you wish to switch |
| 31 | ?S: between blocking and non-blocking, you may try ioctl(FIOSNBIO) instead, |
| 32 | ?S: but that is only supported by some devices. |
| 33 | ?S:. |
| 34 | ?S:eagain: |
| 35 | ?S: This variable bears the symbolic errno code set by read() when no |
| 36 | ?S: data is present on the file and non-blocking I/O was enabled (otherwise, |
| 37 | ?S: read() blocks naturally). |
| 38 | ?S:. |
| 39 | ?S:rd_nodata: |
| 40 | ?S: This variable holds the return code from read() when no data is |
| 41 | ?S: present. It should be -1, but some systems return 0 when O_NDELAY is |
| 42 | ?S: used, which is a shame because you cannot make the difference between |
| 43 | ?S: no data and an EOF.. Sigh! |
| 44 | ?S:. |
| 45 | ?S:d_eofnblk: |
| 46 | ?S: This variable conditionally defines EOF_NONBLOCK if EOF can be seen |
| 47 | ?S: when reading from a non-blocking I/O source. |
| 48 | ?S:. |
| 49 | ?C:VAL_O_NONBLOCK: |
| 50 | ?C: This symbol is to be used during open() or fcntl(F_SETFL) to turn on |
| 51 | ?C: non-blocking I/O for the file descriptor. Note that there is no way |
| 52 | ?C: back, i.e. you cannot turn it blocking again this way. If you wish to |
| 53 | ?C: alternatively switch between blocking and non-blocking, use the |
| 54 | ?C: ioctl(FIOSNBIO) call instead, but that is not supported by all devices. |
| 55 | ?C:. |
| 56 | ?C:VAL_EAGAIN: |
| 57 | ?C: This symbol holds the errno error code set by read() when no data was |
| 58 | ?C: present on the non-blocking file descriptor. |
| 59 | ?C:. |
| 60 | ?C:RD_NODATA: |
| 61 | ?C: This symbol holds the return code from read() when no data is present |
| 62 | ?C: on the non-blocking file descriptor. Be careful! If EOF_NONBLOCK is |
| 63 | ?C: not defined, then you can't distinguish between no data and EOF by |
| 64 | ?C: issuing a read(). You'll have to find another way to tell for sure! |
| 65 | ?C:. |
| 66 | ?C:EOF_NONBLOCK: |
| 67 | ?C: This symbol, if defined, indicates to the C program that a read() on |
| 68 | ?C: a non-blocking file descriptor will return 0 on EOF, and not the value |
| 69 | ?C: held in RD_NODATA (-1 usually, in that case!). |
| 70 | ?C:. |
| 71 | ?H:#define VAL_O_NONBLOCK $o_nonblock |
| 72 | ?H:#define VAL_EAGAIN $eagain |
| 73 | ?H:#define RD_NODATA $rd_nodata |
| 74 | ?H:#$d_eofnblk EOF_NONBLOCK |
| 75 | ?H:. |
| 76 | ?T:status |
| 77 | ?F:!try.out !try.ret !try.err !try !mtry |
| 78 | ?LINT:use d_open3 |
| 79 | : check for non-blocking I/O stuff |
| 80 | case "$h_sysfile" in |
| 81 | true) echo "#include <sys/file.h>" > head.c;; |
| 82 | *) |
| 83 | case "$h_fcntl" in |
| 84 | true) echo "#include <fcntl.h>" > head.c;; |
| 85 | *) echo "#include <sys/fcntl.h>" > head.c;; |
| 86 | esac |
| 87 | ;; |
| 88 | esac |
| 89 | echo " " |
| 90 | echo "Figuring out the flag used by open() for non-blocking I/O..." >&4 |
| 91 | case "$o_nonblock" in |
| 92 | '') |
| 93 | $cat head.c > try.c |
| 94 | $cat >>try.c <<EOCP |
| 95 | #include <stdio.h> |
| 96 | #$i_stdlib I_STDLIB |
| 97 | #ifdef I_STDLIB |
| 98 | #include <stdlib.h> |
| 99 | #endif |
| 100 | #$i_fcntl I_FCNTL |
| 101 | #ifdef I_FCNTL |
| 102 | #include <fcntl.h> |
| 103 | #endif |
| 104 | int main() { |
| 105 | #ifdef O_NONBLOCK |
| 106 | printf("O_NONBLOCK\n"); |
| 107 | exit(0); |
| 108 | #endif |
| 109 | #ifdef O_NDELAY |
| 110 | printf("O_NDELAY\n"); |
| 111 | exit(0); |
| 112 | #endif |
| 113 | ?X: Stevens "Advanced Programming in the UNIX Environment" page 364 mentions |
| 114 | ?X: the FNDELAY symbol, used in 4.3BSD (source: Paul Marquess). |
| 115 | #ifdef FNDELAY |
| 116 | printf("FNDELAY\n"); |
| 117 | exit(0); |
| 118 | #endif |
| 119 | exit(0); |
| 120 | } |
| 121 | EOCP |
| 122 | set try |
| 123 | if eval $compile_ok; then |
| 124 | o_nonblock=`$run ./try` |
| 125 | case "$o_nonblock" in |
| 126 | '') echo "I can't figure it out, assuming O_NONBLOCK will do.";; |
| 127 | *) echo "Seems like we can use $o_nonblock.";; |
| 128 | esac |
| 129 | else |
| 130 | echo "(I can't compile the test program; pray O_NONBLOCK is right!)" |
| 131 | fi |
| 132 | ;; |
| 133 | *) echo "Using $hint value $o_nonblock.";; |
| 134 | esac |
| 135 | $rm_try |
| 136 | |
| 137 | echo " " |
| 138 | echo "Let's see what value errno gets from read() on a $o_nonblock file..." >&4 |
| 139 | case "$eagain" in |
| 140 | '') |
| 141 | case "$d_fork:$d_pipe" in |
| 142 | define:define) |
| 143 | $cat head.c > try.c |
| 144 | $cat >>try.c <<EOCP |
| 145 | #include <errno.h> |
| 146 | #include <sys/types.h> |
| 147 | #include <signal.h> |
| 148 | #include <stdio.h> |
| 149 | #$i_stdlib I_STDLIB |
| 150 | #ifdef I_STDLIB |
| 151 | #include <stdlib.h> |
| 152 | #endif |
| 153 | #$i_fcntl I_FCNTL |
| 154 | #ifdef I_FCNTL |
| 155 | #include <fcntl.h> |
| 156 | #endif |
| 157 | #define MY_O_NONBLOCK $o_nonblock |
| 158 | #ifndef errno /* XXX need better Configure test */ |
| 159 | extern int errno; |
| 160 | #endif |
| 161 | #$i_unistd I_UNISTD |
| 162 | #ifdef I_UNISTD |
| 163 | #include <unistd.h> |
| 164 | #endif |
| 165 | #$i_string I_STRING |
| 166 | #ifdef I_STRING |
| 167 | #include <string.h> |
| 168 | #else |
| 169 | #include <strings.h> |
| 170 | #endif |
| 171 | $signal_t blech(int x) { exit(3); } |
| 172 | EOCP |
| 173 | $cat >> try.c <<'EOCP' |
| 174 | int main() |
| 175 | { |
| 176 | int pd[2]; |
| 177 | int pu[2]; |
| 178 | char buf[1]; |
| 179 | char string[100]; |
| 180 | |
| 181 | pipe(pd); /* Down: child -> parent */ |
| 182 | pipe(pu); /* Up: parent -> child */ |
| 183 | if (0 != fork()) { |
| 184 | int ret; |
| 185 | close(pd[1]); /* Parent reads from pd[0] */ |
| 186 | close(pu[0]); /* Parent writes (blocking) to pu[1] */ |
| 187 | #ifdef F_SETFL |
| 188 | if (-1 == fcntl(pd[0], F_SETFL, MY_O_NONBLOCK)) |
| 189 | exit(1); |
| 190 | #else |
| 191 | exit(4); |
| 192 | #endif |
| 193 | signal(SIGALRM, blech); |
| 194 | alarm(5); |
| 195 | if ((ret = read(pd[0], buf, 1)) > 0) /* Nothing to read! */ |
| 196 | exit(2); |
| 197 | sprintf(string, "%d\n", ret); |
| 198 | write(2, string, strlen(string)); |
| 199 | alarm(0); |
| 200 | #ifdef EAGAIN |
| 201 | if (errno == EAGAIN) { |
| 202 | printf("EAGAIN\n"); |
| 203 | goto ok; |
| 204 | } |
| 205 | #endif |
| 206 | #ifdef EWOULDBLOCK |
| 207 | if (errno == EWOULDBLOCK) |
| 208 | printf("EWOULDBLOCK\n"); |
| 209 | #endif |
| 210 | ok: |
| 211 | write(pu[1], buf, 1); /* Unblocks child, tell it to close our pipe */ |
| 212 | sleep(2); /* Give it time to close our pipe */ |
| 213 | alarm(5); |
| 214 | ret = read(pd[0], buf, 1); /* Should read EOF */ |
| 215 | alarm(0); |
| 216 | sprintf(string, "%d\n", ret); |
| 217 | write(4, string, strlen(string)); |
| 218 | exit(0); |
| 219 | } |
| 220 | |
| 221 | close(pd[0]); /* We write to pd[1] */ |
| 222 | close(pu[1]); /* We read from pu[0] */ |
| 223 | read(pu[0], buf, 1); /* Wait for parent to signal us we may continue */ |
| 224 | close(pd[1]); /* Pipe pd is now fully closed! */ |
| 225 | exit(0); /* Bye bye, thank you for playing! */ |
| 226 | } |
| 227 | EOCP |
| 228 | set try |
| 229 | if eval $compile_ok; then |
| 230 | ?X: Use script to avoid the possible 'alarm call' message |
| 231 | echo "$startsh" >mtry |
| 232 | echo "$run ./try >try.out 2>try.ret 4>try.err || exit 4" >>mtry |
| 233 | chmod +x mtry |
| 234 | ./mtry >/dev/null 2>&1 |
| 235 | case $? in |
| 236 | 0) eagain=`$cat try.out`;; |
| 237 | 1) echo "Could not perform non-blocking setting!";; |
| 238 | 2) echo "I did a successful read() for something that was not there!";; |
| 239 | 3) echo "Hmm... non-blocking I/O does not seem to be working!";; |
| 240 | 4) echo "Could not find F_SETFL!";; |
| 241 | *) echo "Something terribly wrong happened during testing.";; |
| 242 | esac |
| 243 | rd_nodata=`$cat try.ret` |
| 244 | echo "A read() system call with no data present returns $rd_nodata." |
| 245 | case "$rd_nodata" in |
| 246 | 0|-1) ;; |
| 247 | *) |
| 248 | echo "(That's peculiar, fixing that to be -1.)" |
| 249 | rd_nodata=-1 |
| 250 | ;; |
| 251 | esac |
| 252 | case "$eagain" in |
| 253 | '') |
| 254 | echo "Forcing errno EAGAIN on read() with no data available." |
| 255 | eagain=EAGAIN |
| 256 | ;; |
| 257 | *) |
| 258 | echo "Your read() sets errno to $eagain when no data is available." |
| 259 | ;; |
| 260 | esac |
| 261 | status=`$cat try.err` |
| 262 | case "$status" in |
| 263 | 0) echo "And it correctly returns 0 to signal EOF.";; |
| 264 | -1) echo "But it also returns -1 to signal EOF, so be careful!";; |
| 265 | *) echo "However, your read() returns '$status' on EOF??";; |
| 266 | esac |
| 267 | val="$define" |
| 268 | if test "$status" = "$rd_nodata"; then |
| 269 | echo "WARNING: you can't distinguish between EOF and no data!" |
| 270 | val="$undef" |
| 271 | fi |
| 272 | else |
| 273 | echo "I can't compile the test program--assuming errno EAGAIN will do." |
| 274 | eagain=EAGAIN |
| 275 | fi |
| 276 | ;; |
| 277 | *) echo "Can't figure out how to test this--assuming errno EAGAIN will do." |
| 278 | eagain=EAGAIN |
| 279 | val="$define" |
| 280 | ;; |
| 281 | esac |
| 282 | set d_eofnblk |
| 283 | eval $setvar |
| 284 | ;; |
| 285 | *) |
| 286 | echo "Using $hint value $eagain." |
| 287 | echo "Your read() returns $rd_nodata when no data is present." |
| 288 | case "$d_eofnblk" in |
| 289 | "$define") echo "And you can see EOF because read() returns 0.";; |
| 290 | "$undef") echo "But you can't see EOF status from read() returned value.";; |
| 291 | *) |
| 292 | ?X: Should not happen, but if it does, assume the worst! |
| 293 | echo "(Assuming you can't see EOF status from read anyway.)" |
| 294 | d_eofnblk=$undef |
| 295 | ;; |
| 296 | esac |
| 297 | ;; |
| 298 | esac |
| 299 | $rm_try head.c mtry |
| 300 | |