Fix typos; move stray paragraph to Feature Test Macros.
[glibc/history.git] / sysdeps / mach / hurd / stdio_init.c
blob535eb8cdef79bde2385496caef83b580e72cb528
1 /* Copyright (C) 1991 Free Software Foundation, Inc.
2 This file is part of the GNU C Library.
4 The GNU C Library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Library General Public License as
6 published by the Free Software Foundation; either version 2 of the
7 License, or (at your option) any later version.
9 The GNU C Library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Library General Public License for more details.
14 You should have received a copy of the GNU Library General Public
15 License along with the GNU C Library; see the file COPYING.LIB. If
16 not, write to the Free Software Foundation, Inc., 675 Mass Ave,
17 Cambridge, MA 02139, USA. */
19 #include <ansidecl.h>
20 #include <stdio.h>
21 #include <hurd.h>
22 #include <hurd/shared.h>
24 struct mapped
26 struct shared_io shared;
28 /* The rest of the shared page is owned by the user (stdio). */
30 io_t file; /* Port to the file. */
31 size_t blksize; /* Optimal size for i/o. */
32 memory_object_t cntl; /* Memory object for this page. */
33 /* Memory objects for reading and writing data.
34 These two might be the same. */
35 memory_object_t rdmemobj, wrmemobj;
39 /* Get IT. */
40 static error_t
41 #ifdef __GNUC__
42 __inline
43 #endif
44 DEFUN(get_it, (m), struct mapped *m)
46 try:
48 __spin_lock(m->shared.lock);
50 switch (m->shared.it_status)
52 case USER_POTENTIALLY_IT:
53 m->shared.it_status = USER_IT;
54 case USER_RELEASE_IT:
55 case USER_IT:
56 __spin_unlock(m->shared.lock);
57 return 0;
59 case USER_NOT_IT:
60 __spin_unlock(m->shared.lock);
62 error_t error = __io_get_it(m->file, m->cntl);
63 if (error == 0)
64 return 0;
65 else
66 /* Don't just tail-recurse because that might
67 make the function not get inlined. Sigh. */
68 goto try;
71 default:
72 __libc_fatal("get_it: Unrecognized IT status!\n");
76 /* Release IT. */
77 static error_t
78 #ifdef __GNUC__
79 __inline
80 #endif
81 DEFUN(release_it, (m), struct mapped *m)
83 __spin_lock(m->shared.lock);
84 switch (m->shared.it_status)
86 case USER_IT:
87 m->shared.it_status = USER_POTENTIALLY_IT;
88 case USER_NOT_IT:
89 __spin_unlock(m->shared.lock);
90 return 0;
92 case USER_RELEASE_IT:
93 __spin_unlock(m->shared.lock);
94 return __io_release_it(m->file, m->cntl);
96 default:
97 __libc_fatal("release_it: Unrecognized IT status!\n");
101 static int
102 DEFUN(mapped_close, (cookie), PTR cookie)
104 struct mapped *CONST m = (struct mapped *) cookie;
105 int am_it;
106 error_t error = 0;
108 __spin_lock(m->shared.lock);
109 am_it = m->shared.it_status != USER_NOT_IT;
110 __spin_unlock(m->shared.lock);
111 if (am_it)
112 error = __io_release_it(m->file, m->cntl);
114 #define DO(foo) if (error == 0) error = foo; else (void) foo
115 DO(__vm_deallocate(__mach_task_self(), m, sizeof(*m)));
116 DO(__port_deallocate(__mach_task_self(), m->file));
117 DO(__port_deallocate(__mach_task_self(), m->cntl));
118 DO(__port_deallocate(__mach_task_self(), m->rdmemobj));
119 DO(__port_deallocate(__mach_task_self(), m->wrmemobj));
120 #undef DO
122 if (error != 0)
124 errno = error;
125 return -1;
127 return 0;
130 static int
131 DEFUN(mapped_seek, (cookie, pos, whence),
132 PTR cookie AND fpos_t *pos AND int whence)
134 struct shared_io *CONST m = (struct shared_io *) cookie;
135 int error;
137 error = get_it(m);
138 if (error == 0)
140 switch (whence)
142 case SEEK_SET:
143 if (!m->seekable && *pos > m->file_pointer)
144 error = ESPIPE;
145 else
147 m->file_pointer = *pos;
148 error = 0;
150 break;
152 case SEEK_CUR:
153 if (!m->seekable && *pos < 0)
154 error = ESPIPE;
155 else
157 m->file_pointer += *pos;
158 *pos = m->file_pointer;
159 error = 0;
161 break;
163 case SEEK_END:
164 if (!m->use_file_size)
165 error = ESPIPE;
166 else
168 off_t desired = m->file_size + *pos;
169 if (!m->seekable && desired < m->file_pointer)
170 error = ESPIPE;
171 else
173 *pos = m->file_pointer = desired;
174 error = 0;
177 break;
179 default:
180 error = EINVAL;
181 break;
184 if (error == 0)
185 error = release_it(m);
186 else
187 (void) release_it(m);
190 if (error != 0)
192 errno = error;
193 return -1;
195 return 0;
198 static int
199 DEFUN(mapped_input, (stream), FILE *stream)
201 struct mapped *CONST m = (struct mapped *) cookie;
202 struct shared_io *CONST sio = &m->shared;
203 off_t pos, bufp;
204 error_t error;
205 off_t size;
207 if (error = get_it(sio))
209 __error(stream) = 1;
210 errno = error;
211 return EOF;
214 if (__buffer(stream) != NULL && m->rdmemobj == m->wrmemobj &&
215 __offset(stream) == __target(stream))
217 /* The right spot is already mapped. */
218 sio->accessed = 1; /* Tell the FS we are reading it. */
219 __get_limit(stream) = __buffer(stream) + __bufsize(stream);
220 if (!sio->written)
221 /* Make the next writing operation call mapped_output,
222 so it can set the `written' bit at the right time. */
223 __put_limit(stream) = __buffer(stream);
224 if (error = release_it(m))
225 goto release_lost;
226 __bufp(stream) = __buffer(stream);
227 return *__bufp(stream)++;
230 if (__buffer(stream) != NULL)
232 /* Remove the old mapping. */
233 size_t mapping_size = ((__get_limit(stream) > __buffer(stream) ?
234 __get_limit(stream) : __put_limit(stream)) -
235 __buffer(stream));
236 (void) __vm_deallocate(__mach_task_self(),
237 __buffer(stream), mapping_size);
238 __buffer(stream) = NULL;
241 /* We're reading, so we're not at the end-of-file. */
242 __eof(stream) = 0;
244 pos = __target(stream);
245 while (sio->use_read_size && sio->read_size < pos)
247 if (sio->use_file_size && pos >= sio->file_size)
249 /* Tried to read past the end of the file. */
250 if (sio->eof_notify)
251 __io_eofnotify(m->file);
252 if (error = release_it(sio))
253 goto release_lost;
254 __eof(stream) = 1;
255 return EOF;
258 /* Block until there is more to read. */
259 error = __io_readsleep(m->file);
260 if (error)
262 (void) release_it(m);
263 errno = error;
264 return EOF;
267 if (sio->use_read_size)
268 size = sio->read_size;
269 else if (sio->use_file_size)
270 size = sio->file_size;
271 else
272 __libc_fatal("!use_read_size && !use_file_size\n");
274 /* Round POS to a block boundary, leaving the excess in BUFP. */
275 bufp = pos % m->blksize;
276 pos -= bufp;
278 /* Decide how big a window on the file to use. */
279 size -= pos;
280 if (size > m->blksize)
281 size = m->blksize;
283 /* Map the data. */
285 vm_prot_t prot = VM_PROT_READ;
286 if (stream->__mode.__write && m->rdmemobj == m->wrmemobj)
287 prot |= VM_PROT_WRITE;
288 error = __vm_map(__mach_task_self(),
289 &__buffer(stream), size, 0, 1,
290 m->rdmemobj, pos, 0, prot, prot, VM_INHERIT_NONE);
293 if (error == 0)
294 /* Tell the FS that we have read some data. */
295 sio->accessed = 1;
297 if (error == 0)
298 (void) release_it(m);
299 else
300 error = release_it(m);
302 if (error)
304 release_lost:
305 __put_limit(stream) = __get_limit(stream) = __buffer(stream);
306 errno = error;
307 return EOF;
310 /* Set the offset to the position where our mapping begins. */
311 __offset(stream) = pos;
312 /* Set the target position to just past the end of our mapping. */
313 __target(stream) = pos + size;
315 /* Make the next output operation call __flshfp. */
316 __put_limit(stream) = __buffer(stream);
318 __bufsize(stream) = size;
319 __get_limit(stream) = __buffer(stream) + size;
320 __bufp(stream) = __buffer(stream) + bufp;
321 return (unsigned char) *__bufp(stream)++;
324 static void
325 DEFUN(mapped_output, (stream, c),
326 FILE *stream AND int c)
328 struct mapped *CONST m = (struct mapped *) cookie;
329 struct shared_io *CONST sio = &m->shared;
330 error_t error;
331 off_t pos, bufp;
332 size_t size;
334 if (error = get_it(sio))
336 __error(stream) = 1;
337 errno = error;
338 return EOF;
341 if (__put_limit(stream) > __buffer(stream))
343 if (__bufp(stream) > __buffer(stream))
344 /* Tell the FS that we have written some data. */
345 sio->written = 1;
347 if (sio->use_postnotify_size &&
348 (__offset(stream) +
349 (__bufp(stream) - __buffer(stream))) > sio->postnotify_size)
351 /* Notify the FS about what has been written. */
352 if (error = __io_postnotify(m->file, m->cntl,
353 __offset(stream),
354 __bufp(stream) - __buffer(stream)))
355 goto end;
359 if (__buffer(stream) != NULL)
361 /* Remove the old mapping. */
362 (void) __vm_deallocate(__mach_task_self(), __buffer(stream),
363 __get_limit(stream) - __buffer(stream));
364 __buffer(stream) = NULL;
367 size = m->blksize;
369 pos = __target(stream);
370 /* Round POS to a block boundary, leaving the excess in BUFP. */
371 bufp = pos % size;
372 pos -= bufp;
374 if (sio->use_postnotify_size && size > sio->postnotify_size)
375 /* %%% What if SIZE < BUFP after this? */
376 size = sio->postnotify_size;
378 while (sio->use_prenotify_size && __target(stream) >= sio->prenotify_use)
379 if (error = __io_prenotify(m->file, m->cntl, pos, size))
380 goto end;
382 /* Map the data. */
384 vm_prot_t prot = VM_PROT_WRITE;
385 if (stream->__mode.__read && m->wrmemobj == m->rdmemobj)
386 prot |= VM_PROT_READ;
387 error = __vm_map(__mach_task_self(),
388 &__buffer(stream), size, 0, 1,
389 m->memobj, pos, 0, prot, prot, VM_INHERIT_NONE);
392 end:
393 release_it(m);
395 if (error)
397 __put_limit(stream) = __get_limit(stream) = __buffer(stream);
398 __error(stream) = 1;
399 errno = error;
401 else
403 /* Set the offset to the position where our mapping begins. */
404 __target(stream) = __offset(stream) = pos;
406 /* Make the next input operation call __fillbf. */
407 __get_limit(stream) = __buffer(stream);
409 __bufsize(stream) = size;
410 __put_limit(stream) = __buffer(stream) + size;
411 __bufp(stream) = __buffer(stream) + bufp;
412 *__bufp(stream)++ = (unsigned char) c;
416 /* Initialize STREAM as necessary.
417 This may change I/O functions, give a buffer, etc.
418 If no buffer is allocated, but the bufsize is set,
419 the bufsize will be used to allocate the buffer. */
420 void
421 DEFUN(__stdio_init_stream, (stream), FILE *stream)
423 CONST io_t file = (io_t) __cookie(stream);
424 io_statbuf_t buf;
425 memory_object_t cntl, xxmemobj, rdmemobj, wrmemobj;
426 struct mapped *m;
428 if (__io_stat(file, &buf))
429 return;
431 if (S_ISFIFO(buf.stb_mode))
433 /* It's named pipe (FIFO). Make it unbuffered. */
434 __userbuf(stream) = 1;
435 return;
438 if (sizeof(*m) > __vm_page_size)
439 __libc_fatal("stdio: sizeof(struct mapped) > vm_page_size");
441 /* Try to use mapped i/o. */
443 if (__io_map_cntl(m->file, &xxcntl, &rdcntl, &wtcntl))
444 return;
445 cntl = xxcntl; /* %%% ??? */
447 if (__io_map(m->file, &xxmemobj, &rdmemobj, &wrmemobj))
449 (void) __port_deallocate(__mach_task_self(), cntl);
450 return;
453 if (rdmemobj == MACH_PORT_NULL)
454 rdmemobj = xxmemobj;
455 if (wrmemobj == MACH_PORT_NULL)
456 wrmemobj = xxmemobj;
458 /* Lose if we can't do mapped i/o in the necessary direction(s). */
459 if ((stream->__mode.__read && rdmemobj == MACH_PORT_NULL) ||
460 (stream->__mode.__write && wrmemobj == MACH_PORT_NULL) ||
461 /* Map the shared page. */
462 __vm_map(__mach_task_self(), &m, sizeof(*m), NULL, 1, cntl, 0, 0,
463 VM_PROT_READ|VM_PROT_WRITE, VM_PROT_READ|VM_PROT_WRITE,
464 VM_INHERIT_NONE))
466 (void) __port_deallocate(__mach_task_self(), cntl);
467 (void) __port_deallocate(__mach_task_self(), xxmemobj);
468 (void) __port_deallocate(__mach_task_self(), rdmemobj);
469 (void) __port_deallocate(__mach_task_self(), wrmemobj);
470 return;
473 m->file = file;
474 m->blksize = buf.stb_blksize;
475 m->cntl = cntl;
476 m->rdmemobj = rdmemobj;
477 m->wrmemobj = wrmemobj;
479 __io_funcs(stream).__close = mapped_close;
480 __io_funcs(stream).__seek = mapped_seek;
481 __room_funcs(stream).__input = mapped_input;
482 __room_funcs(stream).__output = mapped_output;
483 __cookie(stream) = (PTR) m;
484 __userbuf(stream) = 1; /* Tell stdio not to allocate a buffer. */