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 | |
4 | ?RCS: | |
5 | ?RCS: You may redistribute only under the terms of the Artistic Licence, | |
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 Licence; 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: | |
0f00356b | 24 | ?MAKE:o_nonblock eagain rd_nodata d_eofnblk: cat rm Compile run \ |
37a56d0d | 25 | d_open3 h_sysfile h_fcntl signal_t hint Oldconfig Setvar \ |
8411e286 | 26 | startsh i_unistd i_string i_fcntl |
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:. | |
0f00356b | 76 | ?F:!try.out !try.ret !try.err |
959f3c4c JH |
77 | ?T:status |
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> |
d0abe53c | 96 | #include <stdlib.h> |
8411e286 JH |
97 | #$i_fcntl I_FCNTL |
98 | #ifdef I_FCNTL | |
99 | #include <fcntl.h> | |
100 | #endif | |
959f3c4c JH |
101 | int main() { |
102 | #ifdef O_NONBLOCK | |
103 | printf("O_NONBLOCK\n"); | |
104 | exit(0); | |
105 | #endif | |
106 | #ifdef O_NDELAY | |
107 | printf("O_NDELAY\n"); | |
108 | exit(0); | |
109 | #endif | |
110 | ?X: Stevens "Advanced Programming in the UNIX Environment" page 364 mentions | |
8411e286 | 111 | ?X: the FNDELAY symbol, used in 4.3BSD (source: Paul Marquess). |
959f3c4c JH |
112 | #ifdef FNDELAY |
113 | printf("FNDELAY\n"); | |
114 | exit(0); | |
115 | #endif | |
116 | exit(0); | |
117 | } | |
118 | EOCP | |
119 | set try | |
120 | if eval $compile_ok; then | |
0f00356b | 121 | o_nonblock=`$run ./try` |
959f3c4c JH |
122 | case "$o_nonblock" in |
123 | '') echo "I can't figure it out, assuming O_NONBLOCK will do.";; | |
124 | *) echo "Seems like we can use $o_nonblock.";; | |
125 | esac | |
126 | else | |
127 | echo "(I can't compile the test program; pray O_NONBLOCK is right!)" | |
128 | fi | |
129 | ;; | |
130 | *) echo "Using $hint value $o_nonblock.";; | |
131 | esac | |
132 | $rm -f try try.* .out core | |
133 | ||
134 | echo " " | |
135 | echo "Let's see what value errno gets from read() on a $o_nonblock file..." >&4 | |
136 | case "$eagain" in | |
137 | '') | |
138 | $cat head.c > try.c | |
139 | $cat >>try.c <<EOCP | |
140 | #include <errno.h> | |
141 | #include <sys/types.h> | |
142 | #include <signal.h> | |
37a56d0d | 143 | #include <stdio.h> |
d0abe53c | 144 | #include <stdlib.h> |
80a8aa8f JH |
145 | #$i_fcntl I_FCNTL |
146 | #ifdef I_FCNTL | |
147 | #include <fcntl.h> | |
148 | #endif | |
959f3c4c JH |
149 | #define MY_O_NONBLOCK $o_nonblock |
150 | #ifndef errno /* XXX need better Configure test */ | |
151 | extern int errno; | |
152 | #endif | |
b8fb7a32 JH |
153 | #$i_unistd I_UNISTD |
154 | #ifdef I_UNISTD | |
37a56d0d JH |
155 | #include <unistd.h> |
156 | #endif | |
08b5bf24 JH |
157 | #$i_string I_STRING |
158 | #ifdef I_STRING | |
37a56d0d JH |
159 | #include <string.h> |
160 | #else | |
161 | #include <strings.h> | |
162 | #endif | |
959f3c4c JH |
163 | $signal_t blech(x) int x; { exit(3); } |
164 | EOCP | |
165 | $cat >> try.c <<'EOCP' | |
166 | int main() | |
167 | { | |
168 | int pd[2]; | |
169 | int pu[2]; | |
170 | char buf[1]; | |
171 | char string[100]; | |
172 | ||
173 | pipe(pd); /* Down: child -> parent */ | |
174 | pipe(pu); /* Up: parent -> child */ | |
175 | if (0 != fork()) { | |
176 | int ret; | |
177 | close(pd[1]); /* Parent reads from pd[0] */ | |
178 | close(pu[0]); /* Parent writes (blocking) to pu[1] */ | |
cede5cd9 | 179 | #ifdef F_SETFL |
959f3c4c JH |
180 | if (-1 == fcntl(pd[0], F_SETFL, MY_O_NONBLOCK)) |
181 | exit(1); | |
cede5cd9 JH |
182 | #else |
183 | exit(4); | |
184 | #endif | |
959f3c4c JH |
185 | signal(SIGALRM, blech); |
186 | alarm(5); | |
187 | if ((ret = read(pd[0], buf, 1)) > 0) /* Nothing to read! */ | |
188 | exit(2); | |
189 | sprintf(string, "%d\n", ret); | |
190 | write(2, string, strlen(string)); | |
191 | alarm(0); | |
192 | #ifdef EAGAIN | |
193 | if (errno == EAGAIN) { | |
194 | printf("EAGAIN\n"); | |
195 | goto ok; | |
196 | } | |
197 | #endif | |
198 | #ifdef EWOULDBLOCK | |
199 | if (errno == EWOULDBLOCK) | |
200 | printf("EWOULDBLOCK\n"); | |
201 | #endif | |
202 | ok: | |
203 | write(pu[1], buf, 1); /* Unblocks child, tell it to close our pipe */ | |
204 | sleep(2); /* Give it time to close our pipe */ | |
205 | alarm(5); | |
206 | ret = read(pd[0], buf, 1); /* Should read EOF */ | |
207 | alarm(0); | |
208 | sprintf(string, "%d\n", ret); | |
209 | write(3, string, strlen(string)); | |
210 | exit(0); | |
211 | } | |
212 | ||
213 | close(pd[0]); /* We write to pd[1] */ | |
214 | close(pu[1]); /* We read from pu[0] */ | |
215 | read(pu[0], buf, 1); /* Wait for parent to signal us we may continue */ | |
216 | close(pd[1]); /* Pipe pd is now fully closed! */ | |
217 | exit(0); /* Bye bye, thank you for playing! */ | |
218 | } | |
219 | EOCP | |
220 | set try | |
221 | if eval $compile_ok; then | |
222 | ?X: Use script to avoid the possible 'alarm call' message | |
223 | echo "$startsh" >mtry | |
0f00356b | 224 | echo "$run ./try >try.out 2>try.ret 3>try.err || exit 4" >>mtry |
959f3c4c JH |
225 | chmod +x mtry |
226 | ./mtry >/dev/null 2>&1 | |
227 | case $? in | |
228 | 0) eagain=`$cat try.out`;; | |
229 | 1) echo "Could not perform non-blocking setting!";; | |
230 | 2) echo "I did a successful read() for something that was not there!";; | |
231 | 3) echo "Hmm... non-blocking I/O does not seem to be working!";; | |
cede5cd9 | 232 | 4) echo "Could not find F_SETFL!";; |
959f3c4c JH |
233 | *) echo "Something terribly wrong happened during testing.";; |
234 | esac | |
235 | rd_nodata=`$cat try.ret` | |
236 | echo "A read() system call with no data present returns $rd_nodata." | |
237 | case "$rd_nodata" in | |
238 | 0|-1) ;; | |
239 | *) | |
240 | echo "(That's peculiar, fixing that to be -1.)" | |
241 | rd_nodata=-1 | |
242 | ;; | |
243 | esac | |
244 | case "$eagain" in | |
245 | '') | |
246 | echo "Forcing errno EAGAIN on read() with no data available." | |
247 | eagain=EAGAIN | |
248 | ;; | |
249 | *) | |
250 | echo "Your read() sets errno to $eagain when no data is available." | |
251 | ;; | |
252 | esac | |
253 | status=`$cat try.err` | |
254 | case "$status" in | |
255 | 0) echo "And it correctly returns 0 to signal EOF.";; | |
256 | -1) echo "But it also returns -1 to signal EOF, so be careful!";; | |
257 | *) echo "However, your read() returns '$status' on EOF??";; | |
258 | esac | |
259 | val="$define" | |
260 | if test "$status" = "$rd_nodata"; then | |
261 | echo "WARNING: you can't distinguish between EOF and no data!" | |
262 | val="$undef" | |
263 | fi | |
264 | else | |
265 | echo "I can't compile the test program--assuming errno EAGAIN will do." | |
266 | eagain=EAGAIN | |
267 | fi | |
268 | set d_eofnblk | |
269 | eval $setvar | |
270 | ;; | |
271 | *) | |
272 | echo "Using $hint value $eagain." | |
273 | echo "Your read() returns $rd_nodata when no data is present." | |
274 | case "$d_eofnblk" in | |
275 | "$define") echo "And you can see EOF because read() returns 0.";; | |
276 | "$undef") echo "But you can't see EOF status from read() returned value.";; | |
277 | *) | |
278 | ?X: Should not happen, but if it does, assume the worst! | |
279 | echo "(Assuming you can't see EOF status from read anyway.)" | |
280 | d_eofnblk=$undef | |
281 | ;; | |
282 | esac | |
283 | ;; | |
284 | esac | |
285 | $rm -f try try.* .out core head.c mtry | |
286 |