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 < prev    next >
Encoding:
C/C++ Source or Header  |  1993-07-21  |  15.4 KB  |  632 lines

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