Hallo,
im Grunde geht es um den simple Windows-Named-Mutex Trick für Linux um
zu erkennen ob ein Programm schon mal gestartet wurde - nur mit der
Sicherheit das ein Terminate oder Absturz nicht den erneuten Start
blockiert (was in unserem Test-Szenario häufiger vorkommt)
eine einfache Datei reicht nicht weil ich die nicht löschen wenn ich
durch ein Plugin-Fehler terminiert werde
Es geht mir nicht darum die Abstürze zu korrigieren weil es um ein
Plugin-Loader-Tester geht der Plugins von anderen Entwicklern testet die
es nicht so genau nehmen mit der Qualität - deswegen auch das Testsystem
:)
Bisher habe ich folgende gefunden
Memory mapped file - scheinbar auch möglich das es nach dem Prozess-Ende
definitiv auch wieder vom Betriebssystem entfernt wird
oder mit Shared memory
gibt es da einen verlässlichen Trick wie ich sowas erreichen kann?
Tips?
Alexander schrieb:> reden wir hier von einem Linux PC? da lass es als cron job laufen
das bringt mir nichts - ich brauche eine verlässliche möglichkeit um
mehrfachstarts einens Prozesses zu verhindern - der darf nur einmal
aktiv sein
Problem: drum herum läuft noch ein Watchdog-Prozess dessen "läuft der
Prozess noch" Mechanismus sehr dürftig ist und hin und wieder laufen
dann zwei Prozesse, Absicherung per Datei scheitert daran das der
Prozess selbst auch gerne mal bei der Durchführung seiner Aufgabe
abstürzt (x Gründe)
ich kann (darf) den Top-Level Watchdog nicht aendern und kann die
Aufgabe des Prozesses selbst nicht beeinflussen, möchte aber das der
gesammte Testprozess so "stabil" wie möglich Dauerlauffähig ist um mit
meinen statistiken zu zeige das diese "Probleme" gar nicht so
unrelevant sind wie manche glauben mögen
Meine Software-Qualität ist hier nicht das Problem sondern die drum
herum liegenden Systeme
NichtWichtig schrieb:> wir nutzenpids=$(pidof progname)> um einen bestimmten Prozess zu finden.>> $pids läßt sich dann je-nach-dem abfragen/verwenden/auswerten.
wie schon geschrieben - den Watchdog kann ich nicht aendern
der ist Müll - aber ich muss das erstmal "beweisen", weil das andere
Team denkt Qualität hat was mit Bauchgefühl zu tun
Ich brauche nur eine verlassliche, Terminate sichere Lösung die in dem
Prozess verhindert das er nochmal hochfährt wenn er ein zweites mal
gestartet wird
auch wenn der Prozess dann abstürzt sollte er dann wieder starten
unter Windows reicht in der main "gibt es diesen benamten Mutex schon,
wenn ja raus hier" ansonsten benamten Mutex anlegen - 4 Zeiler,
Terminate, Absturz-Sicher
Du kannst doch einen cron job schreiben der Dateizugriffe überwacht, so
auch für Zugriff auf dein Programm. Erstellen und löschen von
Sperrdateien sollte jetzt nicht das Problem sein.
Alexander schrieb:> Du kannst doch einen cron job schreiben der Dateizugriffe> überwacht, so> auch für Zugriff auf dein Programm. Erstellen und löschen von> Sperrdateien sollte jetzt nicht das Problem sein.
ich habe auf die Umgebung keinen Einfluss - ich kann das nur in meinem
C/C++ Program mit Code lösen - und unter Windows ist es wie gesagt ein
4-Zeiler
cppbert schrieb:> eine einfache Datei reicht nicht weil ich die nicht löschen wenn ich> durch ein Plugin-Fehler terminiert werde
Ganz grob: In das (Hint: link(2) ist atomar) Lockfile die PID
reinschreiben, und beim Start wenn das Lockfile existiert überprüfen ob
es diese PID gibt. In /proc/<PID>/cmdline oder /proc/<PID>/environ kann
man auch noch etwas magic reinschreiben um zu prüfen ob diese PID
wirklich dieser Prozess ist.
Εrnst B. schrieb:> Einen abstrakten Unix-Socket aufmachen, beim zweiten "bind" gibt's> einen> Fehler:
Nice
ist das Terminate/Abbruchsfest? ich denke mal ja weil das OS den socket
dicht macht, oder?
cppbert schrieb:> ist das Terminate/Abbruchsfest? ich denke mal ja weil das OS den socket> dicht macht, oder?
musst aber bei fork, exec und co aufpassen, dass der nicht ungewollt an
Child-Prozesse vererbt wird.
also ggfs. noch ein O_CLOEXEC/SOCK_CLOEXEC flag mit reinbasteln.
Noch was zur flock Lösung: wenn dass Programm / Script ersetzt wird, ist
es eine andere Datei, die gelockt wird, dann kann es schief gehen. Falls
fas ein Problem ist, kann man statt dem Program / Script eine beliebige
andere Datei öffnen. z.B. in /var/lock/.
cppbert schrieb:> gibt es da einen verlässlichen Trick wie ich sowas erreichen kann?
Da braucht's keine Tricks.
Man macht's einfach so wie es alle machen.
Stichwort
1
/var/run
Wenn nicht vorhanden: Datei mit eigener PID schreiben
Wenn vorhanden: Prüfen ob PID passt, wenn ja läuft's bereits -> beenden.
Wenn nein, Datei mit eigener PID schreiben.
Ich empfehle wirklich flock zu nutzen. Es ist simpel, man muss sich
keine Sorgen um Race Conditions usw. machen, und man muss nichts
aufräumen. Und man kann den Lock sogar an andere Prozesse weitergeben,
wenn man will. Das hier ist auch eine der Sachen, für die flock da ist.
Und das ist auch, was Programme wie z.B. apt nutzen, wenn die was
exklusives machen wollen.
Εrnst B. schrieb:> Einen abstrakten Unix-Socket aufmachen, beim zweiten "bind" gibt's einen> Fehler:>
Wollte ich auch gerade vorschlagen. Habe ich schon öfter benutzt.
cppbert schrieb:> Alexander schrieb:>> reden wir hier von einem Linux PC? da lass es als cron job laufen>> das bringt mir nichts - ich brauche eine verlässliche möglichkeit um> mehrfachstarts einens Prozesses zu verhindern - der darf nur einmal> aktiv sein
Vielleicht einen Socket erzeugen und bind(2)en? Wenn der bind(2)
fehlschlägt, also -1 zurückgibt, ist die Adresse vermutlich "already in
use" und errno sollte (IIRC) auf 98 stehen. Wenn der Prozess regulär
beendet wird, schließt er den Socket, und bei Abstürzen räumt das
Betriebssystem den Socket automatisch ab. Nur so ne Idee, YMMV.
Ansonsten gibt es für Linux Programme wie run-one(1), das funktioniert
aber nur, wenn die Aufrufparameter immer gleich sind. Wenn Dein Programm
mit verschiedenen Parametern aufgerufen wird, hilft vielleicht flock(1).
cppbert schrieb:> ich kann (darf) den Top-Level Watchdog nicht aendern und kann die> Aufgabe des Prozesses selbst nicht beeinflussen, möchte aber das der> gesammte Testprozess so "stabil" wie möglich Dauerlauffähig ist um mit> meinen statistiken zu zeige das diese "Probleme" gar nicht so> unrelevant sind wie manche glauben mögen
Entweder hältst du dich für klüger als alle anderen oder eure
Architektur ist Schrott.
In beiden Fällen wird sich am Problem nichts ändern.
Ein T. schrieb:> Vielleicht einen Socket erzeugen und bind(2)en? Wenn der bind(2)> fehlschlägt, also -1 zurückgibt, ist die Adresse vermutlich "already in> use" und errno sollte (IIRC) auf 98 stehen. Wenn der Prozess regulär> beendet wird, schließt er den Socket, und bei Abstürzen räumt das> Betriebssystem den Socket automatisch ab. Nur so ne Idee, YMMV.
siehe Idee von Εrnst B. ein paar Post vorher
Robert Blanko schrieb:> cppbert schrieb:>> ich kann (darf) den Top-Level Watchdog nicht aendern und kann die>> Aufgabe des Prozesses selbst nicht beeinflussen, möchte aber das der>> gesammte Testprozess so "stabil" wie möglich Dauerlauffähig ist um mit>> meinen statistiken zu zeige das diese "Probleme" gar nicht so>> unrelevant sind wie manche glauben mögen>> Entweder hältst du dich für klüger als alle anderen
nicht alle :)
> oder eure Architektur ist Schrott.
Das ist ein Test-System das Schrott erkennen soll
und ich will mehrere Beweise erbringen zur Qualität des ganzen
> In beiden Fällen wird sich am Problem nichts ändern.
zuerst das Problem verständlich machen, mit Fakten und Zahlen
dann aufräumen
cppbert schrieb:> Ein T. schrieb:>> Vielleicht einen Socket erzeugen und bind(2)en? Wenn der bind(2)>> fehlschlägt, also -1 zurückgibt, ist die Adresse vermutlich "already in>> use" und errno sollte (IIRC) auf 98 stehen. Wenn der Prozess regulär>> beendet wird, schließt er den Socket, und bei Abstürzen räumt das>> Betriebssystem den Socket automatisch ab. Nur so ne Idee, YMMV.>> siehe Idee von Εrnst B. ein paar Post vorher
Tja, er war schneller als ich. ;-)
Norbert schrieb:> Stichwort/var/run> Wenn nicht vorhanden: Datei mit eigener PID schreiben> Wenn vorhanden: Prüfen ob PID passt, wenn ja läuft's bereits -> beenden.> Wenn nein, Datei mit eigener PID schreiben.
Das ist eigentlich der klassische Standard-Weg, der nebenbei noch den
Vorteil hat, dass man erkennt, ob das Programm ordnungsgemäß beendet
wurde oder abgestürzt ist.
Rolf M. schrieb:> Das ist eigentlich der klassische Standard-Weg
ja, und portabel zwischen verschiedenen Unix-Geschmacksrichtungen.
Dafür leicht sabotierbar, "rm /var/run/xxx.pid".
Das abstract unix socket ist Linux-Only.
das File-Lock auf dem executable erfordert ein /proc/-Dateisystem
(zumindest in dem Beispiel von DPA), und hilft nicht gegen verschiedene
Versionen oder Kopien vom Programm.
Wie so oft, "it depends", was denn nun die beste Lösung für das Problem
von cppbert ist.
Das er sich scheinbar gegen andere Entwickler auf derselben Maschine
(evtl. sogar mit root-Rechten) "verteidigen" will, macht die Sache etwas
komplizierter.
Εrnst B. schrieb:> Rolf M. schrieb:>> Das ist eigentlich der klassische Standard-Weg>> ja, und portabel zwischen verschiedenen Unix-Geschmacksrichtungen.> Dafür leicht sabotierbar, "rm /var/run/xxx.pid".
Meiner Meinung nach ist dieser klassische Weg ein Relikt von SysV-Init,
das für einige Daemons eine Möglichkeit haben mußte, den Prozeß
wiederzufinden. Leider ist diese Methode nicht atomar -- das war bei
SysV-Init eher irrelevant, könnte es aber für den Anwendungsfall des TO
sein.
> Das abstract unix socket ist Linux-Only.
Es geht auch mit einem TCP- oder UDP-Socket auf localhost -- zu dem
Preis natürlich, daß man diesen Port "verschwendet".
> das File-Lock auf dem executable erfordert ein /proc/-Dateisystem> (zumindest in dem Beispiel von DPA), und hilft nicht gegen verschiedene> Versionen oder Kopien vom Programm.
Und es braucht die entsprechenden Permissions auf /proc/self/exe, was
auch nicht immer gegeben sein muß.
> Wie so oft, "it depends", was denn nun die beste Lösung für das Problem> von cppbert ist.
Ja...
> Das er sich scheinbar gegen andere Entwickler auf derselben Maschine> (evtl. sogar mit root-Rechten) "verteidigen" will, macht die Sache etwas> komplizierter.
Naja, wenn die absichtlich etwas Destruktives machen und deswegen etwas
fehlschlägt, hat er doch seinen gewünschten Beweis.
cppbert schrieb:> eine einfache Datei reicht nicht weil ich die nicht löschen wenn ich> durch ein Plugin-Fehler terminiert werde
Hmm, gibts da nicht sowas wie atexit() unter den Unixen wo man sich
draufklemmen kann? Halt wie beim Windows-DllMain/PROCESS_DETACH.
Prinzipiell find ich auch lock-Files den richtigen Weg. Die IPC geht
aber wohl auch über Pipes (unistd.h/pipe()) - macht aber imho nur Sinn,
wenn Daten zu übertragen sind. Sonst sollte doch eigentlich ein Lockfile
ausreichen.
db8fs schrieb:> cppbert schrieb:>> eine einfache Datei reicht nicht weil ich die nicht löschen wenn ich>> durch ein Plugin-Fehler terminiert werde>> Hmm, gibts da nicht sowas wie atexit() unter den Unixen wo man sich> draufklemmen kann? Halt wie beim Windows-DllMain/PROCESS_DETACH.
Das funktioniert nur, wenn das Programm normal beendet wird.
Ein T. schrieb:> Meiner Meinung nach ist dieser klassische Weg ein Relikt von SysV-Init,> das für einige Daemons eine Möglichkeit haben mußte, den Prozeß> wiederzufinden. Leider ist diese Methode nicht atomar -- das war bei> SysV-Init eher irrelevant, könnte es aber für den Anwendungsfall des TO> sein.
link(2) ist atomar.In Shellscripten nimmt dafür mv.
Ein T. schrieb:>> Hmm, gibts da nicht sowas wie atexit() unter den Unixen wo man sich>> draufklemmen kann? Halt wie beim Windows-DllMain/PROCESS_DETACH.>> Das funktioniert nur, wenn das Programm normal beendet wird.
Hmm, na ja, die guten alten signals abzufangen sollte aber schon
eigentlich schon gehen, selbst wenn's irgendeine ultraspeziale
Spezialkomponente ist.
Muss eben dann der Plugin-Host die Signals weiterverteilen an die
Komponente.
Bin mir auch noch nicht sicher, ob ich das Problem ganz verstanden hab.
Was soll der Plugin-Host denn erkennen können: (a) ob ein Subprozess
wegkachelt oder (b) ob er selber abstürzt, wenn er eine dynamische
Library ausführt oder (c) um zu vermeiden, dass er selber doppelt
instanziiert wird.
Für (a) über's PID-Interface braucht man meiner Meinung nach kein
Lockfile - machste den Prozess auf, kannste auch monitoren/verwalten, ob
das Ding weggeraucht ist oder nicht (und bei Bedarf den
Resourcen-Cleanup durchführen)
Für (b) geht auch, aber halt eben über das signals-IPC-Interface - bei
SIGKILL oder so, halt dann den Cleanup machen und das Lockfile löschen.
Für (c) hilft dann auch ein ganz normales Lockfile, wenn die anderen
beiden Fälle abgehandelt sind.
Danke für die vielen Tips - ich hab jetzt den Socket-Vorschlag von Εrnst
B. in verwendung - macht bisher gute arbeit
db8fs schrieb:> Bin mir auch noch nicht sicher, ob ich das Problem ganz verstanden hab.> Was soll der Plugin-Host denn erkennen können: (a) ob ein Subprozess> wegkachelt oder (b) ob er selber abstürzt, wenn er eine dynamische> Library ausführt oder (c) um zu vermeiden, dass er selber doppelt> instanziiert wird.
mehr oder minder b+c
mein Prozess läd dynamische libraries die Abstürzen können - da erkenne
ich sauber, und mein Prozess wird aber noch von einem Buggy Watchdog
gestartet dessen implementierung nicht gut ist und mich manchmal zweimal
startet
Ich möchte Aufzeige das die Plugin-Absturz-Rate nicht gering ist und die
Watchdog-Doppelstarts auch deutlich keine Einbildung sind :)
Εrnst B. schrieb:> das File-Lock auf dem executable erfordert ein /proc/-Dateisystem> (zumindest in dem Beispiel von DPA), und hilft nicht gegen verschiedene> Versionen oder Kopien vom Programm.
Die Datei kann man beliebig wählen. Man kann da also auch einfach z.B.
/var/lock/meinprogram.lock oder /var/run/meinprogram.lock eingeben, oder
worauf auch immer man genug Berechtigungen hat. Statt /proc/self/exe.
Beim Open dann eventuell noch ein O_CREAT hinzufügen, damit die Datei
auch automatisch erstellt wird falls noch nicht vorhanden.
Das selbe auch beim shell script, dass da die Datei automatisch erstellt
wird nimmt man dann halt >> statt <. Und das "$0" durch den Pfad der
Datei ersetzen.
Noch was zur unix socket variante. Ich bin mir nicht sicher, ob es der
IPC oder der Network Namespace war, aber man kann es mehrfach in
unterschiedlichen Namespaces starten, z.B. mit "unshare". Systemd kann
das Zeugs natürlich auch isolieren.
DPA schrieb:> Die Datei kann man beliebig wählen. Man kann da also auch einfach z.B.> /var/lock/meinprogram.lock oder /var/run/meinprogram.lock eingeben, oder> worauf auch immer man genug Berechtigungen hat. Statt /proc/self/exe.> Beim Open dann eventuell noch ein O_CREAT hinzufügen, damit die Datei> auch automatisch erstellt wird falls noch nicht vorhanden.
... und natürlich auch O_EXCL, damit der Prozeß exklusiven Zugriff auf
die Datei erhält und dadurch die Atomizität sichergestellt wird. Aber
jede Lösung mit Lock- oder Pidfiles ist nicht atomar und erfordert
zudem, daß der Prozeß korrekt hinter sich aufräumt, also regulär beendet
wird. Unter SysV-Init waren solche verwaisten Lock- und Piddateien ja
kein ganz seltenes Problem, sogar ohne Atomizität.
Wenn eine verwaiste Lock- oder Piddatei einen Neustart des Programms
unseres TO cppbert verhindert, dann werden nicht die Entwickler des
Watchdog, sondern der TO höchstpersönlich für Probleme verantwortlich
gemacht. Das ist aber nicht das Ziel unseres TO, vermute ich mal.
DPA schrieb:> Noch was zur unix socket variante. Ich bin mir nicht sicher, ob es der> IPC oder der Network Namespace war, aber man kann es mehrfach in> unterschiedlichen Namespaces starten, z.B. mit "unshare". Systemd kann> das Zeugs natürlich auch isolieren.
Das gilt für Deine dateibasierten Lösungsansätze aber ganz genauso,
insofern sehe ich darin keine Vorzüge.
Ein T. schrieb:> Aber jede Lösung mit Lock- oder Pidfiles ist nicht atomar und erfordert> zudem, daß der Prozeß korrekt hinter sich aufräumt, also regulär beendet> wird.
Nein. Es wird PID-File genannt, weil es als Inhalt die PID des Prozesses
enthält, der sie erzeugt hat. Damit kann man nachsehen, ob der Prozess
noch lebt und sicherheitshalber noch, ob das zugehörige Executable das
selbe ist. Wenn nicht, ist er abgestürzt. Man kann also die drei Fälle
"Prozess läuft", "Prozess läuft nicht, wurde regulär beendet" und
"Prozess ist abgestürzt" unterscheiden. Soweit ich den TE verstanden
habe, braucht er auch alle drei Fälle. Die anderen Lösungen vermögen
nicht, den Absturz zu erkennen.
Rolf M. schrieb:> Nein. Es wird PID-File genannt, weil es als Inhalt die PID des Prozesses> enthält, der sie erzeugt hat. Damit kann man nachsehen, ob der Prozess> noch lebt und sicherheitshalber noch, ob das zugehörige Executable das> selbe ist. Wenn nicht, ist er abgestürzt.
...oder hat eine Funktion aus der execve(2)-Familie aufgerufen, aber das
gerät jetzt ein
> Man kann also die drei Fälle> "Prozess läuft", "Prozess läuft nicht, wurde regulär beendet" und> "Prozess ist abgestürzt" unterscheiden. Soweit ich den TE verstanden> habe, braucht er auch alle drei Fälle. Die anderen Lösungen vermögen> nicht, den Absturz zu erkennen.
Mir ist schon klar, warum ein Pidfile so heißt, wie es heißt, und auch,
wie sowas funktioniert. Trotzdem vielen Dank für die Erklärung. Was ich
allerdings noch nicht verstanden habe, ist, wie Du die Atomizität
sicherstellen möchtest. Denn wenn ich das richtig verstanden habe, ist
das ja kein ohnehin seriell ablaufendes SysV-Init, sondern irgendeine
Art CI/CD-System, das durchaus auf die Idee kommen könnte, das Programm
des TO mehrmals gleichzeitig zu starten.
Ein T. schrieb:> Was ich> allerdings noch nicht verstanden habe, ist, wie Du die Atomizität> sicherstellen möchtest. Denn wenn ich das richtig verstanden habe, ist> das ja kein ohnehin seriell ablaufendes SysV-Init, sondern irgendeine> Art CI/CD-System, das durchaus auf die Idee kommen könnte, das Programm> des TO mehrmals gleichzeitig zu starten.
Wenn ich da mal rein grätschen darf…
Für Program xyz:
Mit tempfile eine Datei mit Zufallsnamen in ›/var/run/xyz/‹ erzeugen.
PID reinschreiben.
Mit link einen Hardlink auf xyz.pid erzeugen. (Atomar)
Wenn das ohne Fehler klappt, war man Erster:
unlink tempfile
Alles gut
Wenn das nicht klappt, gibt's xyz.pid schon:
xyz.pid lesen und die enthaltene PID prüfen.
…
Ein T. schrieb:> ... und natürlich auch O_EXCL, damit der Prozeß exklusiven Zugriff auf> die Datei erhält und dadurch die Atomizität sichergestellt wird.
Nein, es ist beabsichtigt, dass mehrere Prozesse die Datei anlegen oder
öffnen können. Dass soll nicht verhindert werden. Ich arneite dort mit
einem echten lock, nicht mit dem O_EXCL hack.
> Aber jede Lösung mit Lock- oder Pidfiles ist nicht atomar und erfordert> zudem, daß der Prozeß korrekt hinter sich aufräumt, also regulär beendet> wird.
Nein, auch das ist bei meiner Variante mit flock nicht nötig. Der
Prozess muss schon weg / beendet werden, aber auch wenn das per kill -9
oder OOM killer oder sonst wie passiert, ist der Lock automatisch wieder
freigegeben.
Naja, sollte es aber mal nicht möglich sein, den Prozess abzuschiessen,
weil es im kernel im non-interruptable sleep hängen geblieben ist, kann
man notfalls noch die Datei löschen. Der lock ist ja auf der Inode, und
nicht dem link.
Bei der unix socket Variante hingegen wäre man dann vermutlich
aufgeschmissen, und müsste rebooten.
Alexander schrieb:> Echt, kann man den selben Dateinamen mehrfach vergeben in verschiedenen> Mount Namespaces?
Nicht ganz. Der selbe Pfad im selben Dateisystem ist immernoch die
selbe Datei. Aber welches Dateisystem wo gemountet ist, sowie welcher
Teil davon, kann völlig anders sein, der selbe Pfad aus Anwendunssicht
kann damit zu einem ganz anderen Link und Datei auf einem ganz anderen
Dateisystem führen. Es ist auch möglich, einzelne Dateien zu mounten,
oder / selbst zu mounten/ersetzen (das machen container). Ausserdem ist
das auch als normaler user möglich.
Gut das ist klar, aber hat ja mit Namespaces nix zu tun. Aber ich hatte
das eh mißverstanden. Es reicht ja wenn eine Sperrdatei unsichtbar ist,
auch wenn sie nur einmal existiert. Man müsste also zum prüfen noch
versuchen diese anzulegen, wenn es fehl schlägt existiert sie schon.
im shell script mache ich es immer so
DPA schrieb:> Nein, auch das ist bei meiner Variante mit flock nicht nötig. Der> Prozess muss schon weg / beendet werden, aber auch wenn das per kill -9> oder OOM killer oder sonst wie passiert, ist der Lock automatisch wieder> freigegeben.
Bitte entschuldige, aber dann möchte ich Deine Variante gerne sehen,
bitte.
Denn mit BSD-Locks (flock(2)) funktioniert das bei mir nicht. Wenn ein
Prozeß, der ein exklusives Lock (LOCK_EX) hält, irregulär beendet wird
(Ctrl-c reicht aus), also sein Lock nicht freigibt, bleibt das Lock
bestehen. Jeder folgende Aufruf bleibt in flock(2) hängen, bis die Datei
manuell entfernt wird. Vielleicht habe ich aber etwas übersehen, das
will ich nicht ausschließen.
Bezogen auf die Situation des TO wäre das aber fatal. Immerhin möchte
er, wenn ich das richtig verstanden habe, Software testen. Solchen Tests
ist inhärent, daß sie mitunter fehlschlagen können und der Prozeß
abstürzt, also nicht mehr hinter sich aufräumen kann -- was zu dem oben
beschriebenen Verhalten führen würde: das Lock bliebe bestehen und
weitere Aufrufe des Programms blieben im flock(2) hängen. Das würde
allerdings auf den TO zurückfallen anstatt auf den Watchdog seiner
Kollegen, dessen Dysfunktionalität der TO doch belegen möchte.
Norbert schrieb:> Wenn ich da mal rein grätschen darf…> Für Program xyz:> Mit tempfile eine Datei mit Zufallsnamen in ›/var/run/xyz/‹ erzeugen.> PID reinschreiben.> Mit link einen Hardlink auf xyz.pid erzeugen. (Atomar)> Wenn das ohne Fehler klappt, war man Erster:> unlink tempfile> Alles gut> Wenn das nicht klappt, gibt's xyz.pid schon:> xyz.pid lesen und die enthaltene PID prüfen.> …
Stimmt, das geht (auch wenn tempfile(1) ein Shellbefehl ist ich in C/C++
natürlich mk(o)stemp(3) benutzen würde), aber das Aufräumproblem sehe
ich dabei leider immer noch. Was passiert, wenn der Prozeß abraucht und
nicht hinter sich aufräumen kann?
Ein T. schrieb:> DPA schrieb:>> Nein, auch das ist bei meiner Variante mit flock nicht nötig. Der>> Prozess muss schon weg / beendet werden, aber auch wenn das per kill -9>> oder OOM killer oder sonst wie passiert, ist der Lock automatisch wieder>> freigegeben.>> Bitte entschuldige, aber dann möchte ich Deine Variante gerne sehen,> bitte.
Einfach hoch scrollen:
Beitrag "Re: C/C++, Linux: Veriegelung das ein Prozess nur genau 1 mal läuft"
Ich pass es dir auch noch für ein separates lock file an, damit du da
auch nichts falsch machen kannst:
1
#define _DEFAULT_SOURCE
2
#include<sys/file.h>
3
#include<unistd.h>
4
#include<stdio.h>
5
#include<errno.h>
6
intmain(){
7
// Remove O_CLOEXEC if other processes shall inherit the locked fd
Ein T. schrieb:> Denn mit BSD-Locks (flock(2)) funktioniert das bei mir nicht. Wenn ein> Prozeß, der ein exklusives Lock (LOCK_EX) hält, irregulär beendet wird> (Ctrl-c reicht aus), also sein Lock nicht freigibt, bleibt das Lock> bestehen. Jeder folgende Aufruf bleibt in flock(2) hängen, bis die Datei> manuell entfernt wird. Vielleicht habe ich aber etwas übersehen, das> will ich nicht ausschließen.
Das funktioniert definitiv. Ich habe flock schon oft verwendet und
Ausgiebig getestet. Wenn der Prozess beendet wird, ganz egal wie,
schliesst das den File Deskriptor, und nach dem schliessen des letzten
Filedeskriptors der gelockten File Description, gibt das den Lock frei.
Ein T. schrieb:> ist ich in C/C++> natürlich mk(o)stemp(3) benutzen würde
Da hast du natürlich recht. War wohl gedanklich noch ein Überbleibsel
der vielen Bash-Diskussionen hier. ;-)
Ein T. schrieb:> Was passiert, wenn der Prozeß abraucht und> nicht hinter sich aufräumen kann?
Völlig egal. In den einsamen Fragmenten steht in der Datei eine PID
drin. Wenn man die beim nächsten Start prüft, wird man sehen das sie
entweder gar nicht existiert oder aber einem völlig anderen Prozess
gehört. So kann man feststellen das es das letzte mal wohl geraucht hat.
Dann räumt man kurz den alten Schmutz weg und beginnt einfach erneut.
DPA schrieb:> Das funktioniert definitiv.
Tatsache, tut es, wegen mode = S_IWUSR | S_IRUSR. Mit mode = 0 gibt es
(natürlich) einen ENOPERM, wenn der zweite Prozeß die Datei öffnen will,
oder ein Prozeß seine Lockdatei nicht abgeräumt hat. Trotzdem finde ich
es... irgendwie eleganter, diese Angelegenheit auf eine exklusive,
kernelverwaltete Ressource wie einen abstrakten UNIX Domain- oder
TCP/IP-Socket zu legen -- ist aber nur so ein Gefühl und sicher auch
eine Folge davon, daß alleine Linux drei miteinander inkompatible
Dateilock-Mechanismen hat und jedes UNIX dabei seine eigenen subtilen
Eigenheiten besitzt.
PS: Ach so, entschuldige: lieben Dank für Deine erhellende Antwort!
Edit: PS hinzugefügt.