home *** CD-ROM | disk | FTP | other *** search
/ Geek Gadgets 1 / ADE-1.bin / ade-dist / gnat-2.06-src.tgz / tar.out / fsf / gnat / ada / threads / src / io.c < prev    next >
C/C++ Source or Header  |  1996-09-28  |  10KB  |  400 lines

  1. /* Copyright (C) 1992, the Florida State University
  2.    Distributed by the Florida State University under the terms of the
  3.    GNU Library General Public License.
  4.  
  5. This file is part of Pthreads.
  6.  
  7. Pthreads is free software; you can redistribute it and/or
  8. modify it under the terms of the GNU Library General Public
  9. License as published by the Free Software Foundation (version 2).
  10.  
  11. Pthreads is distributed "AS IS" in the hope that it will be
  12. useful, but WITHOUT ANY WARRANTY; without even the implied
  13. warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  14. See the GNU Library General Public License for more details.
  15.  
  16. You should have received a copy of the GNU Library General Public
  17. License along with Pthreads; see the file COPYING.  If not, write
  18. to the Free Software Foundation, 675 Mass Ave, Cambridge,
  19. MA 02139, USA.
  20.  
  21. Report problems and direct all questions to:
  22.  
  23.   pthreads-bugs@ada.cs.fsu.edu
  24.  
  25.   @(#)io.c    2.5 4/12/95
  26.   
  27. */
  28.  
  29. #ifdef IO
  30.  
  31. #include "pthread_internals.h"
  32. #include <sys/types.h>
  33. #include <sys/uio.h>
  34. #include <fcntl.h>
  35.  
  36. #if defined(STACK_CHECK) && defined(SIGNAL_STACK)
  37. /*
  38.  * aioread/write may cause a stack overflow in the UNIX kernel which cannot
  39.  * be caught by sighandler. This seems to be a bug in SunOS. We get
  40.  * around this problem by deliberately trying to access a storage
  41.  * location on stack about a page ahead of where we are. This will
  42.  * cause a premature stack overflow (SIGBUS) which *can* be caught
  43.  * by sighandler.
  44.  */
  45.   extern int pthread_page_size;
  46. #define ACCESS_STACK \
  47.   MACRO_BEGIN \
  48.     if (*(int *) (pthread_get_sp() - pthread_page_size)) \
  49.       ; \
  50.   MACRO_END
  51.  
  52. #else !STACK_CHECK || !SIGNAL_STACK
  53. #define ACCESS_STACK
  54. #endif !STACK_CHECK || !SIGNAL_STACK
  55.  
  56. /*------------------------------------------------------------*/
  57. /*
  58.  * read - Same as POSIX.1 read except that it blocks only the current thread
  59.  * rather than entire process.
  60.  */
  61. int READ(fd, buf, nbytes)
  62.      int fd;
  63.      void *buf;
  64.      IO_SIZE_T nbytes;
  65. {
  66.   int mode;
  67.   struct iovec iov[1];
  68.   pthread_t p;
  69.   struct timeval timeout;
  70.  
  71.  
  72.   /*
  73.    * If the mode is O_NDELAY perform a Non Blocking read & return immediately.
  74.    */
  75.   if ((mode = fcntl(fd, F_GETFL, 0)) & (O_NDELAY|O_NONBLOCK)) {
  76.     iov[0].iov_base = buf;
  77.     iov[0].iov_len = nbytes;
  78.     return(readv(fd, iov, 1));
  79.   }
  80.  
  81.   ACCESS_STACK;
  82.  
  83.   /*
  84.    * Else issue an asynchronous request for nbytes.
  85.    */
  86.   timeout.tv_sec        = 0;
  87.   timeout.tv_usec       = 0;
  88.   p = mac_pthread_self();
  89.   SET_KERNEL_FLAG;
  90.   p->resultp.aio_return = AIO_INPROGRESS;
  91.  
  92.   if (aioread(fd, buf, nbytes, 0l, SEEK_CUR,
  93.           (struct aio_result_t *) &p->resultp) < 0) {
  94.     CLEAR_KERNEL_FLAG;
  95.     return(-1);
  96.   }
  97.  
  98.   if (p->resultp.aio_return != AIO_INPROGRESS) {
  99.     if (p->resultp.aio_return != -1)
  100.       lseek(fd, p->resultp.aio_return, SEEK_CUR);
  101.     else
  102.       set_errno (p->resultp.aio_errno);
  103.     p->state |= T_IO_OVER;
  104.     CLEAR_KERNEL_FLAG;
  105.     aiowait(&timeout);
  106.     return(p->resultp.aio_return);
  107.   }
  108.   sigaddset(&p->sigwaitset, AIO_SIG);
  109.   p->state &= ~T_RUNNING;
  110.   p->state |= T_BLOCKED | T_INTR_POINT;
  111.   if (sigismember(&p->pending, SIGCANCEL) && !sigismember(&p->mask, SIGCANCEL))
  112.     SIG_CLEAR_KERNEL_FLAG(TRUE);
  113.   else {
  114.     pthread_q_deq_head(&ready, PRIMARY_QUEUE);
  115.     SIM_SYSCALL(TRUE);
  116.     CLEAR_KERNEL_FLAG;
  117.   }
  118.  
  119.   /*
  120.    * The case when the read() is interrupted (when the thread receives a
  121.    * signal other than SIGIO), read() returns -1 and errno is set to EINTR
  122.    * (this is done in signal.c when the thread is woken up).
  123.    */
  124.   switch (p->resultp.aio_return) {
  125.   case AIO_INPROGRESS:
  126.     aiocancel((struct aio_result_t *) &p->resultp);
  127.     return (-1);
  128.   case -1:
  129.     aiowait(&timeout);
  130.     set_errno (p->resultp.aio_errno);
  131.     return (-1);
  132.   default:
  133.     aiowait(&timeout);
  134.     lseek(fd, p->resultp.aio_return, SEEK_CUR);
  135.     return(p->resultp.aio_return);
  136.   }
  137. }
  138.  
  139. /*------------------------------------------------------------*/
  140. /*
  141.  * write - Same as POSIX.1 write except that it blocks only the current
  142.  * thread rather than entire process.
  143.  */
  144. int WRITE(fd, buf, nbytes)
  145.      int fd;
  146.      const void *buf;
  147.      IO_SIZE_T nbytes;
  148. {
  149.  
  150.   int mode;
  151.   struct iovec iov[1];
  152.   pthread_t p;
  153.   struct timeval timeout;
  154.  
  155.   /*
  156.    * If the mode is O_NDELAY perform a Non Blocking write & return immediately.
  157.    */
  158.   if ((mode = fcntl(fd, F_GETFL, 0)) & (O_NDELAY|O_NONBLOCK)) {
  159.     iov[0].iov_base = (caddr_t) buf;
  160.     iov[0].iov_len = nbytes;
  161.     return (writev(fd, iov, 1));
  162.   }
  163.  
  164.   ACCESS_STACK;
  165.  
  166.   /*
  167.    * Else issue an asynchronous request for nbytes.
  168.    */
  169.   timeout.tv_sec        = 0;
  170.   timeout.tv_usec       = 0;
  171.   p = mac_pthread_self();
  172.   SET_KERNEL_FLAG;
  173.   p->resultp.aio_return = AIO_INPROGRESS;
  174.  
  175.   if (aiowrite(fd, (char *) buf, nbytes, 0l, SEEK_CUR,
  176.            (struct aio_result_t *) &p->resultp) < 0) {
  177.     CLEAR_KERNEL_FLAG;
  178.     return(-1);
  179.   }
  180.  
  181.   if (p->resultp.aio_return != AIO_INPROGRESS) {
  182.     if (p->resultp.aio_return != -1)
  183.       lseek(fd, p->resultp.aio_return, SEEK_CUR);
  184.     else
  185.       set_errno(p->resultp.aio_errno);
  186.     p->state |= T_IO_OVER;
  187.     CLEAR_KERNEL_FLAG;
  188.     aiowait(&timeout);
  189.     return(p->resultp.aio_return);
  190.   }
  191.   sigaddset(&p->sigwaitset, AIO_SIG);
  192.   p->state &= ~T_RUNNING;
  193.   p->state |= T_BLOCKED | T_INTR_POINT; 
  194.   if (sigismember(&p->pending, SIGCANCEL) &&
  195.       !sigismember(&p->mask, SIGCANCEL))
  196.     SIG_CLEAR_KERNEL_FLAG(TRUE);
  197.   else {
  198.     pthread_q_deq_head(&ready, PRIMARY_QUEUE);
  199.     SIM_SYSCALL(TRUE);
  200.     CLEAR_KERNEL_FLAG;
  201.   }
  202.   switch (p->resultp.aio_return) {
  203.   case AIO_INPROGRESS:
  204.     aiocancel((struct aio_result_t *) &p->resultp);
  205.     return(-1);
  206.   case -1:
  207.     aiowait(&timeout);
  208.     set_errno (p->resultp.aio_errno);
  209.     return(-1);
  210.   default:
  211.     aiowait(&timeout);
  212.     lseek(fd, p->resultp.aio_return, SEEK_CUR);
  213.     return(p->resultp.aio_return);
  214.   }
  215. }
  216.  
  217. #ifndef SVR4
  218. /*------------------------------------------------------------*/
  219. /*
  220.  * accept - Same as BSD accept except that it blocks only the current thread
  221.  * rather than entire process.
  222.  */
  223. int accept(s, addr, addrlen)
  224.      int s;
  225.      struct sockaddr *addr;
  226.      int *addrlen;
  227. {
  228.   int mode;
  229.   struct iovec iov[1];
  230.   pthread_t p;
  231.   struct timeval timeout;
  232.   int result;
  233.  
  234.   /*
  235.    * If the mode is O_NDELAY perform a Non Blocking accept & return 
  236.    * immediately.
  237.    */
  238.   if ((mode = fcntl(s, F_GETFL, 0)) & (O_NDELAY|O_NONBLOCK)) {
  239.     return (ACCEPT(s, addr, addrlen));
  240.   }
  241.  
  242.   ACCESS_STACK;
  243.  
  244.   /*
  245.    * Else issue an asynchronous request
  246.    */
  247.  
  248.   mode = fcntl(s, F_GETFL, 0);
  249.   if (fcntl(s, F_SETFL, (mode|FNDELAY|FASYNC)) < 0)
  250.     return (-1);
  251.   if (fcntl(s, F_SETOWN, getpid()) < 0) {
  252.     fcntl (s, F_SETFL, mode);
  253.     return(-1);
  254.   }
  255.  
  256.   p = mac_pthread_self();
  257.   SET_KERNEL_FLAG; /* No preemption */
  258.  
  259.   while (TRUE) {
  260. #ifdef DEBUG
  261.     printf("Try to accept\n");
  262. #endif
  263.     result = ACCEPT(s, addr, addrlen);
  264.     if (result != -1) {
  265.       CLEAR_KERNEL_FLAG;
  266.       if ((fcntl(result, F_SETFL, mode) != -1) &&
  267.           (fcntl(s, F_SETFL, mode) != -1))
  268.         return(result);
  269.       return (-1);
  270.     }
  271.     if (errno != EWOULDBLOCK) {
  272.       CLEAR_KERNEL_FLAG;
  273.       fcntl(s, F_SETFL, mode);
  274.       return(-1);
  275.     };
  276. #ifdef DEBUG
  277.     printf("Unsuccessfull\n");
  278. #endif DEBUG
  279.     sigaddset(&p->sigwaitset, AIO_SIG);
  280.     p->state &= ~T_RUNNING;
  281.     p->state |= T_BLOCKED | T_INTR_POINT;
  282.     if (sigismember(&p->pending, SIGCANCEL) &&
  283.     !sigismember(&p->mask, SIGCANCEL))
  284.       SIG_CLEAR_KERNEL_FLAG(TRUE);
  285.     else {
  286.       pthread_q_deq_head(&ready, PRIMARY_QUEUE);
  287.       SIM_SYSCALL(TRUE);
  288.       CLEAR_KERNEL_FLAG;
  289.     }
  290.   }
  291. }
  292.  
  293. /*------------------------------------------------------------*/
  294. /*
  295.  * pthread_fds_set - initialization of file descriptor
  296.  */
  297. void pthread_fds_set(l, r)
  298.      fd_set *l, *r;
  299. {
  300.   if (l)
  301.     if (r)
  302.       *l = *r;
  303.     else 
  304.       FD_ZERO(l);
  305. }
  306.  
  307. /*------------------------------------------------------------*/
  308. /*
  309.  * pthread_fds_union - bit-wise union of file descriptor fields
  310.  */
  311. void pthread_fds_union(l, r, width)
  312.      fd_set *l,*r;
  313.      int width;
  314. {
  315.   int i;
  316.  
  317.   for (i = 0; i < howmany(width, NFDBITS); i++)
  318.     (*l).fds_bits [i] = (*l).fds_bits [i] | (*r).fds_bits [i];
  319. }
  320.  
  321. /*------------------------------------------------------------*/
  322. /*
  323.  * select - Same as BSD select except that it blocks only the current thread
  324.  * rather than entire process.
  325.  */
  326. int select(width, readfds, writefds, exceptfds, timeout)
  327.      int width;
  328.      fd_set *readfds, *writefds, *exceptfds;
  329.      struct timeval *timeout;
  330. {
  331.   static struct timeval mintimeout = {0, 0};
  332.   pthread_t p;
  333.   int result;
  334.   struct timespec p_timeout;
  335.   
  336.   ACCESS_STACK;
  337.   
  338.   p = mac_pthread_self();
  339.   SET_KERNEL_FLAG;
  340.   
  341.   pthread_fds_set(&(p->readfds), readfds);
  342.   pthread_fds_set(&(p->writefds), writefds);
  343.   pthread_fds_set(&(p->exceptfds), exceptfds); 
  344.   
  345.   result = SELECT(width, readfds, writefds, exceptfds, &mintimeout);
  346.   if (result != 0) {
  347.     CLEAR_KERNEL_FLAG;
  348.     return result;
  349.   }
  350.   
  351.   p->width = width;
  352.   gwidth = MAX(gwidth, width);
  353.   pthread_fds_union(&greadfds, &(p->readfds), width);
  354.   pthread_fds_union(&gwritefds, &(p->writefds), width);
  355.   pthread_fds_union(&gexceptfds, &(p->exceptfds), width);
  356.   p->wait_on_select = TRUE;
  357.   
  358.   if (timeout && timerisset(timeout)) {
  359.     U2P_TIME(p_timeout, *timeout);
  360.     if (pthread_timed_sigwait(p, p_timeout, REL_TIME, NULL, NULL) == -1) {
  361.       CLEAR_KERNEL_FLAG;
  362.       return(-1);
  363.     }
  364.   }
  365.   sigaddset(&p->sigwaitset, AIO_SIG);
  366.   p->state &= ~T_RUNNING;
  367.   p->state |= T_BLOCKED | T_INTR_POINT;
  368.   if (sigismember(&p->pending, SIGCANCEL) &&
  369.       !sigismember(&p->mask, SIGCANCEL))
  370.     SIG_CLEAR_KERNEL_FLAG(TRUE);
  371.   else {
  372.     pthread_q_deq_head(&ready, PRIMARY_QUEUE);
  373.     SIM_SYSCALL(TRUE);
  374.     CLEAR_KERNEL_FLAG;
  375.   }
  376.  
  377.   if (p->wait_on_select)
  378.     return(0);
  379.  
  380.   pthread_fds_set(readfds, &(p->readfds));  
  381.   pthread_fds_set(writefds, &(p->writefds)); 
  382.   pthread_fds_set(exceptfds, &(p->exceptfds));
  383.   return(p->how_many);
  384. }
  385. #endif !SVR4
  386.  
  387. /*------------------------------------------------------------*/
  388. #if defined(STACK_CHECK) && defined(SIGNAL_STACK)
  389. /*
  390.  * pthread_io_end - dummy function used to do pc mapping to check
  391.  *                  stack_overflow.
  392.  */
  393. void pthread_io_end()
  394. {
  395.   return;
  396. }
  397. /*------------------------------------------------------------*/
  398. #endif STACK_CHECK && SIGNAL_STACK
  399. #endif IO
  400.