Commit | Line | Data |
---|---|---|
959f3c4c JH |
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 | |
0065f4af | 4 | ?RCS: |
65a32477 | 5 | ?RCS: You may redistribute only under the terms of the Artistic License, |
959f3c4c JH |
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 | |
65a32477 | 8 | ?RCS: that same Artistic License; a copy of which may be found at the root |
959f3c4c JH |
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: | |
2cb64bf6 | 24 | ?MAKE:o_nonblock eagain rd_nodata d_eofnblk: cat rm_try Compile run \ |
37a56d0d | 25 | d_open3 h_sysfile h_fcntl signal_t hint Oldconfig Setvar \ |
70bf069f | 26 | startsh i_unistd i_fcntl i_stdlib d_fork d_pipe d_alarm |
959f3c4c JH |
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:. | |
959f3c4c | 76 | ?T:status |
41322e17 | 77 | ?F:!try.out !try.ret !try.err !try !mtry |
959f3c4c JH |
78 | ?LINT:use d_open3 |
79 | : check for non-blocking I/O stuff | |
80 | case "$h_sysfile" in | |
cede5cd9 JH |
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 | ;; | |
959f3c4c JH |
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 | |
e8970d08 | 94 | $cat >>try.c <<EOCP |
37a56d0d | 95 | #include <stdio.h> |
1273bb5e JH |
96 | #$i_stdlib I_STDLIB |
97 | #ifdef I_STDLIB | |
d0abe53c | 98 | #include <stdlib.h> |
1273bb5e | 99 | #endif |
8411e286 JH |
100 | #$i_fcntl I_FCNTL |
101 | #ifdef I_FCNTL | |
102 | #include <fcntl.h> | |
103 | #endif | |
959f3c4c JH |
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 | |
8411e286 | 114 | ?X: the FNDELAY symbol, used in 4.3BSD (source: Paul Marquess). |
959f3c4c JH |
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 | |
0f00356b | 124 | o_nonblock=`$run ./try` |
959f3c4c JH |
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 | |
2cb64bf6 | 135 | $rm_try |
959f3c4c JH |
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 | '') | |
62f5a14f MBT |
141 | case "$d_fork:$d_pipe:$d_alarm" in |
142 | define:define:define) | |
959f3c4c JH |
143 | $cat head.c > try.c |
144 | $cat >>try.c <<EOCP | |
145 | #include <errno.h> | |
146 | #include <sys/types.h> | |
147 | #include <signal.h> | |
2cb64bf6 | 148 | #include <stdio.h> |
1273bb5e JH |
149 | #$i_stdlib I_STDLIB |
150 | #ifdef I_STDLIB | |
151 | #include <stdlib.h> | |
152 | #endif | |
80a8aa8f JH |
153 | #$i_fcntl I_FCNTL |
154 | #ifdef I_FCNTL | |
155 | #include <fcntl.h> | |
156 | #endif | |
959f3c4c JH |
157 | #define MY_O_NONBLOCK $o_nonblock |
158 | #ifndef errno /* XXX need better Configure test */ | |
159 | extern int errno; | |
160 | #endif | |
b8fb7a32 JH |
161 | #$i_unistd I_UNISTD |
162 | #ifdef I_UNISTD | |
37a56d0d JH |
163 | #include <unistd.h> |
164 | #endif | |
37a56d0d | 165 | #include <string.h> |
dc952a08 | 166 | $signal_t blech(int x) { exit(3); } |
959f3c4c JH |
167 | EOCP |
168 | $cat >> try.c <<'EOCP' | |
169 | int main() | |
170 | { | |
171 | int pd[2]; | |
172 | int pu[2]; | |
173 | char buf[1]; | |
174 | char string[100]; | |
f29bc7d4 | 175 | int ret; |
959f3c4c | 176 | |
f29bc7d4 MBT |
177 | ret = pipe(pd); /* Down: child -> parent */ |
178 | if (ret != 0) | |
179 | exit(3); | |
180 | ret = pipe(pu); /* Up: parent -> child */ | |
181 | if (ret != 0) | |
182 | exit(3); | |
959f3c4c | 183 | if (0 != fork()) { |
959f3c4c JH |
184 | close(pd[1]); /* Parent reads from pd[0] */ |
185 | close(pu[0]); /* Parent writes (blocking) to pu[1] */ | |
cede5cd9 | 186 | #ifdef F_SETFL |
959f3c4c JH |
187 | if (-1 == fcntl(pd[0], F_SETFL, MY_O_NONBLOCK)) |
188 | exit(1); | |
cede5cd9 JH |
189 | #else |
190 | exit(4); | |
191 | #endif | |
959f3c4c JH |
192 | signal(SIGALRM, blech); |
193 | alarm(5); | |
194 | if ((ret = read(pd[0], buf, 1)) > 0) /* Nothing to read! */ | |
195 | exit(2); | |
196 | sprintf(string, "%d\n", ret); | |
f29bc7d4 MBT |
197 | ret = write(2, string, strlen(string)); |
198 | if (ret != strlen(string)) | |
199 | exit(3); | |
959f3c4c JH |
200 | alarm(0); |
201 | #ifdef EAGAIN | |
202 | if (errno == EAGAIN) { | |
203 | printf("EAGAIN\n"); | |
204 | goto ok; | |
205 | } | |
206 | #endif | |
207 | #ifdef EWOULDBLOCK | |
208 | if (errno == EWOULDBLOCK) | |
209 | printf("EWOULDBLOCK\n"); | |
210 | #endif | |
211 | ok: | |
f29bc7d4 MBT |
212 | ret = write(pu[1], buf, 1); /* Unblocks child, tell it to close our pipe */ |
213 | if (ret != 1) | |
214 | exit(3); | |
959f3c4c JH |
215 | sleep(2); /* Give it time to close our pipe */ |
216 | alarm(5); | |
217 | ret = read(pd[0], buf, 1); /* Should read EOF */ | |
218 | alarm(0); | |
219 | sprintf(string, "%d\n", ret); | |
f29bc7d4 MBT |
220 | ret = write(4, string, strlen(string)); |
221 | if (ret != strlen(string)) | |
222 | exit(3); | |
959f3c4c JH |
223 | exit(0); |
224 | } | |
225 | ||
226 | close(pd[0]); /* We write to pd[1] */ | |
227 | close(pu[1]); /* We read from pu[0] */ | |
f29bc7d4 MBT |
228 | ret = read(pu[0], buf, 1); /* Wait for parent to signal us we may continue */ |
229 | if (ret != 1) | |
230 | exit(3); | |
959f3c4c JH |
231 | close(pd[1]); /* Pipe pd is now fully closed! */ |
232 | exit(0); /* Bye bye, thank you for playing! */ | |
233 | } | |
234 | EOCP | |
235 | set try | |
236 | if eval $compile_ok; then | |
237 | ?X: Use script to avoid the possible 'alarm call' message | |
238 | echo "$startsh" >mtry | |
26470d78 | 239 | echo "$run ./try >try.out 2>try.ret 4>try.err || exit 4" >>mtry |
959f3c4c | 240 | chmod +x mtry |
9c11722e | 241 | $run ./mtry >/dev/null 2>&1 |
959f3c4c JH |
242 | case $? in |
243 | 0) eagain=`$cat try.out`;; | |
244 | 1) echo "Could not perform non-blocking setting!";; | |
245 | 2) echo "I did a successful read() for something that was not there!";; | |
246 | 3) echo "Hmm... non-blocking I/O does not seem to be working!";; | |
cede5cd9 | 247 | 4) echo "Could not find F_SETFL!";; |
959f3c4c JH |
248 | *) echo "Something terribly wrong happened during testing.";; |
249 | esac | |
250 | rd_nodata=`$cat try.ret` | |
251 | echo "A read() system call with no data present returns $rd_nodata." | |
252 | case "$rd_nodata" in | |
253 | 0|-1) ;; | |
254 | *) | |
255 | echo "(That's peculiar, fixing that to be -1.)" | |
256 | rd_nodata=-1 | |
257 | ;; | |
258 | esac | |
259 | case "$eagain" in | |
260 | '') | |
261 | echo "Forcing errno EAGAIN on read() with no data available." | |
262 | eagain=EAGAIN | |
263 | ;; | |
264 | *) | |
265 | echo "Your read() sets errno to $eagain when no data is available." | |
266 | ;; | |
267 | esac | |
268 | status=`$cat try.err` | |
269 | case "$status" in | |
270 | 0) echo "And it correctly returns 0 to signal EOF.";; | |
271 | -1) echo "But it also returns -1 to signal EOF, so be careful!";; | |
272 | *) echo "However, your read() returns '$status' on EOF??";; | |
273 | esac | |
274 | val="$define" | |
275 | if test "$status" = "$rd_nodata"; then | |
276 | echo "WARNING: you can't distinguish between EOF and no data!" | |
277 | val="$undef" | |
278 | fi | |
279 | else | |
280 | echo "I can't compile the test program--assuming errno EAGAIN will do." | |
281 | eagain=EAGAIN | |
282 | fi | |
9b269d84 JH |
283 | ;; |
284 | *) echo "Can't figure out how to test this--assuming errno EAGAIN will do." | |
285 | eagain=EAGAIN | |
286 | val="$define" | |
287 | ;; | |
288 | esac | |
959f3c4c JH |
289 | set d_eofnblk |
290 | eval $setvar | |
291 | ;; | |
292 | *) | |
293 | echo "Using $hint value $eagain." | |
294 | echo "Your read() returns $rd_nodata when no data is present." | |
295 | case "$d_eofnblk" in | |
296 | "$define") echo "And you can see EOF because read() returns 0.";; | |
297 | "$undef") echo "But you can't see EOF status from read() returned value.";; | |
298 | *) | |
299 | ?X: Should not happen, but if it does, assume the worst! | |
300 | echo "(Assuming you can't see EOF status from read anyway.)" | |
301 | d_eofnblk=$undef | |
302 | ;; | |
303 | esac | |
304 | ;; | |
305 | esac | |
2cb64bf6 | 306 | $rm_try head.c mtry |
959f3c4c | 307 |