Ich hab mir in den letzten 2 Wochen mal Gedanken zu RPC gemacht und heute eine Implementierung für mein OS geschrieben. Meine Implementierung sieht (mal alle lightOS spezifischen Details weggelassen so aus): Ein thread registriert einen RPC-Handler, welcher von anderen Threads aufgerufen werden kann. Sobald ein RPC-Aufruf reinkommt wird der Registerinhalt des threads, welcher den RPC-Handler registriert hat, gespeichert, ein paar Parameter auf den Stack gepusht und dann beim RPC-Handler mit der Ausführung begonnen. Ist der RPC-Handler fertig werden wird der alte Registerinhalt wiederhergestellt und mit der Ausführung an der alten stelle weitergemacht. (das ist afaik mit der LOST IPC vergleichbar)
Nun hab ich folgendes Problem: Es gibt in jedem Thread bestimmte Bereiche, die atomisch ausgeführt werden müssen, zB best. Teile von malloc, das pushen auf einen vector, das anhängen an eine Liste, etc... Da diese Sachen nicht innerhalb von einer Instruktion geschehen, könnten sie von einem RPC-Aufruf unterbrochen werden. Wenn jetzt aber der RPC-Handler seinerseits eine dieser Funktionen aufruft, dann könnte es krachen, zB könnten Speicherbereiche doppelt alloziert werden, freie Speicherbereiche verloren gehen oder der Zustand der Liste/des Vectors inkonsistent werden. In multithreading anwendungen würde man das über mutex/futex, Semaphore oder Semaphoren regeln, aber das geht in diesem Fall nicht, da bei allen diesen Synchronisationsmethoden die möglichkeit bestehen muss, dass der Codebereich, welcher den Lock hat, solange ausgeführt werden muss, bis dieser Lock wieder frei ist. Da aber der RPC-Handler die weitere Ausführung unterbrochen hat und erst nach dem RPC-Handler die Ausführung dort weitergeht, können oben genannte Methoden nicht verwendet werden ohne das es nicht zu einem Deadlock kommt.
Die einzigen Lösungen die ich sehe:
* spezielle Bereiche des Threads RPC'bar bzw. der umgekehrte Fall nicht-RPC'bar machen => viel Aufwand, portierbarkeit von bestehendem Code?
* RPC-Handler nichts derartiges machen lassen => schränkt zu sehr ein
* Popup-Threads: Für jeden RPC-Call einen Thread erstellen bzw. einen eigenen bestehenden Thread weiternutzen. Dann kann man solche Probleme wieder über die ganz normale Synchronisation von Multithreadinganwendungen lösen.
* Thread Migration: fast das gleiche wie Popup-Thread. Der unterschied ist nur, dass man den aufrufenden thread in den Kontext des aufzurufenden Prozesses verschleppt und dann den RPC-Handler ausführt. Damit spart man sich die Kosten der Threaderstellung, aber dadurch wird die RPC wieder synchron.
Mir gefallen die ersten beiden Lösungen überhaupt nicht und die letzten beiden kann man nunmal auch über message-passing und multithreading lösen ohne soviel aufwand betreiben zu müssen. Fällt evtl. jemandem noch eine andere Lösung ein, wie man RPC realisieren könnte?