Fork us on GitHub Follow us on Facebook Follow us on Twitter

Changeset 19ea61d in mainline


Ignore:
Timestamp:
2017-11-20T20:01:24Z (3 years ago)
Author:
Jiri Svoboda <jiri@…>
Branches:
master
Children:
677cad5
Parents:
c657bd7
Message:

Chardev should allow large data transfers.

Location:
uspace/lib/c/generic/io
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • uspace/lib/c/generic/io/chardev.c

    rc657bd7 r19ea61d  
    9696int chardev_read(chardev_t *chardev, void *buf, size_t size, size_t *nread)
    9797{
    98         if (size > 4 * sizeof(sysarg_t))
    99                 return ELIMIT;
    100 
    10198        async_exch_t *exch = async_exchange_begin(chardev->sess);
    102         sysarg_t message[4] = { 0 };
    103         const ssize_t ret = async_req_1_4(exch, CHARDEV_READ, size,
    104             &message[0], &message[1], &message[2], &message[3]);
     99
     100        if (size > DATA_XFER_LIMIT) {
     101                /* This should not hurt anything. */
     102                size = DATA_XFER_LIMIT;
     103        }
     104
     105        ipc_call_t answer;
     106        aid_t req = async_send_0(exch, CHARDEV_READ, &answer);
     107        int rc = async_data_read_start(exch, buf, size);
    105108        async_exchange_end(exch);
    106         if (ret > 0 && (size_t)ret <= size)
    107                 memcpy(buf, message, size);
    108 
    109         if (ret < 0) {
     109
     110        if (rc != EOK) {
     111                async_forget(req);
    110112                *nread = 0;
    111                 return ret;
    112         }
    113 
    114         *nread = ret;
    115         return EOK;
    116 }
    117 
    118 /** Write to character device.
    119  *
    120  * Write @a size bytes from @a data to character device. On success EOK
    121  * is returned, all bytes were written and @a *nwritten is set to @a size.
     113                return rc;
     114        }
     115
     116        sysarg_t retval;
     117        async_wait_for(req, &retval);
     118
     119        if (retval != EOK) {
     120                *nread = 0;
     121                return retval;
     122        }
     123
     124        *nread = IPC_GET_ARG2(answer);
     125        /* In case of partial success, ARG1 contains the error code */
     126        return IPC_GET_ARG1(answer);
     127
     128}
     129
     130/** Write up to DATA_XFER_LIMIT bytes to character device.
     131 *
     132 * Write up to @a size or DATA_XFER_LIMIT bytes from @a data to character
     133 * device. On success EOK is returned, bytes were written and @a *nwritten
     134 * is set to min(@a size, DATA_XFER_LIMIT)
    122135 *
    123136 * On error a non-zero error code is returned and @a *nwritten is filled with
     
    131144 * @return EOK on success or non-zero error code
    132145 */
     146static int chardev_write_once(chardev_t *chardev, const void *data,
     147    size_t size, size_t *nwritten)
     148{
     149        async_exch_t *exch = async_exchange_begin(chardev->sess);
     150        ipc_call_t answer;
     151        aid_t req;
     152        int rc;
     153
     154        /* Break down large transfers */
     155        if (size > DATA_XFER_LIMIT)
     156                size = DATA_XFER_LIMIT;
     157
     158        req = async_send_0(exch, CHARDEV_WRITE, &answer);
     159        rc = async_data_write_start(exch, data, size);
     160        async_exchange_end(exch);
     161
     162        if (rc != EOK) {
     163                async_forget(req);
     164                *nwritten = 0;
     165                return rc;
     166        }
     167
     168        sysarg_t retval;
     169        async_wait_for(req, &retval);
     170        if (retval != EOK) {
     171                *nwritten = 0;
     172                return retval;
     173        }
     174
     175        *nwritten = IPC_GET_ARG2(answer);
     176        /* In case of partial success, ARG1 contains the error code */
     177        return IPC_GET_ARG1(answer);
     178}
     179
     180/** Write to character device.
     181 *
     182 * Write @a size bytes from @a data to character device. On success EOK
     183 * is returned, all bytes were written and @a *nwritten is set to @a size.
     184 *
     185 * On error a non-zero error code is returned and @a *nwritten is filled with
     186 * the number of bytes that were successfully transferred.
     187 *
     188 * @param chardev Character device
     189 * @param buf Destination buffer
     190 * @param size Maximum number of bytes to read
     191 * @param nwritten Place to store actual number of bytes written
     192 *
     193 * @return EOK on success or non-zero error code
     194 */
    133195int chardev_write(chardev_t *chardev, const void *data, size_t size,
    134196    size_t *nwritten)
    135197{
    136         int ret;
    137 
    138         if (size > 3 * sizeof(sysarg_t))
    139                 return ELIMIT;
    140 
    141         async_exch_t *exch = async_exchange_begin(chardev->sess);
    142         sysarg_t message[3] = { 0 };
    143         memcpy(message, data, size);
    144         ret = async_req_4_0(exch, CHARDEV_WRITE, size,
    145             message[0], message[1], message[2]);
    146         async_exchange_end(exch);
    147 
    148         if (ret < 0) {
    149                 *nwritten = 0;
    150                 return ret;
    151         }
    152 
    153         *nwritten = ret;
     198        size_t nw;
     199        size_t p;
     200        int rc;
     201
     202        p = 0;
     203        while (p < size) {
     204                rc = chardev_write_once(chardev, data + p, size - p, &nw);
     205                /* nw is always valid, we can have partial success */
     206                p += nw;
     207
     208                if (rc != EOK) {
     209                        /* We can return partial success */
     210                        *nwritten = p;
     211                        return rc;
     212                }
     213        }
     214
     215        *nwritten = p;
    154216        return EOK;
    155217}
  • uspace/lib/c/generic/io/chardev_srv.c

    rc657bd7 r19ea61d  
    4646    ipc_call_t *call)
    4747{
    48         size_t size = IPC_GET_ARG1(*call);
     48        void *buf;
     49        size_t size;
    4950        int rc;
     51        ipc_callid_t rcallid;
    5052
    51         if (srv->srvs->ops->read == NULL) {
    52                 async_answer_0(callid, ENOTSUP);
     53        if (!async_data_read_receive(&rcallid, &size)) {
     54                async_answer_0(callid, EINVAL);
    5355                return;
    5456        }
    5557
    56         if (size <= 4 * sizeof(sysarg_t)) {
    57                 sysarg_t message[4] = {};
     58        buf = malloc(size);
     59        if (buf == NULL) {
     60                async_answer_0(rcallid, ENOMEM);
     61                async_answer_0(callid, ENOMEM);
     62                return;
     63        }
    5864
    59                 rc = srv->srvs->ops->read(srv, (char *)message, size);
    60                 async_answer_4(callid, rc, message[0], message[1],
    61                     message[2], message[3]);
    62         } else {
    63                 async_answer_0(callid, ELIMIT);
     65        if (srv->srvs->ops->read == NULL) {
     66                async_answer_0(rcallid, ENOTSUP);
     67                async_answer_0(callid, ENOTSUP);
     68                free(buf);
     69                return;
    6470        }
     71
     72        rc = srv->srvs->ops->read(srv, buf, size);
     73        if (rc < 0) {
     74                async_answer_0(rcallid, rc);
     75                async_answer_0(callid, rc);
     76                free(buf);
     77                return;
     78        }
     79
     80        async_data_read_finalize(rcallid, buf, size);
     81
     82        free(buf);
     83        async_answer_2(callid, EOK, EOK, rc /* nread */);
    6584}
    6685
     
    6887    ipc_call_t *call)
    6988{
    70         size_t size = IPC_GET_ARG1(*call);
     89        void *data;
     90        size_t size;
    7191        int rc;
     92
     93        rc = async_data_write_accept(&data, false, 0, 0, 0, &size);
     94        if (rc != EOK) {
     95                async_answer_0(callid, rc);
     96                return;
     97        }
    7298
    7399        if (srv->srvs->ops->write == NULL) {
     
    76102        }
    77103
    78         if (size <= 3 * sizeof(sysarg_t)) {
    79                 const sysarg_t message[3] = {
    80                         IPC_GET_ARG2(*call),
    81                         IPC_GET_ARG3(*call),
    82                         IPC_GET_ARG4(*call)
    83                 };
     104        rc = srv->srvs->ops->write(srv, data, size);
     105        free(data);
     106        if (rc < 0)
     107                async_answer_0(callid, rc);
    84108
    85                 rc = srv->srvs->ops->write(srv, (char *)message, size);
    86                 async_answer_0(callid, rc);
    87         } else {
    88                 async_answer_0(callid, ELIMIT);
    89         }
     109        async_answer_2(callid, EOK, EOK, rc /* nwritten */);
    90110}
    91111
Note: See TracChangeset for help on using the changeset viewer.