home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Source Code 1993 July / THE_SOURCE_CODE_CD_ROM.iso / gnu / glibc-1.06 / sysdeps / mach / hurd / stdio_init.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-05-15  |  12.0 KB  |  486 lines

  1. /* Copyright (C) 1991 Free Software Foundation, Inc.
  2. This file is part of the GNU C Library.
  3.  
  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.
  8.  
  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.
  13.  
  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.  */
  18.  
  19. #include <ansidecl.h>
  20. #include <stdio.h>
  21. #include <hurd.h>
  22. #include <hurd/shared.h>
  23.  
  24. struct mapped
  25.   {
  26.     struct shared_io shared;
  27.  
  28.     /* The rest of the shared page is owned by the user (stdio).  */
  29.  
  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;
  36.   };
  37.  
  38.  
  39. /* Get IT.  */
  40. #ifdef    __GNUC__
  41. __inline
  42. #endif
  43. static error_t
  44. DEFUN(get_it, (m), struct mapped *m)
  45. {
  46.  try:
  47.  
  48.   __spin_lock(m->shared.lock);
  49.  
  50.   switch (m->shared.it_status)
  51.     {
  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;
  58.  
  59.     case USER_NOT_IT:
  60.       __spin_unlock(m->shared.lock);
  61.       {
  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;
  69.       }
  70.  
  71.     default:
  72.       __libc_fatal("get_it: Unrecognized IT status!\n");
  73.     }
  74. }
  75.  
  76. /* Release IT.  */
  77. #ifdef    __GNUC__
  78. __inline
  79. #endif
  80. static error_t
  81. DEFUN(release_it, (m), struct mapped *m)
  82. {
  83.   __spin_lock(m->shared.lock);
  84.   switch (m->shared.it_status)
  85.     {
  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;
  91.  
  92.     case USER_RELEASE_IT:
  93.       __spin_unlock(m->shared.lock);
  94.       return __io_release_it(m->file, m->cntl);
  95.  
  96.     default:
  97.       __libc_fatal("release_it: Unrecognized IT status!\n");
  98.     }
  99. }
  100.  
  101. static int
  102. DEFUN(mapped_close, (cookie), PTR cookie)
  103. {
  104.   struct mapped *CONST m = (struct mapped *) cookie;
  105.   int am_it;
  106.   error_t error = 0;
  107.  
  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);
  113.  
  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
  121.  
  122.   if (error != 0)
  123.     {
  124.       errno = error;
  125.       return -1;
  126.     }
  127.   return 0;
  128. }
  129.  
  130. static int
  131. DEFUN(mapped_seek, (cookie, pos, whence),
  132.       PTR cookie AND fpos_t *pos AND int whence)
  133. {
  134.   struct shared_io *CONST m = (struct shared_io *) cookie;
  135.   int error;
  136.  
  137.   error = get_it(m);
  138.   if (error == 0)
  139.     {
  140.       switch (whence)
  141.     {
  142.     case SEEK_SET:
  143.       if (!m->seekable && *pos > m->file_pointer)
  144.         error = ESPIPE;
  145.       else
  146.         {
  147.           m->file_pointer = *pos;
  148.           error = 0;
  149.         }
  150.       break;
  151.  
  152.     case SEEK_CUR:
  153.       if (!m->seekable && *pos < 0)
  154.         error = ESPIPE;
  155.       else
  156.         {
  157.           m->file_pointer += *pos;
  158.           *pos = m->file_pointer;
  159.           error = 0;
  160.         }
  161.       break;
  162.  
  163.     case SEEK_END:
  164.       if (!m->use_file_size)
  165.         error = ESPIPE;
  166.       else
  167.         {
  168.           off_t desired = m->file_size + *pos;
  169.           if (!m->seekable && desired < m->file_pointer)
  170.         error = ESPIPE;
  171.           else
  172.         {
  173.           *pos = m->file_pointer = desired;
  174.           error = 0;
  175.         }
  176.         }
  177.       break;
  178.  
  179.     default:
  180.       error = EINVAL;
  181.       break;
  182.     }
  183.  
  184.       if (error == 0)
  185.     error = release_it(m);
  186.       else
  187.     (void) release_it(m);
  188.     }
  189.  
  190.   if (error != 0)
  191.     {
  192.       errno = error;
  193.       return -1;
  194.     }
  195.   return 0;
  196. }
  197.  
  198. static int
  199. DEFUN(mapped_input, (stream), FILE *stream)
  200. {
  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;
  206.  
  207.   if (error = get_it(sio))
  208.     {
  209.       __error(stream) = 1;
  210.       errno = error;
  211.       return EOF;
  212.     }
  213.  
  214.   if (__buffer(stream) != NULL && m->rdmemobj == m->wrmemobj &&
  215.       __offset(stream) == __target(stream))
  216.     {
  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)++;
  228.     }
  229.  
  230.   if (__buffer(stream) != NULL)
  231.     {
  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;
  239.     }
  240.  
  241.   /* We're reading, so we're not at the end-of-file.  */
  242.   __eof(stream) = 0;
  243.  
  244.   pos = __target(stream);
  245.   while (sio->use_read_size && sio->read_size < pos)
  246.     {
  247.       if (sio->use_file_size && pos >= sio->file_size)
  248.     {
  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;
  256.     }
  257.  
  258.       /* Block until there is more to read.  */
  259.       error = __io_readsleep(m->file);
  260.       if (error)
  261.     {
  262.       (void) release_it(m);
  263.       errno = error;
  264.       return EOF;
  265.     }
  266.     }
  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");
  273.  
  274.   /* Round POS to a block boundary, leaving the excess in BUFP.  */
  275.   bufp = pos % m->blksize;
  276.   pos -= bufp;
  277.  
  278.   /* Decide how big a window on the file to use.  */
  279.   size -= pos;
  280.   if (size > m->blksize)
  281.     size = m->blksize;
  282.  
  283.   /* Map the data.  */
  284.   {
  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);
  291.   }
  292.  
  293.   if (error == 0)
  294.     /* Tell the FS that we have read some data.  */
  295.     sio->accessed = 1;
  296.  
  297.   if (error == 0)
  298.     (void) release_it(m);
  299.   else
  300.     error = release_it(m);
  301.  
  302.   if (error)
  303.     {
  304.     release_lost:
  305.       __put_limit(stream) = __get_limit(stream) = __buffer(stream);
  306.       errno = error;
  307.       return EOF;
  308.     }
  309.  
  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;
  314.  
  315.   /* Make the next output operation call __flshfp.  */
  316.   __put_limit(stream) = __buffer(stream);
  317.  
  318.   __bufsize(stream) = size;
  319.   __get_limit(stream) = __buffer(stream) + size;
  320.   __bufp(stream) = __buffer(stream) + bufp;
  321.   return (unsigned char) *__bufp(stream)++;
  322. }
  323.  
  324. static void
  325. DEFUN(mapped_output, (stream, c),
  326.       FILE *stream AND int c)
  327. {
  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;
  333.  
  334.   if (error = get_it(sio))
  335.     {
  336.       __error(stream) = 1;
  337.       errno = error;
  338.       return EOF;
  339.     }
  340.  
  341.   if (__put_limit(stream) > __buffer(stream))
  342.     {
  343.       if (__bufp(stream) > __buffer(stream))
  344.     /* Tell the FS that we have written some data.  */
  345.     sio->written = 1;
  346.  
  347.       if (sio->use_postnotify_size &&
  348.       (__offset(stream) +
  349.        (__bufp(stream) - __buffer(stream))) > sio->postnotify_size)
  350.     {
  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;
  356.     }
  357.     }
  358.  
  359.   if (__buffer(stream) != NULL)
  360.     {
  361.       /* Remove the old mapping.  */
  362.       (void) __vm_deallocate(__mach_task_self(), __buffer(stream),
  363.                  __get_limit(stream) - __buffer(stream));
  364.       __buffer(stream) = NULL;
  365.     }
  366.  
  367.   size = m->blksize;
  368.  
  369.   pos = __target(stream);
  370.   /* Round POS to a block boundary, leaving the excess in BUFP.  */
  371.   bufp = pos % size;
  372.   pos -= bufp;
  373.  
  374.   if (sio->use_postnotify_size && size > sio->postnotify_size)
  375.     /* %%% What if SIZE < BUFP after this?  */
  376.     size = sio->postnotify_size;
  377.  
  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;
  381.  
  382.   /* Map the data.  */
  383.   {
  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);
  390.   }
  391.  
  392.  end:
  393.   release_it(m);
  394.  
  395.   if (error)
  396.     {
  397.       __put_limit(stream) = __get_limit(stream) = __buffer(stream);
  398.       __error(stream) = 1;
  399.       errno = error;
  400.     }
  401.   else
  402.     {
  403.       /* Set the offset to the position where our mapping begins.  */
  404.       __target(stream) = __offset(stream) = pos;
  405.  
  406.       /* Make the next input operation call __fillbf.  */
  407.       __get_limit(stream) = __buffer(stream);
  408.  
  409.       __bufsize(stream) = size;
  410.       __put_limit(stream) = __buffer(stream) + size;
  411.       __bufp(stream) = __buffer(stream) + bufp;
  412.       *__bufp(stream)++ = (unsigned char) c;
  413.     }
  414. }
  415.  
  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)
  422. {
  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;
  427.  
  428.   if (__io_stat(file, &buf))
  429.     return;
  430.  
  431.   if (S_ISFIFO(buf.stb_mode))
  432.     {
  433.       /* It's named pipe (FIFO).  Make it unbuffered.  */
  434.       __userbuf(stream) = 1;
  435.       return;
  436.     }
  437.  
  438.   if (sizeof(*m) > __vm_page_size)
  439.     __libc_fatal("stdio: sizeof(struct mapped) > vm_page_size");
  440.  
  441.   /* Try to use mapped i/o.  */
  442.  
  443.   if (__io_map_cntl(m->file, &xxcntl, &rdcntl, &wtcntl))
  444.     return;
  445.   cntl = xxcntl; /* %%% ??? */
  446.  
  447.   if (__io_map(m->file, &xxmemobj, &rdmemobj, &wrmemobj))
  448.     {
  449.       (void) __port_deallocate(__mach_task_self(), cntl);
  450.       return;
  451.     }
  452.  
  453.   if (rdmemobj == MACH_PORT_NULL)
  454.     rdmemobj = xxmemobj;
  455.   if (wrmemobj == MACH_PORT_NULL)
  456.     wrmemobj = xxmemobj;
  457.  
  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))
  465.     {
  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;
  471.     }
  472.  
  473.   m->file = file;
  474.   m->blksize = buf.stb_blksize;
  475.   m->cntl = cntl;
  476.   m->rdmemobj = rdmemobj;
  477.   m->wrmemobj = wrmemobj;
  478.  
  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.  */
  485. }
  486.