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

Changeset facebd56 in mainline


Ignore:
Timestamp:
2010-03-12T21:59:09Z (12 years ago)
Author:
Jiri Svoboda <jiri@…>
Branches:
lfn, master
Children:
2070570, e2b73d4f
Parents:
5782081
Message:

Input buffering for ANSI C streams. Make output stream syncing less aggressive.

Location:
uspace/lib/libc
Files:
2 edited

Legend:

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

    r5782081 rfacebd56  
    4646#include <adt/list.h>
    4747
     48static void _ffillbuf(FILE *stream);
    4849static void _fflushbuf(FILE *stream);
    4950
     
    5758        .buf = NULL,
    5859        .buf_size = 0,
    59         .buf_head = NULL
     60        .buf_head = NULL,
     61        .buf_tail = NULL,
     62        .buf_state = _bs_empty
    6063};
    6164
     
    6972        .buf = NULL,
    7073        .buf_size = BUFSIZ,
    71         .buf_head = NULL
     74        .buf_head = NULL,
     75        .buf_tail = NULL,
     76        .buf_state = _bs_empty
    7277};
    7378
     
    8186        .buf = NULL,
    8287        .buf_size = 0,
    83         .buf_head = NULL
     88        .buf_head = NULL,
     89        .buf_tail = NULL,
     90        .buf_state = _bs_empty
    8491};
    8592
     
    179186        stream->buf_size = size;
    180187        stream->buf_head = stream->buf;
     188        stream->buf_tail = stream->buf;
     189        stream->buf_state = _bs_empty;
    181190}
    182191
     
    210219       
    211220        stream->buf_head = stream->buf;
     221        stream->buf_tail = stream->buf;
    212222        return 0;
    213223}
     
    243253        stream->klog = false;
    244254        stream->phone = -1;
     255        stream->need_sync = false;
    245256        _setvbuf(stream);
    246257       
     
    264275        stream->klog = false;
    265276        stream->phone = -1;
     277        stream->need_sync = false;
    266278        _setvbuf(stream);
    267279       
     
    295307        stream->klog = false;
    296308        stream->phone = -1;
     309        stream->need_sync = false;
    297310        _setvbuf(stream);
    298311       
     
    331344}
    332345
    333 /** Read from a stream.
     346/** Read from a stream (unbuffered).
    334347 *
    335348 * @param buf    Destination buffer.
     
    337350 * @param nmemb  Number of records to read.
    338351 * @param stream Pointer to the stream.
    339  *
    340  */
    341 size_t fread(void *buf, size_t size, size_t nmemb, FILE *stream)
     352 */
     353static size_t _fread(void *buf, size_t size, size_t nmemb, FILE *stream)
    342354{
    343355        size_t left, done;
     
    345357        if (size == 0 || nmemb == 0)
    346358                return 0;
    347 
    348         /* Make sure no data is pending write. */
    349         _fflushbuf(stream);
    350359
    351360        left = size * nmemb;
     
    368377}
    369378
     379/** Write to a stream (unbuffered).
     380 *
     381 * @param buf    Source buffer.
     382 * @param size   Size of each record.
     383 * @param nmemb  Number of records to write.
     384 * @param stream Pointer to the stream.
     385 */
    370386static size_t _fwrite(const void *buf, size_t size, size_t nmemb, FILE *stream)
    371387{
     
    394410                }
    395411        }
     412
     413        if (done > 0)
     414                stream->need_sync = true;
    396415       
    397416        return (done / size);
    398417}
    399418
    400 /** Drain stream buffer, do not sync stream. */
     419/** Read some data in stream buffer. */
     420static void _ffillbuf(FILE *stream)
     421{
     422        ssize_t rc;
     423
     424        stream->buf_head = stream->buf_tail = stream->buf;
     425
     426        rc = read(stream->fd, stream->buf, stream->buf_size);
     427        if (rc < 0) {
     428                stream->error = true;
     429                return;
     430        }
     431
     432        if (rc == 0) {
     433                stream->eof = true;
     434                return;
     435        }
     436
     437        stream->buf_head += rc;
     438        stream->buf_state = _bs_read;
     439}
     440
     441/** Write out stream buffer, do not sync stream. */
    401442static void _fflushbuf(FILE *stream)
    402443{
    403444        size_t bytes_used;
    404        
     445
    405446        if ((!stream->buf) || (stream->btype == _IONBF) || (stream->error))
    406447                return;
    407        
    408         bytes_used = stream->buf_head - stream->buf;
     448
     449        bytes_used = stream->buf_head - stream->buf_tail;
    409450        if (bytes_used == 0)
    410451                return;
    411        
    412         (void) _fwrite(stream->buf, 1, bytes_used, stream);
     452
     453        /* If buffer has prefetched read data, we need to seek back. */
     454        if (stream->buf_state == _bs_read)
     455                lseek(stream->fd, - (ssize_t) bytes_used, SEEK_CUR);
     456
     457        /* If buffer has unwritten data, we need to write them out. */
     458        if (stream->buf_state == _bs_write)
     459                (void) _fwrite(stream->buf_tail, 1, bytes_used, stream);
     460
    413461        stream->buf_head = stream->buf;
    414 }
     462        stream->buf_tail = stream->buf;
     463        stream->buf_state = _bs_empty;
     464}
     465
     466/** Read from a stream.
     467 *
     468 * @param dest   Destination buffer.
     469 * @param size   Size of each record.
     470 * @param nmemb  Number of records to read.
     471 * @param stream Pointer to the stream.
     472 *
     473 */
     474size_t fread(void *dest, size_t size, size_t nmemb, FILE *stream)
     475{
     476        uint8_t *dp;
     477        size_t bytes_left;
     478        size_t now;
     479        size_t data_avail;
     480        size_t total_read;
     481        size_t i;
     482
     483        if (size == 0 || nmemb == 0)
     484                return 0;
     485
     486        /* If not buffered stream, read in directly. */
     487        if (stream->btype == _IONBF) {
     488                now = _fread(dest, size, nmemb, stream);
     489                return now;
     490        }
     491
     492        /* Make sure no data is pending write. */
     493        if (stream->buf_state == _bs_write)
     494                _fflushbuf(stream);
     495
     496        /* Perform lazy allocation of stream buffer. */
     497        if (stream->buf == NULL) {
     498                if (_fallocbuf(stream) != 0)
     499                        return 0; /* Errno set by _fallocbuf(). */
     500        }
     501
     502        bytes_left = size * nmemb;
     503        total_read = 0;
     504        dp = (uint8_t *) dest;
     505
     506        while ((!stream->error) && (!stream->eof) && (bytes_left > 0)) {
     507                if (stream->buf_head == stream->buf_tail)
     508                        _ffillbuf(stream);
     509
     510                if (stream->error || stream->eof)
     511                        break;
     512
     513                data_avail = stream->buf_head - stream->buf_tail;
     514
     515                if (bytes_left > data_avail)
     516                        now = data_avail;
     517                else
     518                        now = bytes_left;
     519
     520                for (i = 0; i < now; i++) {
     521                        dp[i] = stream->buf_tail[i];
     522                }
     523
     524                dp += now;
     525                stream->buf_tail += now;
     526                bytes_left -= now;
     527                total_read += now;
     528        }
     529
     530        return (total_read / size);
     531}
     532
    415533
    416534/** Write to a stream.
     
    442560                return now;
    443561        }
    444        
     562
     563        /* Make sure buffer contains no prefetched data. */
     564        if (stream->buf_state == _bs_read)
     565                _fflushbuf(stream);
     566
     567
    445568        /* Perform lazy allocation of stream buffer. */
    446569        if (stream->buf == NULL) {
     
    482605        }
    483606       
     607        if (total_written > 0)
     608                stream->buf_state = _bs_write;
     609
    484610        if (need_flush)
    485611                fflush(stream);
     
    570696int fseek(FILE *stream, off64_t offset, int whence)
    571697{
    572         off64_t rc = lseek(stream->fd, offset, whence);
     698        off64_t rc;
     699
     700        _fflushbuf(stream);
     701
     702        rc = lseek(stream->fd, offset, whence);
    573703        if (rc == (off64_t) (-1)) {
    574704                /* errno has been set by lseek64. */
    575705                return -1;
    576706        }
    577        
     707
    578708        stream->eof = false;
    579        
    580709        return 0;
    581710}
     
    600729        }
    601730       
    602         if (stream->fd >= 0)
     731        if (stream->fd >= 0 && stream->need_sync) {
     732                /**
     733                 * Better than syncing always, but probably still not the
     734                 * right thing to do.
     735                 */
     736                stream->need_sync = false;
    603737                return fsync(stream->fd);
     738        }
    604739       
    605740        return ENOENT;
  • uspace/lib/libc/include/stdio.h

    r5782081 rfacebd56  
    7575};
    7676
     77enum _buffer_state {
     78        /** Buffer is empty */
     79        _bs_empty,
     80
     81        /** Buffer contains data to be written */
     82        _bs_write,
     83
     84        /** Buffer contains prefetched data for reading */
     85        _bs_read
     86};
     87
    7788typedef struct {
    7889        /** Linked list pointer. */
     
    94105        int phone;
    95106
     107        /**
     108         * Non-zero if the stream needs sync on fflush(). XXX change
     109         * console semantics so that sync is not needed.
     110         */
     111        int need_sync;
     112
    96113        /** Buffering type */
    97114        enum _buffer_type btype;
     115
    98116        /** Buffer */
    99117        uint8_t *buf;
     118
    100119        /** Buffer size */
    101120        size_t buf_size;
     121
     122        /** Buffer state */
     123        enum _buffer_state buf_state;
     124
    102125        /** Buffer I/O pointer */
    103126        uint8_t *buf_head;
     127
     128        /** Points to end of occupied space when in read mode. */
     129        uint8_t *buf_tail;
    104130} FILE;
    105131
Note: See TracChangeset for help on using the changeset viewer.