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: | |
24 | ?MAKE:o_nonblock eagain rd_nodata d_eofnblk: cat rm Compile \ | |
25 | d_open3 h_sysfile h_fcntl signal_t hint Oldconfig Setvar startsh | |
26 | ?MAKE: -pick add $@ %< | |
27 | ?S:o_nonblock: | |
28 | ?S: This variable bears the symbol value to be used during open() or fcntl() | |
29 | ?S: to turn on non-blocking I/O for a file descriptor. If you wish to switch | |
30 | ?S: between blocking and non-blocking, you may try ioctl(FIOSNBIO) instead, | |
31 | ?S: but that is only supported by some devices. | |
32 | ?S:. | |
33 | ?S:eagain: | |
34 | ?S: This variable bears the symbolic errno code set by read() when no | |
35 | ?S: data is present on the file and non-blocking I/O was enabled (otherwise, | |
36 | ?S: read() blocks naturally). | |
37 | ?S:. | |
38 | ?S:rd_nodata: | |
39 | ?S: This variable holds the return code from read() when no data is | |
40 | ?S: present. It should be -1, but some systems return 0 when O_NDELAY is | |
41 | ?S: used, which is a shame because you cannot make the difference between | |
42 | ?S: no data and an EOF.. Sigh! | |
43 | ?S:. | |
44 | ?S:d_eofnblk: | |
45 | ?S: This variable conditionally defines EOF_NONBLOCK if EOF can be seen | |
46 | ?S: when reading from a non-blocking I/O source. | |
47 | ?S:. | |
48 | ?C:VAL_O_NONBLOCK: | |
49 | ?C: This symbol is to be used during open() or fcntl(F_SETFL) to turn on | |
50 | ?C: non-blocking I/O for the file descriptor. Note that there is no way | |
51 | ?C: back, i.e. you cannot turn it blocking again this way. If you wish to | |
52 | ?C: alternatively switch between blocking and non-blocking, use the | |
53 | ?C: ioctl(FIOSNBIO) call instead, but that is not supported by all devices. | |
54 | ?C:. | |
55 | ?C:VAL_EAGAIN: | |
56 | ?C: This symbol holds the errno error code set by read() when no data was | |
57 | ?C: present on the non-blocking file descriptor. | |
58 | ?C:. | |
59 | ?C:RD_NODATA: | |
60 | ?C: This symbol holds the return code from read() when no data is present | |
61 | ?C: on the non-blocking file descriptor. Be careful! If EOF_NONBLOCK is | |
62 | ?C: not defined, then you can't distinguish between no data and EOF by | |
63 | ?C: issuing a read(). You'll have to find another way to tell for sure! | |
64 | ?C:. | |
65 | ?C:EOF_NONBLOCK: | |
66 | ?C: This symbol, if defined, indicates to the C program that a read() on | |
67 | ?C: a non-blocking file descriptor will return 0 on EOF, and not the value | |
68 | ?C: held in RD_NODATA (-1 usually, in that case!). | |
69 | ?C:. | |
70 | ?H:#define VAL_O_NONBLOCK $o_nonblock | |
71 | ?H:#define VAL_EAGAIN $eagain | |
72 | ?H:#define RD_NODATA $rd_nodata | |
73 | ?H:#$d_eofnblk EOF_NONBLOCK | |
74 | ?H:. | |
75 | ?F:!try !try.out !try.ret !try.err | |
76 | ?T:status | |
77 | ?LINT:use d_open3 | |
78 | : check for non-blocking I/O stuff | |
79 | case "$h_sysfile" in | |
80 | true) echo "#include <sys/file.h>" > head.c;; | |
81 | *) | |
82 | case "$h_fcntl" in | |
83 | true) echo "#include <fcntl.h>" > head.c;; | |
84 | *) echo "#include <sys/fcntl.h>" > head.c;; | |
85 | esac | |
86 | ;; | |
87 | esac | |
88 | echo " " | |
89 | echo "Figuring out the flag used by open() for non-blocking I/O..." >&4 | |
90 | case "$o_nonblock" in | |
91 | '') | |
92 | $cat head.c > try.c | |
93 | $cat >>try.c <<'EOCP' | |
94 | int main() { | |
95 | #ifdef O_NONBLOCK | |
96 | printf("O_NONBLOCK\n"); | |
97 | exit(0); | |
98 | #endif | |
99 | #ifdef O_NDELAY | |
100 | printf("O_NDELAY\n"); | |
101 | exit(0); | |
102 | #endif | |
103 | ?X: Stevens "Advanced Programming in the UNIX Environment" page 364 mentions | |
104 | ?X: the FNDELAY symbol, used in 4.33BSD (source: Paul Marquess). | |
105 | #ifdef FNDELAY | |
106 | printf("FNDELAY\n"); | |
107 | exit(0); | |
108 | #endif | |
109 | exit(0); | |
110 | } | |
111 | EOCP | |
112 | set try | |
113 | if eval $compile_ok; then | |
114 | o_nonblock=`./try` | |
115 | case "$o_nonblock" in | |
116 | '') echo "I can't figure it out, assuming O_NONBLOCK will do.";; | |
117 | *) echo "Seems like we can use $o_nonblock.";; | |
118 | esac | |
119 | else | |
120 | echo "(I can't compile the test program; pray O_NONBLOCK is right!)" | |
121 | fi | |
122 | ;; | |
123 | *) echo "Using $hint value $o_nonblock.";; | |
124 | esac | |
125 | $rm -f try try.* .out core | |
126 | ||
127 | echo " " | |
128 | echo "Let's see what value errno gets from read() on a $o_nonblock file..." >&4 | |
129 | case "$eagain" in | |
130 | '') | |
131 | $cat head.c > try.c | |
132 | $cat >>try.c <<EOCP | |
133 | #include <errno.h> | |
134 | #include <sys/types.h> | |
135 | #include <signal.h> | |
136 | #define MY_O_NONBLOCK $o_nonblock | |
137 | #ifndef errno /* XXX need better Configure test */ | |
138 | extern int errno; | |
139 | #endif | |
140 | $signal_t blech(x) int x; { exit(3); } | |
141 | EOCP | |
142 | $cat >> try.c <<'EOCP' | |
143 | int main() | |
144 | { | |
145 | int pd[2]; | |
146 | int pu[2]; | |
147 | char buf[1]; | |
148 | char string[100]; | |
149 | ||
150 | pipe(pd); /* Down: child -> parent */ | |
151 | pipe(pu); /* Up: parent -> child */ | |
152 | if (0 != fork()) { | |
153 | int ret; | |
154 | close(pd[1]); /* Parent reads from pd[0] */ | |
155 | close(pu[0]); /* Parent writes (blocking) to pu[1] */ | |
156 | if (-1 == fcntl(pd[0], F_SETFL, MY_O_NONBLOCK)) | |
157 | exit(1); | |
158 | signal(SIGALRM, blech); | |
159 | alarm(5); | |
160 | if ((ret = read(pd[0], buf, 1)) > 0) /* Nothing to read! */ | |
161 | exit(2); | |
162 | sprintf(string, "%d\n", ret); | |
163 | write(2, string, strlen(string)); | |
164 | alarm(0); | |
165 | #ifdef EAGAIN | |
166 | if (errno == EAGAIN) { | |
167 | printf("EAGAIN\n"); | |
168 | goto ok; | |
169 | } | |
170 | #endif | |
171 | #ifdef EWOULDBLOCK | |
172 | if (errno == EWOULDBLOCK) | |
173 | printf("EWOULDBLOCK\n"); | |
174 | #endif | |
175 | ok: | |
176 | write(pu[1], buf, 1); /* Unblocks child, tell it to close our pipe */ | |
177 | sleep(2); /* Give it time to close our pipe */ | |
178 | alarm(5); | |
179 | ret = read(pd[0], buf, 1); /* Should read EOF */ | |
180 | alarm(0); | |
181 | sprintf(string, "%d\n", ret); | |
182 | write(3, string, strlen(string)); | |
183 | exit(0); | |
184 | } | |
185 | ||
186 | close(pd[0]); /* We write to pd[1] */ | |
187 | close(pu[1]); /* We read from pu[0] */ | |
188 | read(pu[0], buf, 1); /* Wait for parent to signal us we may continue */ | |
189 | close(pd[1]); /* Pipe pd is now fully closed! */ | |
190 | exit(0); /* Bye bye, thank you for playing! */ | |
191 | } | |
192 | EOCP | |
193 | set try | |
194 | if eval $compile_ok; then | |
195 | ?X: Use script to avoid the possible 'alarm call' message | |
196 | echo "$startsh" >mtry | |
197 | echo "./try >try.out 2>try.ret 3>try.err || exit 4" >>mtry | |
198 | chmod +x mtry | |
199 | ./mtry >/dev/null 2>&1 | |
200 | case $? in | |
201 | 0) eagain=`$cat try.out`;; | |
202 | 1) echo "Could not perform non-blocking setting!";; | |
203 | 2) echo "I did a successful read() for something that was not there!";; | |
204 | 3) echo "Hmm... non-blocking I/O does not seem to be working!";; | |
205 | *) echo "Something terribly wrong happened during testing.";; | |
206 | esac | |
207 | rd_nodata=`$cat try.ret` | |
208 | echo "A read() system call with no data present returns $rd_nodata." | |
209 | case "$rd_nodata" in | |
210 | 0|-1) ;; | |
211 | *) | |
212 | echo "(That's peculiar, fixing that to be -1.)" | |
213 | rd_nodata=-1 | |
214 | ;; | |
215 | esac | |
216 | case "$eagain" in | |
217 | '') | |
218 | echo "Forcing errno EAGAIN on read() with no data available." | |
219 | eagain=EAGAIN | |
220 | ;; | |
221 | *) | |
222 | echo "Your read() sets errno to $eagain when no data is available." | |
223 | ;; | |
224 | esac | |
225 | status=`$cat try.err` | |
226 | case "$status" in | |
227 | 0) echo "And it correctly returns 0 to signal EOF.";; | |
228 | -1) echo "But it also returns -1 to signal EOF, so be careful!";; | |
229 | *) echo "However, your read() returns '$status' on EOF??";; | |
230 | esac | |
231 | val="$define" | |
232 | if test "$status" = "$rd_nodata"; then | |
233 | echo "WARNING: you can't distinguish between EOF and no data!" | |
234 | val="$undef" | |
235 | fi | |
236 | else | |
237 | echo "I can't compile the test program--assuming errno EAGAIN will do." | |
238 | eagain=EAGAIN | |
239 | fi | |
240 | set d_eofnblk | |
241 | eval $setvar | |
242 | ;; | |
243 | *) | |
244 | echo "Using $hint value $eagain." | |
245 | echo "Your read() returns $rd_nodata when no data is present." | |
246 | case "$d_eofnblk" in | |
247 | "$define") echo "And you can see EOF because read() returns 0.";; | |
248 | "$undef") echo "But you can't see EOF status from read() returned value.";; | |
249 | *) | |
250 | ?X: Should not happen, but if it does, assume the worst! | |
251 | echo "(Assuming you can't see EOF status from read anyway.)" | |
252 | d_eofnblk=$undef | |
253 | ;; | |
254 | esac | |
255 | ;; | |
256 | esac | |
257 | $rm -f try try.* .out core head.c mtry | |
258 |