Commit | Line | Data |
---|---|---|
d8875586 MBT |
1 | ?RCS: $Id: nblock_io.U 1 2006-08-24 12:32:52Z rmanfredi $ |
2 | ?RCS: | |
3 | ?RCS: Copyright (c) 1991-1997, 2004-2006, 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 4.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 +cc +ccflags +ldflags \ | |
25 | d_open3 h_sysfile h_fcntl signal_t hint Oldconfig Setvar startsh Warn | |
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 !mtry | |
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 | if $cc $ccflags $ldflags -o try try.c >/dev/null 2>&1; then | |
113 | o_nonblock=`./try` | |
114 | case "$o_nonblock" in | |
115 | '') echo "I can't figure it out, assuming O_NONBLOCK will do.";; | |
116 | *) echo "Seems like we can use $o_nonblock.";; | |
117 | esac | |
118 | else | |
119 | echo "(I can't compile the test program; pray O_NONBLOCK is right!)" | |
120 | fi | |
121 | ;; | |
122 | *) echo "Using $hint value $o_nonblock.";; | |
123 | esac | |
124 | $rm -f try try.* .out core | |
125 | ||
126 | echo " " | |
127 | echo "Let's see what value errno gets from read() on a $o_nonblock file..." >&4 | |
128 | case "$eagain" in | |
129 | '') | |
130 | $cat head.c > try.c | |
131 | $cat >>try.c <<EOCP | |
132 | #include <errno.h> | |
133 | #include <sys/types.h> | |
134 | #include <signal.h> | |
135 | #define MY_O_NONBLOCK $o_nonblock | |
136 | extern int errno; | |
137 | $signal_t blech(x) int x; { exit(3); } | |
138 | EOCP | |
139 | $cat >> try.c <<'EOCP' | |
140 | int main() | |
141 | { | |
142 | int pd[2]; | |
143 | int pu[2]; | |
144 | char buf[1]; | |
145 | char string[100]; | |
146 | ||
147 | pipe(pd); /* Down: child -> parent */ | |
148 | pipe(pu); /* Up: parent -> child */ | |
149 | if (0 != fork()) { | |
150 | int ret; | |
151 | close(pd[1]); /* Parent reads from pd[0] */ | |
152 | close(pu[0]); /* Parent writes (blocking) to pu[1] */ | |
153 | if (-1 == fcntl(pd[0], F_SETFL, MY_O_NONBLOCK)) | |
154 | exit(1); | |
155 | signal(SIGALRM, blech); | |
156 | alarm(5); | |
157 | if ((ret = read(pd[0], buf, 1)) > 0) /* Nothing to read! */ | |
158 | exit(2); | |
159 | sprintf(string, "%d\n", ret); | |
160 | write(2, string, strlen(string)); | |
161 | alarm(0); | |
162 | #ifdef EAGAIN | |
163 | if (errno == EAGAIN) { | |
164 | printf("EAGAIN\n"); | |
165 | goto ok; | |
166 | } | |
167 | #endif | |
168 | #ifdef EWOULDBLOCK | |
169 | if (errno == EWOULDBLOCK) | |
170 | printf("EWOULDBLOCK\n"); | |
171 | #endif | |
172 | ok: | |
173 | write(pu[1], buf, 1); /* Unblocks child, tell it to close our pipe */ | |
174 | sleep(2); /* Give it time to close our pipe */ | |
175 | alarm(5); | |
176 | ret = read(pd[0], buf, 1); /* Should read EOF */ | |
177 | alarm(0); | |
178 | sprintf(string, "%d\n", ret); | |
179 | write(3, string, strlen(string)); | |
180 | exit(0); | |
181 | } | |
182 | ||
183 | close(pd[0]); /* We write to pd[1] */ | |
184 | close(pu[1]); /* We read from pu[0] */ | |
185 | read(pu[0], buf, 1); /* Wait for parent to signal us we may continue */ | |
186 | close(pd[1]); /* Pipe pd is now fully closed! */ | |
187 | exit(0); /* Bye bye, thank you for playing! */ | |
188 | } | |
189 | EOCP | |
190 | if $cc $ccflags $ldflags -o try try.c >/dev/null 2>&1; then | |
191 | ?X: Use script to avoid the possible 'alarm call' message | |
192 | echo "$startsh" >mtry | |
193 | echo "./try >try.out 2>try.ret 3>try.err || exit 4" >>mtry | |
194 | chmod +x mtry | |
195 | ./mtry >/dev/null 2>&1 | |
196 | case $? in | |
197 | 0) eagain=`$cat try.out`;; | |
198 | 1) echo "Could not perform non-blocking setting!";; | |
199 | 2) echo "I did a successful read() for something that was not there!";; | |
200 | 3) echo "Hmm... non-blocking I/O does not seem to be working!";; | |
201 | *) echo "Something terribly wrong happened during testing.";; | |
202 | esac | |
203 | rd_nodata=`$cat try.ret` | |
204 | echo "A read() system call with no data present returns $rd_nodata." | |
205 | case "$rd_nodata" in | |
206 | 0|-1) ;; | |
207 | *) | |
208 | echo "(That's peculiar, fixing that to be -1.)" | |
209 | rd_nodata=-1 | |
210 | ;; | |
211 | esac | |
212 | case "$eagain" in | |
213 | '') | |
214 | echo "Forcing errno EAGAIN on read() with no data available." | |
215 | eagain=EAGAIN | |
216 | ;; | |
217 | *) | |
218 | echo "Your read() sets errno to $eagain when no data is available." | |
219 | ;; | |
220 | esac | |
221 | status=`$cat try.err` | |
222 | case "$status" in | |
223 | 0) echo "And it correctly returns 0 to signal EOF.";; | |
224 | -1) echo "But it also returns -1 to signal EOF, so be careful!";; | |
225 | *) echo "However, your read() returns '$status' on EOF??";; | |
226 | esac | |
227 | val="$define" | |
228 | if test "$status" = "$rd_nodata"; then | |
229 | ./warn "your read() can't distinguish between EOF and no data!" | |
230 | val="$undef" | |
231 | fi | |
232 | else | |
233 | echo "I can't compile the test program--assuming errno EAGAIN will do." | |
234 | eagain=EAGAIN | |
235 | fi | |
236 | set d_eofnblk | |
237 | eval $setvar | |
238 | ;; | |
239 | *) | |
240 | echo "Using $hint value $eagain." | |
241 | echo "Your read() returns $rd_nodata when no data is present." | |
242 | case "$d_eofnblk" in | |
243 | "$define") echo "And you can see EOF because read() returns 0.";; | |
244 | "$undef") echo "But you can't see EOF status from read() returned value.";; | |
245 | *) | |
246 | ?X: Should not happen, but if it does, assume the worst! | |
247 | echo "(Assuming you can't see EOF status from read anyway.)" | |
248 | d_eofnblk=$undef | |
249 | ;; | |
250 | esac | |
251 | ;; | |
252 | esac | |
253 | $rm -f try try.* .out core head.c mtry | |
254 |