[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[tyndur-devel] [PATCH 3/6] libc: Lesepuffer in fread



+ libc: Einen ziemlich simplen Lesepuffer in fread eingebaut. Vermutlich
  trotzdem kompliziert genug, dass er alles kaputtmacht.

Signed-off-by: Kevin Wolf <kevin@xxxxxxxxxx>
---
 src/modules/include/lostio.h   |    4 +
 src/modules/lib/stdlibc/file.c |  180 ++++++++++++++++++++++++++++++++++++----
 2 files changed, 168 insertions(+), 16 deletions(-)

diff --git a/src/modules/include/lostio.h b/src/modules/include/lostio.h
index 4b31fba..38c8164 100644
--- a/src/modules/include/lostio.h
+++ b/src/modules/include/lostio.h
@@ -131,9 +131,13 @@ struct lostio_internal_file {
     void*           buffer_ptr;
     size_t          buffer_size;
     size_t          buffer_pos;
+    size_t          buffer_filled;
     uint8_t         buffer_mode;
+    bool            buffer_writes;
     bool            free_buffer;
 
+    uint64_t        cur_pos;
+
     /*
      * Achtung: os_eof ist _nicht_ der EOF-Marker aus der C-Spezifikation, der
      * erst gesetzt wird, wenn das Programm aus dem Puffer das letzte Byte
diff --git a/src/modules/lib/stdlibc/file.c b/src/modules/lib/stdlibc/file.c
index 89b95e6..7aab88f 100644
--- a/src/modules/lib/stdlibc/file.c
+++ b/src/modules/lib/stdlibc/file.c
@@ -118,6 +118,7 @@ FILE* fopen (const char* filename, const char* mode)
     setvbuf(int_res, malloc(BUFSIZ), _IOFBF, BUFSIZ);
     int_res->free_buffer = true;
 
+    int_res->cur_pos = 0;
     int_res->error = false;
     int_res->os_eof = false;
 
@@ -175,6 +176,64 @@ int fclose (FILE* io_res)
     return result ? EOF : 0;
 }
 
+static void prepare_buffer(FILE* io_res, bool is_write)
+{
+    if (io_res->buffer_writes == is_write) {
+        return;
+    }
+
+    if (io_res->buffer_writes == false) {
+        lio_compat_seek(io_res->res, io_res->buffer_pos, LIO_SEEK_CUR);
+        io_res->cur_pos += io_res->buffer_pos;
+    } else {
+        fflush(io_res);
+    }
+
+    io_res->buffer_pos = 0;
+    io_res->buffer_filled = 0;
+    io_res->buffer_writes = is_write;
+}
+
+size_t fread_buffered(void* dest, size_t bytes, FILE* io_res)
+{
+    if ((io_res->res->flags & IO_RES_FLAG_READAHEAD) == 0) {
+        return 0;
+    }
+
+    if (io_res->buffer_ptr == NULL) {
+        return 0;
+    }
+
+    if (io_res->buffer_pos < io_res->buffer_filled) {
+        size_t len = io_res->buffer_filled - io_res->buffer_pos;
+        if (len > bytes) {
+            len = bytes;
+        }
+        memcpy(dest, io_res->buffer_ptr + io_res->buffer_pos, len);
+        io_res->buffer_pos += len;
+        return len;
+    }
+
+    io_res->buffer_filled = 0;
+    lio_compat_seek(io_res->res, io_res->buffer_pos, LIO_SEEK_CUR);
+    io_res->cur_pos += io_res->buffer_pos;
+
+    if (bytes > io_res->buffer_size / 4) {
+        return 0;
+    }
+
+    io_res->buffer_filled = lio_compat_readahead(io_res->buffer_ptr,
+       io_res->buffer_size, io_res->res);
+    if (io_res->buffer_filled < bytes) {
+        io_res->buffer_filled = 0;
+        return 0;
+    }
+
+    memcpy(dest, io_res->buffer_ptr, bytes);
+    io_res->buffer_pos = bytes;
+
+    return bytes;
+}
 
 /**
  * Teil aus der Datei lesen
@@ -225,20 +284,33 @@ size_t fread(void* dest, size_t blocksize, size_t blockcount, FILE* io_res)
         }
     }
 
-    // Der Buffer wird noch geleert, damit auch wirklich die Aktuellsten
+    // Ein Schreibpuffer wird noch geleert, damit auch wirklich die Aktuellsten
     // Daten gelesen werden.
-    fflush(io_res);
+    prepare_buffer(io_res, false);
 
-    ret = lio_compat_read(dest + read_bytes,
-        (blocksize * blockcount) - read_bytes, 1, io_res->res);
+    read_bytes += fread_buffered(dest + read_bytes,
+        (blocksize * blockcount) - read_bytes, io_res);
 
-    if (ret == -EAGAIN) {
-        return 0;
-    } else if (ret < 0) {
-        io_res->error = true;
-        return 0;
-    } else if (!ret) {
-        io_res->os_eof = true;
+    if (blocksize * blockcount > read_bytes) {
+        lio_compat_seek(io_res->res, io_res->buffer_pos, LIO_SEEK_CUR);
+        io_res->cur_pos += io_res->buffer_pos;
+
+        io_res->buffer_filled = 0;
+        ret = lio_compat_read(dest + read_bytes,
+            (blocksize * blockcount) - read_bytes, 1, io_res->res);
+
+        if (ret == -EAGAIN) {
+            return 0;
+        } else if (ret < 0) {
+            io_res->error = true;
+            return 0;
+        } else if (!ret) {
+            io_res->os_eof = true;
+        } else {
+            io_res->cur_pos += ret;
+        }
+    } else {
+        ret = 0;
     }
 
     return (read_bytes + ret) / blocksize;
@@ -368,6 +440,9 @@ size_t fwrite(const void* data, size_t blocksize, size_t blockcount,
         free(io_res->ungetc_buffer);
     }
 
+    // Puffer leeren, wenn es ein Lesepuffer ist
+    prepare_buffer(io_res, true);
+
 	//Wenn kein Buffer gesetzt ist, aber das Zwischenspeichern nicht deaktivert
 	// ist, wird das hier gemacht. Das schuetzt vor Pagefaults ;-).
 	if ((io_res->buffer_ptr == NULL) && (io_res->buffer_mode != 
@@ -385,6 +460,7 @@ size_t fwrite(const void* data, size_t blocksize, size_t blockcount,
                 io_res->error = true;
                 return 0;
             } else {
+                io_res->cur_pos += ret;
                 return ret / blocksize;
             }
             break;
@@ -408,6 +484,7 @@ size_t fwrite(const void* data, size_t blocksize, size_t blockcount,
                     io_res->error = true;
                     return 0;
                 } else {
+                    io_res->cur_pos += ret;
                     return ret / blocksize;
                 }
             }
@@ -429,6 +506,7 @@ size_t fwrite(const void* data, size_t blocksize, size_t blockcount,
                     io_res->error = true;
                     return 0;
                 } else {
+                    io_res->cur_pos += ret;
                     return ret / blocksize;
                 }
             } else {
@@ -496,11 +574,37 @@ int fputs(const char *str, FILE *io_res)
  */
 int fseek (FILE* io_res, long int offset, int origin)
 {
+    int ret;
+
     // Ungueltige Handles abfangen
     if (!is_valid_res(io_res)) {
         return -1;
     }
 
+    // Wenn innerhalb von einem Lesepuffer herumgesprungen wird, brauchen wir
+    // nichts neues von der Platte zu laden
+    if (io_res->buffer_writes == false) {
+        switch (origin) {
+            case SEEK_SET:
+                if (offset >= io_res->cur_pos &&
+                    offset < io_res->cur_pos + io_res->buffer_filled)
+                {
+                    io_res->buffer_pos = offset - io_res->cur_pos;
+                    return 0;
+                }
+                break;
+            case SEEK_CUR:
+                if (io_res->buffer_pos + offset >= 0 &&
+                    io_res->buffer_pos + offset < io_res->buffer_filled)
+                {
+                    io_res->buffer_pos += offset;
+                }
+                break;
+        }
+    }
+
+    // Ansonsten müssen wir den Puffer wegwerfen bzw. zurückschreiben
+    prepare_buffer(io_res, true);
     fflush(io_res);
 
     // ungetc-Buffer leeren
@@ -509,7 +613,23 @@ int fseek (FILE* io_res, long int offset, int origin)
         free(io_res->ungetc_buffer);
     }
 
-    return (lio_compat_seek(io_res->res, offset, origin) ? 0 : -1);
+    ret = (lio_compat_seek(io_res->res, offset, origin) ? 0 : -1);
+
+    if (ret == 0) {
+        switch (origin) {
+            case SEEK_SET:
+                io_res->cur_pos = offset;
+                break;
+            case SEEK_CUR:
+                io_res->cur_pos += offset;
+                break;
+            case SEEK_END:
+                io_res->cur_pos = ftell(io_res);
+                break;
+        }
+    }
+
+    return ret;
 }
 
 
@@ -522,6 +642,8 @@ int fseek (FILE* io_res, long int offset, int origin)
  */
 long ftell(FILE* io_res)
 {
+    long result;
+
     //Ungueltige Handles abfangen
     if (!is_valid_res(io_res)) {
         return EOF;
@@ -529,11 +651,11 @@ long ftell(FILE* io_res)
 
     if (IS_LIO2_FILE(io_res)) {
         int64_t pos = lio_seek(io_res->res->lio2_stream, 0, LIO_SEEK_CUR);
-        return (pos < 0 ? -1 : pos);
+        result = (pos < 0 ? -1 : pos);
+        goto out;
     }
 
     io_tell_request_t tell_request;
-    long result;
     tell_request.id = io_res->res->id;
     
     //Sonst könnte die Angabe falsch sein
@@ -548,7 +670,11 @@ long ftell(FILE* io_res)
     //Antwort und Daten wieder freigeben
     free(resp->data);
     free(resp);
-    
+
+out:
+    if (result >= 0) {
+        result += io_res->buffer_pos;
+    }
     return result;
 }
 
@@ -572,6 +698,12 @@ int feof(FILE* io_res)
         return 0;
     }
 
+    if (io_res->buffer_writes == false &&
+        io_res->buffer_pos < io_res->buffer_filled)
+    {
+        return 0;
+    }
+
     if (IS_LIO2_FILE(io_res)) {
         // FIXME: EOF ist hier eigentlich doof, aber irgend ein Idiot hat das
         // mal so implementiert und das wird teilweise so geprüft... ;-)
@@ -579,6 +711,7 @@ int feof(FILE* io_res)
     }
 
     //Auch hier könnte mit Daten im Buffer ein falsches Ergebnis rauskommen
+    prepare_buffer(io_res, true);
     fflush(io_res);
 
     return lio_compat_eof(io_res->res);
@@ -646,9 +779,17 @@ int fflush(FILE* io_res)
         return 0;
     }
 
