home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Source Code 1993 July / THE_SOURCE_CODE_CD_ROM.iso / X / mit / fonts / server / os / io.c.orig < prev    next >
Encoding:
Text File  |  1991-06-21  |  15.0 KB  |  619 lines

  1. /* $XConsortium: io.c,v 1.5 91/06/21 18:19:12 keith Exp $ */
  2. /*
  3.  * i/o functions
  4.  *
  5.  */
  6. /*
  7.  * Copyright 1990, 1991 Network Computing Devices;
  8.  * Portions Copyright 1987 by Digital Equipment Corporation and the
  9.  * Massachusetts Institute of Technology
  10.  *
  11.  * Permission to use, copy, modify, and distribute this protoype software
  12.  * and its documentation to Members and Affiliates of the MIT X Consortium
  13.  * any purpose and without fee is hereby granted, provided
  14.  * that the above copyright notice appear in all copies and that both that
  15.  * copyright notice and this permission notice appear in supporting
  16.  * documentation, and that the names of Network Computing Devices, Digital or
  17.  * MIT not be used in advertising or publicity pertaining to distribution of
  18.  * the software without specific, written prior permission.
  19.  *
  20.  * NETWORK COMPUTING DEVICES, DIGITAL AND MIT DISCLAIM ALL WARRANTIES WITH
  21.  * REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
  22.  * AND FITNESS, IN NO EVENT SHALL NETWORK COMPUTING DEVICES, DIGITAL OR MIT BE
  23.  * LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  24.  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
  25.  * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
  26.  * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  27.  *
  28.  * @(#)io.c    4.2    5/3/91
  29.  *
  30.  */
  31.  
  32. #include    <stdio.h>
  33. #include    <errno.h>
  34. #include    <sys/types.h>
  35. #include    <sys/param.h>
  36. #include    <sys/uio.h>
  37.  
  38. #include    "FSproto.h"
  39. #include    "clientstr.h"
  40. #include    "osdep.h"
  41. #include    "globals.h"
  42.  
  43. extern int  errno;
  44.  
  45. /* check for both EAGAIN and EWOULDBLOCK, because some supposedly POSIX
  46.  * systems are broken and return EWOULDBLOCK when they should return EAGAIN
  47.   */
  48.  
  49. #if defined(EAGAIN) && defined(EWOULDBLOCK)
  50. #define ETEST(err) (err == EAGAIN || err == EWOULDBLOCK)
  51. #else
  52.  
  53. #ifdef EAGAIN
  54. #define ETEST(err) (err == EAGAIN)
  55. #else
  56. #define ETEST(err) (err == EWOULDBLOCK)
  57. #endif
  58.  
  59. #endif
  60.  
  61.  
  62. extern long ClientsWithInput[];
  63. extern long ClientsWriteBlocked[];
  64. extern long OutputPending[];
  65.  
  66. extern long OutputBufferSize;
  67.  
  68. extern int  ConnectionTranslation[];
  69.  
  70. extern Bool AnyClientsWriteBlocked;
  71. extern Bool NewOutputPending;
  72.  
  73. static int  timesThisConnection = 0;
  74. static ConnectionInputPtr FreeInputs = (ConnectionInputPtr) NULL;
  75. static ConnectionOutputPtr FreeOutputs = (ConnectionOutputPtr) NULL;
  76. static OsCommPtr AvailableInput = (OsCommPtr) NULL;
  77.  
  78. static ConnectionInputPtr AllocateInputBuffer();
  79. static ConnectionOutputPtr AllocateOutputBuffer();
  80.  
  81.  
  82. #define        MAX_TIMES_PER    10
  83.  
  84. #define    yield_control()                \
  85.     { isItTimeToYield = TRUE;        \
  86.       timesThisConnection = 0; }
  87.  
  88. #define    yield_control_no_input()        \
  89.     { yield_control();            \
  90.       BITCLEAR(ClientsWithInput, fd); }
  91.  
  92. #define    yield_control_death()            \
  93.     { timesThisConnection = 0; }
  94.  
  95. #define    request_length(req, client)        \
  96.     (((client)->swapped ? lswaps((req)->length) : (req)->length) << 2)
  97.  
  98. int
  99. ReadRequest(client)
  100.     ClientPtr   client;
  101. {
  102.     OsCommPtr   oc = (OsCommPtr) client->osPrivate;
  103.     ConnectionInputPtr oci = oc->input;
  104.     fsReq      *request;
  105.     int         fd = oc->fd;
  106.     int         result,
  107.                 gotnow,
  108.                 needed;
  109.  
  110.     if (AvailableInput) {
  111.     if (AvailableInput != oc) {
  112.         ConnectionInputPtr aci = AvailableInput->input;
  113.  
  114.         if (aci->size > BUFWATERMARK) {
  115.         fsfree(aci->buffer);
  116.         fsfree(aci);
  117.         } else {
  118.         aci->next = FreeInputs;
  119.         FreeInputs = aci;
  120.         }
  121.         AvailableInput->input = (ConnectionInputPtr) NULL;
  122.     }
  123.     AvailableInput = (OsCommPtr) NULL;
  124.     }
  125.     if (!oci) {
  126.     if ((oci = FreeInputs ) != (ConnectionInputPtr) 0) {
  127.         FreeInputs = oci->next;
  128.     } else if (!(oci = AllocateInputBuffer())) {
  129.         yield_control_death();
  130.         return -1;
  131.     }
  132.     oc->input = oci;
  133.     }
  134.     oci->bufptr += oci->lenLastReq;
  135.  
  136.     request = (fsReq *) oci->bufptr;
  137.  
  138.     gotnow = oci->bufcnt + oci->buffer - oci->bufptr;
  139.  
  140.     /* not enough for a request */
  141.     if ((gotnow < sizeof(fsReq)) ||
  142.         (gotnow < (needed = request_length(request, client)))) {
  143.     oci->lenLastReq = 0;
  144.     if ((gotnow < sizeof(fsReq)) || needed == 0)
  145.         needed = sizeof(fsReq);
  146.     else if (needed > MAXBUFSIZE) {
  147.         yield_control_death();
  148.         return -1;
  149.     }
  150.     /* see if we need to shift up a partial request so the rest can fit */
  151.     if ((gotnow == 0) ||
  152.         ((oci->bufptr - oci->buffer + needed) > oci->size)) {
  153.         if ((gotnow > 0) && (oci->bufptr != oci->buffer))
  154.         bcopy(oci->bufptr, oci->buffer, gotnow);
  155.         /* grow buffer if necessary */
  156.         if (needed > oci->size) {
  157.         char       *ibuf;
  158.  
  159.         ibuf = (char *) fsrealloc(oci, needed);
  160.         if (!ibuf) {
  161.             yield_control_death();
  162.             return -1;
  163.         }
  164.         oci->size = needed;
  165.         oci->buffer = ibuf;
  166.         }
  167.         oci->bufptr = oci->buffer;
  168.         oci->bufcnt = gotnow;
  169.     }
  170.     /* fill 'er up */
  171.     result = read(fd, oci->buffer + oci->bufcnt,
  172.               oci->size - oci->bufcnt);
  173.     if (result <= 0) {
  174.         if ((result < 0) && ETEST(errno)) {
  175.         yield_control_no_input();
  176.         return 0;
  177.         } else {
  178.         yield_control_death();
  179.         return -1;
  180.         }
  181.     }
  182.     oci->bufcnt += result;
  183.     gotnow += result;
  184.  
  185.     /* free up space after huge requests */
  186.     if ((oci->size > BUFWATERMARK) &&
  187.         (oci->bufcnt < BUFSIZE) && (needed < BUFSIZE)) {
  188.         char       *ibuf;
  189.  
  190.         ibuf = (char *) fsrealloc(oci, BUFSIZE);
  191.         if (ibuf) {
  192.         oci->size = BUFSIZE;
  193.         oci->buffer = ibuf;
  194.         oci->bufptr = ibuf + oci->bufcnt - gotnow;
  195.         }
  196.     }
  197.     request = (fsReq *) oci->bufptr;
  198.     if ((gotnow < sizeof(fsReq)) ||
  199.         (gotnow < (needed = request_length(request, client)))) {
  200.         yield_control_no_input();
  201.         return 0;
  202.     }
  203.     }
  204.     if (needed == 0)
  205.     needed = sizeof(fsReq);
  206.     oci->lenLastReq = needed;
  207.     /*
  208.      * Check to see if client has at least one whole request in the buffer. If
  209.      * there is only a partial request, treat like buffer is empty so that
  210.      * select() will be called again and other clients can get into the queue.
  211.      */
  212.  
  213.     if (gotnow >= needed + sizeof(fsReq)) {
  214.     request = (fsReq *) (oci->bufptr + needed);
  215.     if (gotnow >= needed + request_length(request, client))
  216.         BITSET(ClientsWithInput, fd);
  217.     else
  218.         yield_control_no_input();
  219.     } else {
  220.     if (gotnow == needed)
  221.         AvailableInput = oc;
  222.     yield_control_no_input();
  223.     }
  224.  
  225.     if (++timesThisConnection >= MAX_TIMES_PER)
  226.     yield_control();
  227.  
  228.     client->requestBuffer = (pointer) oci->bufptr;
  229.     return needed;
  230. }
  231.  
  232. Bool
  233. InsertFakeRequest(client, data, count)
  234.     ClientPtr   client;
  235.     char       *data;
  236.     int         count;
  237. {
  238.     OsCommPtr   oc = (OsCommPtr) client->osPrivate;
  239.     ConnectionInputPtr oci = oc->input;
  240.     int         fd = oc->fd;
  241.     fsReq      *request;
  242.     int         gotnow,
  243.                 moveup;
  244.  
  245.     if (AvailableInput) {
  246.     if (AvailableInput != oc) {
  247.         register ConnectionInputPtr aci = AvailableInput->input;
  248.  
  249.         if (aci->size > BUFWATERMARK) {
  250.         fsfree(aci->buffer);
  251.         fsfree(aci);
  252.         } else {
  253.         aci->next = FreeInputs;
  254.         FreeInputs = aci;
  255.         }
  256.         AvailableInput->input = (ConnectionInputPtr) NULL;
  257.     }
  258.     AvailableInput = (OsCommPtr) NULL;
  259.     }
  260.     if (!oci) {
  261.     if ((oci = FreeInputs) != (ConnectionInputPtr) 0)
  262.         FreeInputs = oci->next;
  263.     else if (!(oci = AllocateInputBuffer()))
  264.         return FALSE;
  265.     oc->input = oci;
  266.  
  267.     }
  268.     oci->bufptr += oci->lenLastReq;
  269.     oci->lenLastReq = 0;
  270.     gotnow = oci->bufcnt + oci->buffer - oci->bufptr;
  271.     if ((gotnow + count) > oci->size) {
  272.     char       *ibuf;
  273.  
  274.     ibuf = (char *) fsrealloc(oci->buffer, gotnow + count);
  275.     if (!ibuf)
  276.         return FALSE;
  277.     oci->size = gotnow + count;
  278.     oci->buffer = ibuf;
  279.     oci->bufptr = ibuf + oci->bufcnt - gotnow;
  280.     }
  281.     moveup = count - (oci->bufptr - oci->buffer);
  282.     if (moveup > 0) {
  283.     if (gotnow > 0)
  284.         bcopy(oci->bufptr, oci->bufptr + moveup, gotnow);
  285.     oci->bufptr += moveup;
  286.     oci->bufcnt += moveup;
  287.     }
  288.     bcopy(data, oci->bufptr - count, count);
  289.     oci->bufptr -= count;
  290.     request = (fsReq *) oci->bufptr;
  291.     gotnow += count;
  292.     if ((gotnow >= sizeof(fsReq)) &&
  293.         (gotnow >= request_length(request, client)))
  294.     BITSET(ClientsWithInput, fd);
  295.     else
  296.     yield_control_no_input();
  297.     return TRUE;
  298. }
  299.  
  300. ResetCurrentRequest(client)
  301.     ClientPtr   client;
  302. {
  303.     OsCommPtr   oc = (OsCommPtr) client->osPrivate;
  304.     ConnectionInputPtr oci = oc->input;
  305.     int         fd = oc->fd;
  306.     fsReq      *request;
  307.     int         gotnow;
  308.  
  309.     if (AvailableInput == oc)
  310.     AvailableInput = (OsCommPtr) NULL;
  311.     oci->lenLastReq = 0;
  312.     request = (fsReq *) oci->bufptr;
  313.     gotnow = oci->bufcnt + oci->buffer - oci->bufptr;
  314.     if ((gotnow >= sizeof(fsReq)) &&
  315.         (gotnow >= request_length(request, client))) {
  316.     BITSET(ClientsWithInput, fd);
  317.     yield_control();
  318.     } else {
  319.     yield_control_no_input();
  320.     }
  321. }
  322.  
  323. static int  padlength[4] = {0, 3, 2, 1};
  324.  
  325. int
  326. FlushClient(client, oc, extraBuf, extraCount)
  327.     ClientPtr   client;
  328.     OsCommPtr   oc;
  329.     char       *extraBuf;
  330.     int         extraCount;
  331. {
  332.     ConnectionOutputPtr oco = oc->output;
  333.     int         fd = oc->fd;
  334.     struct iovec iov[3];
  335.     char        padBuffer[3];
  336.     long        written;
  337.     long        padsize;
  338.     long        notWritten;
  339.     long        todo;
  340.  
  341.     if (!oco)
  342.     return 0;
  343.     written = 0;
  344.     padsize = padlength[extraCount & 3];
  345.     notWritten = oco->count + extraCount + padsize;
  346.     todo = notWritten;
  347.     while (notWritten) {
  348.     long        before = written;
  349.     long        remain = todo;
  350.     int         i = 0;
  351.     long        len;
  352.  
  353.     /*-
  354.      * You could be very general here and have "in" and "out" iovecs and
  355.      * write a loop without using a macro, but what the heck.  This
  356.      * translates to:
  357.      *
  358.      *     how much of this piece is new?
  359.      *    if more new then we are trying this time, clamp
  360.      *    if nothing new
  361.      *        then bump down amount already written, for next piece
  362.      *        else put new stuff in iovec, will need all of next piece
  363.      *
  364.      * Note that todo had better be at least 1 or else we'll end up
  365.      * writing 0 iovecs.
  366.      */
  367.  
  368. #define    InsertIOV(pointer, length)    \
  369.     len = (length) - before;    \
  370.     if (len > remain)        \
  371.         len = remain;        \
  372.     if (len <= 0) {            \
  373.         before = (-len);        \
  374.     } else {            \
  375.         iov[i].iov_len = len;    \
  376.         iov[i].iov_base = (pointer) + before; \
  377.         i++;            \
  378.         remain -= len;        \
  379.         before = 0;            \
  380.     }
  381.  
  382.     InsertIOV((char *) oco->buf, oco->count);
  383.     InsertIOV(extraBuf, extraCount);
  384.     InsertIOV(padBuffer, padsize);
  385.  
  386.     errno = 0;
  387.     if ((len = writev(fd, iov, i)) >= 0) {
  388.         written += len;
  389.         notWritten -= len;
  390.         todo = notWritten;
  391.     } else if (ETEST(errno)) {
  392.         BITSET(ClientsWriteBlocked, fd);
  393.         AnyClientsWriteBlocked = TRUE;
  394.  
  395.         if (written < oco->count) {
  396.         if (written > 0) {
  397.             oco->count -= written;
  398.             bcopy((char *) oco->buf + written,
  399.               (char *) oco->buf, oco->count);
  400.             written = 0;
  401.         }
  402.         } else {
  403.         written -= oco->count;
  404.         oco->count = 0;
  405.         }
  406.  
  407.         /* grow buffer if necessary */
  408.         if (notWritten > oco->size) {
  409.         unsigned char *obuf;
  410.  
  411.         obuf = (unsigned char *) fsrealloc(oco->buf,
  412.                           notWritten + OutputBufferSize);
  413.         if (!obuf) {
  414.             close(fd);
  415.             MarkClientException(client);
  416.             oco->count = 0;
  417.             return -1;
  418.         }
  419.         oco->size = notWritten + OutputBufferSize;
  420.         oco->buf = obuf;
  421.         }
  422.         if ((len = extraCount - written) > 0) {
  423.         bcopy(extraBuf + written,
  424.               (char *) oco->buf + oco->count, len);
  425.         }
  426.         oco->count = notWritten;
  427.         return extraCount;
  428.     } else {
  429.         close(fd);
  430.         MarkClientException(client);
  431.         oco->count = 0;
  432.         return -1;
  433.     }
  434.     }
  435.  
  436.     /* everything was flushed */
  437.     oco->count = 0;
  438.  
  439.     /* clear the write block if it was set */
  440.     if (AnyClientsWriteBlocked) {
  441.     BITCLEAR(ClientsWriteBlocked, fd);
  442.     if (!ANYSET(ClientsWriteBlocked))
  443.         AnyClientsWriteBlocked = FALSE;
  444.     }
  445.     if (oco->size > BUFWATERMARK) {
  446.     fsfree(oco->buf);
  447.     fsfree(oco);
  448.     } else {
  449.     oco->next = FreeOutputs;
  450.     FreeOutputs = oco;
  451.     }
  452.     oc->output = (ConnectionOutputPtr) NULL;
  453.  
  454.     return extraCount;
  455. }
  456.  
  457. void
  458. FlushAllOutput()
  459. {
  460.     int         index,
  461.                 base,
  462.                 mask;
  463.     OsCommPtr   oc;
  464.     ClientPtr   client;
  465.  
  466.     if (!NewOutputPending)
  467.     return;
  468.  
  469.     NewOutputPending = FALSE;
  470.  
  471.     for (base = 0; base < mskcnt; base++) {
  472.     mask = OutputPending[base];
  473.     OutputPending[base] = 0;
  474.     while (mask) {
  475.         index = ffs(mask) - 1;
  476.         mask &= ~lowbit(mask);
  477.         if ((index = ConnectionTranslation[(base << 5) + index]) == 0)
  478.         continue;
  479.         client = clients[index];
  480.         if (client->clientGone == CLIENT_GONE)
  481.         continue;
  482.         oc = (OsCommPtr) client->osPrivate;
  483.         if (GETBIT(ClientsWithInput, oc->fd)) {
  484.         BITSET(OutputPending, oc->fd);
  485.         NewOutputPending = TRUE;
  486.         } else {
  487.         (void) FlushClient(client, oc, (char *) NULL, 0);
  488.         }
  489.     }
  490.     }
  491. }
  492.  
  493. WriteToClient(client, count, buf)
  494.     ClientPtr   client;
  495.     int         count;
  496.     char       *buf;
  497. {
  498.     OsCommPtr   oc = (OsCommPtr) client->osPrivate;
  499.     ConnectionOutputPtr oco = oc->output;
  500.     int         padBytes;
  501.  
  502.     if (!count)
  503.     return 0;
  504.  
  505.     if (!oco) {
  506.     if ((oco = FreeOutputs) != (ConnectionOutputPtr) 0) {
  507.         FreeOutputs = oco->next;
  508.     } else if (!(oco = AllocateOutputBuffer())) {
  509.         close(oc->fd);
  510.         MarkClientException(client);
  511.         return -1;
  512.     }
  513.     oc->output = oco;
  514.     }
  515.     padBytes = padlength[count & 3];
  516.  
  517.     if (oco->count + count + padBytes > oco->size) {
  518.     BITCLEAR(OutputPending, oc->fd);
  519.     NewOutputPending = FALSE;
  520.     return FlushClient(client, oc, buf, count);
  521.     }
  522.     NewOutputPending = TRUE;
  523.     BITSET(OutputPending, oc->fd);
  524.     bcopy(buf, (char *) oco->buf + oco->count, count);
  525.     oco->count += count + padBytes;
  526.  
  527.     return count;
  528. }
  529.  
  530. static      ConnectionInputPtr
  531. AllocateInputBuffer()
  532. {
  533.     register ConnectionInputPtr oci;
  534.  
  535.     oci = (ConnectionInputPtr) fsalloc(sizeof(ConnectionInput));
  536.     if (!oci)
  537.     return (ConnectionInputPtr) NULL;
  538.     oci->buffer = (char *) fsalloc(BUFSIZE);
  539.     if (!oci->buffer) {
  540.     fsfree(oci);
  541.     return (ConnectionInputPtr) NULL;
  542.     }
  543.     oci->next = 0;
  544.     oci->size = BUFSIZE;
  545.     oci->bufptr = oci->buffer;
  546.     oci->bufcnt = 0;
  547.     oci->lenLastReq = 0;
  548.     return oci;
  549. }
  550. static      ConnectionOutputPtr
  551. AllocateOutputBuffer()
  552. {
  553.     register ConnectionOutputPtr oco;
  554.  
  555.     oco = (ConnectionOutputPtr) fsalloc(sizeof(ConnectionOutput));
  556.     if (!oco)
  557.     return (ConnectionOutputPtr) NULL;
  558.     oco->buf = (unsigned char *) fsalloc(BUFSIZE);
  559.     if (!oco->buf) {
  560.     fsfree(oco);
  561.     return (ConnectionOutputPtr) NULL;
  562.     }
  563.     oco->size = BUFSIZE;
  564.     oco->count = 0;
  565.     return oco;
  566. }
  567.  
  568.  
  569. void
  570. FreeOsBuffers(oc)
  571.     OsCommPtr   oc;
  572. {
  573.     register ConnectionInputPtr oci;
  574.     register ConnectionOutputPtr oco;
  575.  
  576.     if (AvailableInput == oc)
  577.     AvailableInput = (OsCommPtr) NULL;
  578.     if ((oci = oc->input) != (ConnectionInputPtr) 0) {
  579.     if (FreeInputs) {
  580.         fsfree(oci->buffer);
  581.         fsfree(oci);
  582.     } else {
  583.         FreeInputs = oci;
  584.         oci->next = (ConnectionInputPtr) NULL;
  585.         oci->bufptr = oci->buffer;
  586.         oci->bufcnt = 0;
  587.         oci->lenLastReq = 0;
  588.     }
  589.     }
  590.     if ((oco = oc->output) != (ConnectionOutputPtr) 0) {
  591.     if (FreeOutputs) {
  592.         fsfree(oco->buf);
  593.         fsfree(oco);
  594.     } else {
  595.         FreeOutputs = oco;
  596.         oco->next = (ConnectionOutputPtr) NULL;
  597.         oco->count = 0;
  598.     }
  599.     }
  600. }
  601.  
  602. void
  603. ResetOsBuffers()
  604. {
  605.     register ConnectionInputPtr oci;
  606.     register ConnectionOutputPtr oco;
  607.  
  608.     while ((oci = FreeInputs) != (ConnectionInputPtr) 0) {
  609.     FreeInputs = oci->next;
  610.     fsfree(oci->buffer);
  611.     fsfree(oci);
  612.     }
  613.     while ((oco = FreeOutputs) != (ConnectionOutputPtr) 0) {
  614.     FreeOutputs = oco->next;
  615.     fsfree(oco->buf);
  616.     fsfree(oco);
  617.     }
  618. }
  619.