[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