[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[tyndur-devel] [PATCH 14/22] 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