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

[tyndur-devel] [PATCH v2 15/24] servmgr: Workaround für zyklische Abhängigkeiten



! Es kann passieren, dass Service A auf B wartet, der auf C wartet. Dann
  melden sich diese beide beim servmgr, der dann für B darauf warten
  soll, dass B gestartet ist, und für A, dass B fertig ist. Da týndur
  leider keine Popupthreads für IPC benutzt, existiert aber nur ein
  wartender Thread. Wenn A später als B angefragt hat, wird also A ewig
  auf B warten, da B nie weiterlaufen kann, auch wenn C fertig ist.
  Ein einfacher Workaround ist es, zu einem Zeitpunkt immer nur einem
  anfragenden Service/Prozess das Privileg zu gestatten, den servmgr
  selbst zu benutzen, um zu warten. Alle anderen bekommen ein EAGAIN,
  wenn der Zielservice noch nicht angemeldet ist, und müssen das Warten
  selber übernehmen (hier als wiederholte Anfragen bei servmgr
  implementiert).

Signed-off-by: Max Reitz <max@xxxxxxxxxx>
---
 src/modules/lib/servmgr.c   | 11 +++++++++--
 src/modules/servmgr/rpcif.c | 22 ++++++++++++++++++++--
 2 files changed, 29 insertions(+), 4 deletions(-)

diff --git a/src/modules/lib/servmgr.c b/src/modules/lib/servmgr.c
index 3909350..429be73 100644
--- a/src/modules/lib/servmgr.c
+++ b/src/modules/lib/servmgr.c
@@ -26,6 +26,7 @@
  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
+#include <errno.h>
 #include <string.h>
 #include <init.h>
 #include <rpc.h>
@@ -36,8 +37,14 @@ static pid_t servmgr_pid(void);
 
 bool servmgr_need(const char* service_name)
 {
-    return rpc_get_dword(servmgr_pid(), "NEEDSERV", strlen(service_name) + 1,
-        (char*) service_name);
+    int result;
+
+    do {
+        result = rpc_get_int(servmgr_pid(), "NEEDSERV",
+                             strlen(service_name) + 1, (char*) service_name);
+    } while (result == -EAGAIN);
+
+    return result == 1;
 }
 
 /**
diff --git a/src/modules/servmgr/rpcif.c b/src/modules/servmgr/rpcif.c
index 6bbce79..645c8c5 100644
--- a/src/modules/servmgr/rpcif.c
+++ b/src/modules/servmgr/rpcif.c
@@ -40,6 +40,8 @@
 #include <string.h>
 #include <stdio.h>
 #include <init.h>
+#include <errno.h>
+#include <lock.h>
 #include "servmgr.h"
 
 static void rpc_needserv(pid_t pid, uint32_t cid, size_t data_size, void* data);
@@ -64,7 +66,7 @@ static void rpc_needserv(pid_t pid, uint32_t cid, size_t data_size, void* data)
 
     // Pruefen ob der Name nullterminiert ist
     if (!data_size || (name[data_size - 1] != 0)) {
-        rpc_send_dword_response(pid, cid, 0);
+        rpc_send_int_response(pid, cid, 0);
         return;
     }
 
@@ -73,10 +75,26 @@ static void rpc_needserv(pid_t pid, uint32_t cid, size_t data_size, void* data)
     } else {
         // Noch nicht konfiguriert. Jetzt bleibt nur hoffen, dass der Dienst
         // schon geladen wurde, sich aber noch nicht registriert hat.
+
+        static volatile uint32_t semaphore;
+        if (locked_increment(&semaphore) > 0) {
+            locked_decrement(&semaphore);
+            // Wir können nicht mehrere gleichzeitig warten lassen, weil das sonst
+            // zyklische Abhängigkeiten geben könnte
+            if (service_running(name)) {
+                rpc_send_int_response(pid, cid, true);
+            } else {
+                rpc_send_int_response(pid, cid, -EAGAIN);
+            }
+            return;
+        }
+
         result = service_wait(name, 10000);
+
+        locked_decrement(&semaphore);
     }
 
-    rpc_send_dword_response(pid, cid, result);
+    rpc_send_int_response(pid, cid, result);
 }
 
 /**
-- 
2.6.3