[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