+    // Wenn es ein Lesepuffer ist, gibt es auch nichts zu schreiben
+    if (!io_res->buffer_writes) {
+        return 0;
+    }
+
     size_t size = lio_compat_write(io_res->buffer_ptr,
         1, io_res->buffer_pos, io_res->res);
-    
+    if (size > 0) {
+        io_res->cur_pos += size;
+    }
+
     if (size == io_res->buffer_pos) {
         io_res->buffer_pos = 0;
         return 0;
@@ -668,6 +809,7 @@ int fflush(FILE* io_res)
  */
 int fpurge(FILE* io_res)
 {
+    prepare_buffer(io_res, true);
 	io_res->buffer_pos = 0;
     return 0;
 }
@@ -714,6 +856,8 @@ int setvbuf(FILE* io_res, char* buffer, int mode, size_t size)
 			io_res->buffer_ptr = NULL;
             io_res->buffer_pos = 0;
             io_res->buffer_size = 0;
+            io_res->buffer_filled = 0;
+            io_res->buffer_writes = true;
 			io_res->buffer_mode = IO_BUFFER_MODE_NONE;
 			break;
 			
@@ -722,6 +866,8 @@ int setvbuf(FILE* io_res, char* buffer, int mode, size_t size)
 			io_res->buffer_ptr = buffer;
 			io_res->buffer_pos = 0;
 			io_res->buffer_size = size;
+            io_res->buffer_filled = 0;
+            io_res->buffer_writes = true;
 			io_res->buffer_mode = IO_BUFFER_MODE_FULL;
 			break;
 		
@@ -730,6 +876,8 @@ int setvbuf(FILE* io_res, char* buffer, int mode, size_t size)
 			io_res->buffer_ptr = buffer;
 			io_res->buffer_pos = 0;
 			io_res->buffer_size = size;
+            io_res->buffer_filled = 0;
+            io_res->buffer_writes = true;
 			io_res->buffer_mode = IO_BUFFER_MODE_LINE;
 			break;
 		
-- 
1.7.7