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. */
22 #include <hurd/shared.h>
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
;
44 DEFUN(get_it
, (m
), struct mapped
*m
)
48 __spin_lock(m
->shared
.lock
);
50 switch (m
->shared
.it_status
)
52 case USER_POTENTIALLY_IT
:
53 m
->shared
.it_status
= USER_IT
;
56 __spin_unlock(m
->shared
.lock
);
60 __spin_unlock(m
->shared
.lock
);
62 error_t error
= __io_get_it(m
->file
, m
->cntl
);
66 /* Don't just tail-recurse because that might
67 make the function not get inlined. Sigh. */
72 __libc_fatal("get_it: Unrecognized IT status!\n");
81 DEFUN(release_it
, (m
), struct mapped
*m
)
83 __spin_lock(m
->shared
.lock
);
84 switch (m
->shared
.it_status
)
87 m
->shared
.it_status
= USER_POTENTIALLY_IT
;
89 __spin_unlock(m
->shared
.lock
);
93 __spin_unlock(m
->shared
.lock
);
94 return __io_release_it(m
->file
, m
->cntl
);
97 __libc_fatal("release_it: Unrecognized IT status!\n");
102 DEFUN(mapped_close
, (cookie
), PTR cookie
)
104 struct mapped
*CONST m
= (struct mapped
*) cookie
;
108 __spin_lock(m
->shared
.lock
);
109 am_it
= m
->shared
.it_status
!= USER_NOT_IT
;
110 __spin_unlock(m
->shared
.lock
);
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
));
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
;
143 if (!m
->seekable
&& *pos
> m
->file_pointer
)
147 m
->file_pointer
= *pos
;
153 if (!m
->seekable
&& *pos
< 0)
157 m
->file_pointer
+= *pos
;
158 *pos
= m
->file_pointer
;
164 if (!m
->use_file_size
)
168 off_t desired
= m
->file_size
+ *pos
;
169 if (!m
->seekable
&& desired
< m
->file_pointer
)
173 *pos
= m
->file_pointer
= desired
;
185 error
= release_it(m
);
187 (void) release_it(m
);
199 DEFUN(mapped_input
, (stream
), FILE *stream
)
201 struct mapped
*CONST m
= (struct mapped
*) cookie
;
202 struct shared_io
*CONST sio
= &m
->shared
;
207 if (error
= get_it(sio
))
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
);
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
))
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
)) -
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. */
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. */
251 __io_eofnotify(m
->file
);
252 if (error
= release_it(sio
))
258 /* Block until there is more to read. */
259 error
= __io_readsleep(m
->file
);
262 (void) release_it(m
);
267 if (sio
->use_read_size
)
268 size
= sio
->read_size
;
269 else if (sio
->use_file_size
)
270 size
= sio
->file_size
;
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
;
278 /* Decide how big a window on the file to use. */
280 if (size
> m
->blksize
)
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
);
294 /* Tell the FS that we have read some data. */
298 (void) release_it(m
);
300 error
= release_it(m
);
305 __put_limit(stream
) = __get_limit(stream
) = __buffer(stream
);
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
)++;
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
;
334 if (error
= get_it(sio
))
341 if (__put_limit(stream
) > __buffer(stream
))
343 if (__bufp(stream
) > __buffer(stream
))
344 /* Tell the FS that we have written some data. */
347 if (sio
->use_postnotify_size
&&
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
,
354 __bufp(stream
) - __buffer(stream
)))
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
;
369 pos
= __target(stream
);
370 /* Round POS to a block boundary, leaving the excess in 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
))
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
);
397 __put_limit(stream
) = __get_limit(stream
) = __buffer(stream
);
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. */
421 DEFUN(__stdio_init_stream
, (stream
), FILE *stream
)
423 CONST io_t file
= (io_t
) __cookie(stream
);
425 memory_object_t cntl
, xxmemobj
, rdmemobj
, wrmemobj
;
428 if (__io_stat(file
, &buf
))
431 if (S_ISFIFO(buf
.stb_mode
))
433 /* It's named pipe (FIFO). Make it unbuffered. */
434 __userbuf(stream
) = 1;
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
))
445 cntl
= xxcntl
; /* %%% ??? */
447 if (__io_map(m
->file
, &xxmemobj
, &rdmemobj
, &wrmemobj
))
449 (void) __port_deallocate(__mach_task_self(), cntl
);
453 if (rdmemobj
== MACH_PORT_NULL
)
455 if (wrmemobj
== MACH_PORT_NULL
)
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
,
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
);
474 m
->blksize
= buf
.stb_blksize
;
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. */