Changeset ef8bcc6 in mainline for uspace/lib/libc/generic/io/io.c


Ignore:
Timestamp:
2009-06-15T21:46:21Z (15 years ago)
Author:
Jiri Svoboda <jirik.svoboda@…>
Branches:
lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
Children:
953769f
Parents:
c07af37
Message:

Stdio stream buffering (only for writing a.t.m.) Issue: Do we need two moving delimiters (head, tail) to recover from error or is one moving data delimiter enough, like in the current implementation? (Where the buffer must be drained as a whole, cannot do it part at a time.

File:
1 edited

Legend:

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

    rc07af37 ref8bcc6  
    3636#include <unistd.h>
    3737#include <fcntl.h>
     38#include <assert.h>
    3839#include <string.h>
    3940#include <errno.h>
     
    4546#include <adt/list.h>
    4647
     48static void _fflushbuf(FILE *stream);
     49
    4750static FILE stdin_null = {
    4851        .fd = -1,
     
    5053        .eof = true,
    5154        .klog = false,
    52         .phone = -1
     55        .phone = -1,
     56        .btype = _IONBF,
     57        .buf = NULL,
     58        .buf_size = 0,
     59        .buf_head = NULL
    5360};
    5461
     
    5865        .eof = false,
    5966        .klog = true,
    60         .phone = -1
     67        .phone = -1,
     68        .btype = _IOLBF,
     69        .buf = NULL,
     70        .buf_size = BUFSIZ,
     71        .buf_head = NULL
    6172};
    6273
     
    6677        .eof = false,
    6778        .klog = true,
    68         .phone = -1
     79        .phone = -1,
     80        .btype = _IONBF,
     81        .buf = NULL,
     82        .buf_size = 0,
     83        .buf_head = NULL
    6984};
    7085
     
    157172}
    158173
     174/** Set stream buffer. */
     175void setvbuf(FILE *stream, void *buf, int mode, size_t size)
     176{
     177        stream->btype = mode;
     178        stream->buf = buf;
     179        stream->buf_size = size;
     180        stream->buf_head = stream->buf;
     181}
     182
     183/** Allocate stream buffer. */
     184static int _fallocbuf(FILE *stream)
     185{
     186        assert(stream->buf == NULL);
     187
     188        stream->buf = malloc(stream->buf_size);
     189        if (stream->buf == NULL) {
     190                errno = ENOMEM;
     191                return -1;
     192        }
     193
     194        stream->buf_head = stream->buf;
     195        return 0;
     196}
     197
    159198/** Open a stream.
    160199 *
     
    187226        stream->klog = false;
    188227        stream->phone = -1;
     228
     229        /* FIXME: Should select buffering type based on what was opened. */
     230        setvbuf(stream, NULL, _IOFBF, BUFSIZ);
    189231       
    190232        list_append(&stream->link, &files);
     
    207249        stream->klog = false;
    208250        stream->phone = -1;
     251
     252        /* FIXME: Should select buffering type based on what was opened. */
     253        setvbuf(stream, NULL, _IOLBF, BUFSIZ);
    209254       
    210255        list_append(&stream->link, &files);
     
    237282        stream->klog = false;
    238283        stream->phone = -1;
     284
     285        /* FIXME: Should select buffering type based on what was opened. */
     286        setvbuf(stream, NULL, _IOLBF, BUFSIZ);
    239287       
    240288        list_append(&stream->link, &files);
     
    284332        size_t left = size * nmemb;
    285333        size_t done = 0;
    286        
     334
     335        /* Make sure no data is pending write. */
     336        _fflushbuf(stream);
     337
    287338        while ((left > 0) && (!stream->error) && (!stream->eof)) {
    288339                ssize_t rd = read(stream->fd, buf + done, left);
     
    301352}
    302353
    303 /** Write to a stream.
    304  *
    305  * @param buf    Source buffer.
    306  * @param size   Size of each record.
    307  * @param nmemb  Number of records to write.
    308  * @param stream Pointer to the stream.
    309  *
    310  */
    311 size_t fwrite(const void *buf, size_t size, size_t nmemb, FILE *stream)
     354static size_t _fwrite(const void *buf, size_t size, size_t nmemb, FILE *stream)
    312355{
    313356        size_t left = size * nmemb;
     
    333376}
    334377
     378/** Drain stream buffer, do not sync stream. */
     379static void _fflushbuf(FILE *stream)
     380{
     381        size_t bytes_used;
     382
     383        if (!stream->buf || stream->btype == _IONBF || stream->error)
     384                return;
     385
     386        bytes_used = stream->buf_head - stream->buf;
     387        if (bytes_used == 0)
     388                return;
     389
     390        (void) _fwrite(stream->buf, 1, bytes_used, stream);
     391        stream->buf_head = stream->buf;
     392}
     393
     394/** Write to a stream.
     395 *
     396 * @param buf    Source buffer.
     397 * @param size   Size of each record.
     398 * @param nmemb  Number of records to write.
     399 * @param stream Pointer to the stream.
     400 *
     401 */
     402size_t fwrite(const void *buf, size_t size, size_t nmemb, FILE *stream)
     403{
     404        uint8_t *data;
     405        size_t bytes_left;
     406        size_t now;
     407        size_t buf_free;
     408        size_t total_written;
     409        size_t i;
     410        uint8_t b;
     411        bool need_flush;
     412
     413        /* If not buffered stream, write out directly. */
     414        if (stream->btype == _IONBF)
     415                return _fwrite(buf, size, nmemb, stream);
     416
     417        /* Perform lazy allocation of stream buffer. */
     418        if (stream->buf == NULL) {
     419                if (_fallocbuf(stream) != 0)
     420                        return 0; /* Errno set by _fallocbuf(). */
     421        }
     422
     423        data = (uint8_t *) buf;
     424        bytes_left = size * nmemb;
     425        total_written = 0;
     426        need_flush = false;
     427
     428        while (!stream->error && bytes_left > 0) {
     429
     430                buf_free = stream->buf_size - (stream->buf_head - stream->buf);
     431                if (bytes_left > buf_free)
     432                        now = buf_free;
     433                else
     434                        now = bytes_left;
     435
     436                for (i = 0; i < now; i++) {
     437                        b = data[i];
     438                        stream->buf_head[i] = b;
     439
     440                        if (b == '\n' && stream->btype == _IOLBF)
     441                                need_flush = true;
     442                }
     443
     444                buf += now;
     445                stream->buf_head += now;
     446                buf_free -= now;
     447                bytes_left -= now;
     448                total_written += now;
     449
     450                if (buf_free == 0) {
     451                        /* Only need to drain buffer. */
     452                        _fflushbuf(stream);
     453                        need_flush = false;
     454                }
     455        }
     456
     457        if (need_flush)
     458                fflush(stream);
     459
     460        return (total_written / size);
     461}
     462
    335463int fputc(wchar_t c, FILE *stream)
    336464{
     
    406534int fflush(FILE *stream)
    407535{
     536        _fflushbuf(stream);
     537
    408538        if (stream->klog) {
    409539                klog_update();
Note: See TracChangeset for help on using the changeset viewer.