[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[tyndur-devel] [PATCH v2 8/8] kernel2: Blockierendes Lesen
+ kernel2: lio_(p)read() blockiert jetzt, wenn es gar nichts lesen kann,
aber moredata noch gesetzt ist (d.h. es sonst -EAGAIN zurückgeben
würde).
Solange man sich nicht einloggt, verbraten die getterms jetzt nicht
mehr 100% CPU um die Tastatur zu pollen, sondern der Idle-Thread kommt
zum Zug.
Signed-off-by: Kevin Wolf <kevin@xxxxxxxxxx>
---
src/kernel2/include/lostio/client.h | 4 +--
src/kernel2/include/tasks.h | 1 +
src/kernel2/src/lostio/client.c | 48 ++++++++++++++++++++++++-----
src/kernel2/src/lostio/include/lostio_int.h | 11 +++++++
src/kernel2/src/lostio/tree.c | 6 ++++
src/kernel2/src/syscalls/lio_server.c | 5 ++-
src/kernel2/src/syscalls/lostio.c | 4 +--
7 files changed, 66 insertions(+), 13 deletions(-)
diff --git a/src/kernel2/include/lostio/client.h b/src/kernel2/include/lostio/client.h
index d3490f0..c7b3795 100644
--- a/src/kernel2/include/lostio/client.h
+++ b/src/kernel2/include/lostio/client.h
@@ -68,7 +68,7 @@ struct lio_stream* lio_open(struct lio_resource* res, int flags);
*
* @return Anzahl der gelesenen Bytes oder negativ im Fehlerfall
*/
-ssize_t lio_read(struct lio_stream* s, size_t bytes, void* buf);
+ssize_t lio_read(struct lio_stream* s, size_t bytes, void* buf, int flags);
/**
* Liest aus einem Stream aus, ohne die Position des streams zu benutzen oder
@@ -77,7 +77,7 @@ ssize_t lio_read(struct lio_stream* s, size_t bytes, void* buf);
* @return Anzahl der gelesenen Bytes oder negativ im Fehlerfall
*/
ssize_t lio_pread(struct lio_stream* s, uint64_t offset, size_t bytes,
- void* buf);
+ void* buf, int flags);
/**
* Schreibt in einen Stream
diff --git a/src/kernel2/include/tasks.h b/src/kernel2/include/tasks.h
index e17d22b..8fac5ad 100644
--- a/src/kernel2/include/tasks.h
+++ b/src/kernel2/include/tasks.h
@@ -52,6 +52,7 @@
#define PM_STATUS_WAIT_FOR_RPC 3
#define PM_STATUS_WAIT_FOR_LIO 4
#define PM_STATUS_WAIT_FOR_IO_REQUEST 5
+#define PM_STATUS_WAIT_FOR_DATA 6
typedef struct pm_process {
/// Die eindeutige Prozessnummer
diff --git a/src/kernel2/src/lostio/client.c b/src/kernel2/src/lostio/client.c
index 4673a27..8f3bcd1 100644
--- a/src/kernel2/src/lostio/client.c
+++ b/src/kernel2/src/lostio/client.c
@@ -92,7 +92,7 @@ static struct lio_resource* resolve_symlink(struct lio_resource* link,
return NULL;
}
- len = lio_read(stream, link->size, buf);
+ len = lio_read(stream, link->size, buf, 0);
lio_close(stream);
if (len < 0) {
@@ -288,11 +288,11 @@ fail:
*
* @return Anzahl der gelesenen Bytes oder negativ im Fehlerfall
*/
-ssize_t lio_read(struct lio_stream* s, size_t bytes, void* buf)
+ssize_t lio_read(struct lio_stream* s, size_t bytes, void* buf, int flags)
{
ssize_t result;
- result = lio_pread(s, s->pos_read, bytes, buf);
+ result = lio_pread(s, s->pos_read, bytes, buf, flags);
if (result > 0) {
s->pos_read += result;
}
@@ -302,11 +302,12 @@ ssize_t lio_read(struct lio_stream* s, size_t bytes, void* buf)
/**
* Liest aus einem Stream aus, ohne die Position des streams zu benutzen oder
- * zu veraendern.
+ * zu veraendern. Diese Funktion blockiert nie, sondern gibt -EAGAIN zurück,
+ * wenn es nichts zu lesen gibt.
*
* @return Anzahl der gelesenen Bytes oder negativ im Fehlerfall
*/
-ssize_t lio_pread(struct lio_stream* s, uint64_t offset, size_t bytes,
+ssize_t lio_pread_nonblock(struct lio_stream* s, uint64_t offset, size_t bytes,
void* buf)
{
ssize_t ret = 0;
@@ -361,6 +362,37 @@ ssize_t lio_pread(struct lio_stream* s, uint64_t offset, size_t bytes,
return ret;
}
+static void lio_pread_unblock_cb(void* opaque)
+{
+ pm_thread_t* t = opaque;
+
+ BUG_ON(t->status != PM_STATUS_WAIT_FOR_DATA);
+ t->status = PM_STATUS_READY;
+}
+
+/**
+ * Liest aus einem Stream aus, ohne die Position des streams zu benutzen oder
+ * zu veraendern. Diese Funktion blockiert, bis etwas gelesen werden kann.
+ *
+ * @return Anzahl der gelesenen Bytes oder negativ im Fehlerfall
+ */
+ssize_t lio_pread(struct lio_stream* s, uint64_t offset, size_t bytes,
+ void* buf, int flags)
+{
+ bool blocking = (flags & LIO_REQ_BLOCKING);
+ ssize_t ret;
+
+ ret = lio_pread_nonblock(s, offset, bytes, buf);
+ while (ret == -EAGAIN && blocking) {
+ notifier_add(&s->res_read->on_resize,
+ lio_pread_unblock_cb, current_thread, true);
+ pm_scheduler_kern_yield(0, PM_STATUS_WAIT_FOR_DATA);
+ ret = lio_pread_nonblock(s, offset, bytes, buf);
+ }
+
+ return ret;
+}
+
/**
* Schreibt in einen Stream
*
@@ -430,7 +462,7 @@ ssize_t lio_pwrite(struct lio_stream* s, uint64_t offset, size_t bytes,
old_flags = s->flags;
// FIXME Wenn das mal nicht racy ist...
s->flags |= LIO_READ;
- ret = lio_pread(s, offset_aligned, bytes_aligned, bounce);
+ ret = lio_pread(s, offset_aligned, bytes_aligned, bounce, 0);
s->flags = old_flags;
}
@@ -447,7 +479,7 @@ ssize_t lio_pwrite(struct lio_stream* s, uint64_t offset, size_t bytes,
// Offset zeigt jetzt auf das erste Byte nach dem letzten geschriebenen
if (ret > 0){
if (res->size < offset) {
- res->size = offset;
+ lio_resource_update_size(res, offset);
}
}
@@ -589,7 +621,7 @@ int lio_truncate(struct lio_stream* s, uint64_t size)
/* Anschliessend die Ressourcengroesse anpassen (drv->truncate kann das
* u.U. auch schon gemacht haben) */
- res->size = size;
+ lio_resource_update_size(res, size);
return 0;
}
diff --git a/src/kernel2/src/lostio/include/lostio_int.h b/src/kernel2/src/lostio/include/lostio_int.h
index a0f2947..33c055c 100644
--- a/src/kernel2/src/lostio/include/lostio_int.h
+++ b/src/kernel2/src/lostio/include/lostio_int.h
@@ -40,6 +40,7 @@
#include <syscall_structs.h>
#include "lostio/core.h"
+#include "notifier.h"
#include "tasks.h"
#define ROUND_TO_NEXT_BLOCK(bytes, blocksize) \
@@ -180,6 +181,13 @@ struct lio_resource {
bool resolvable;
bool retargetable;
+ /**
+ * Wird aufgerufen, wenn sich die Größe einer Ressource ändert (dies
+ * schließt Fälle ein, in denen moredata von true zu false wechselt, wenn
+ * dann statt -EGAIN das Dateiende gemeldet wird.
+ */
+ struct notifier* on_resize;
+
/** Id der Ressource fuer Userspace-Programme */
lio_usp_resource_t usp_id;
@@ -286,6 +294,9 @@ void lio_resource_remove_child(struct lio_resource* parent,
struct lio_node* lio_create_node(struct lio_resource* parent,
struct lio_resource* res, const char* name);
+/** Größe aktualisieren und on_size-Notifier ausführen */
+void lio_resource_update_size(struct lio_resource* res, uint64_t size);
+
/** Weist einer Ressource eine Userspace-ID zu */
void lio_usp_add_resource(struct lio_resource* res);
diff --git a/src/kernel2/src/lostio/tree.c b/src/kernel2/src/lostio/tree.c
index ee0e481..3fcd2c7 100644
--- a/src/kernel2/src/lostio/tree.c
+++ b/src/kernel2/src/lostio/tree.c
@@ -371,3 +371,9 @@ struct lio_node* lio_create_node(struct lio_resource* parent,
return n;
}
+/** Größe aktualisieren und on_size-Notifier ausführen */
+void lio_resource_update_size(struct lio_resource* res, uint64_t size)
+{
+ res->size = size;
+ notify(res->on_resize);
+}
diff --git a/src/kernel2/src/syscalls/lio_server.c b/src/kernel2/src/syscalls/lio_server.c
index 0ead479..5127d7a 100644
--- a/src/kernel2/src/syscalls/lio_server.c
+++ b/src/kernel2/src/syscalls/lio_server.c
@@ -262,7 +262,6 @@ int syscall_lio_srv_res_upload(struct lio_server_resource* resource)
}
res->tree = lio_usp_get_tree(resource->tree);
- res->size = resource->size;
res->blocksize = resource->blocksize;
res->readable = ((resource->flags & LIO_SRV_READABLE) ? 1 : 0);
res->writable = ((resource->flags & LIO_SRV_WRITABLE) ? 1 : 0);
@@ -278,6 +277,10 @@ int syscall_lio_srv_res_upload(struct lio_server_resource* resource)
}
res->opaque = resource->opaque;
+ /* Auch aufrufen falls sich die Größe nicht geändert hat: moredata könnte
+ * von true auf false gewechselt sein. */
+ lio_resource_update_size(res, resource->size);
+
return 0;
}
diff --git a/src/kernel2/src/syscalls/lostio.c b/src/kernel2/src/syscalls/lostio.c
index b060626..32efd4b 100644
--- a/src/kernel2/src/syscalls/lostio.c
+++ b/src/kernel2/src/syscalls/lostio.c
@@ -163,9 +163,9 @@ void syscall_lio_read(lio_usp_stream_t* stream_id, uint64_t* offset,
}
if (flags & LIO_REQ_FILEPOS) {
- *result = lio_read(fd->stream, bytes, buffer);
+ *result = lio_read(fd->stream, bytes, buffer, flags);
} else {
- *result = lio_pread(fd->stream, *offset, bytes, buffer);
+ *result = lio_pread(fd->stream, *offset, bytes, buffer, flags);
}
}
--
2.1.4