Ich bins mal wieder. Neuer Thread, neues Problem: Ich muss SIGUSR1 (bzw. 2) an mein Programm senden können, aber ich kann mir nicht ggeneu vorstellen, wie das gehen soll.
Wie es ungefähr aussehen soll: Der Prozess forkt sich und beginnt mit dem Kind alive-Nachrichten auszutauschen (SIGALARM), und das alle 2 Sek. Wenn nun der Benützer SIGUSR1 sendet, terminiert der Vater und danach das Kind, weil es keine Antwort auf sein SIGALARM erhält.
Wie kann ich jetzt SIGUSR schicken? Das Einzige, was mir momentan einfällt, ist es über scanf zu machen. Etwas einlesen, und anhand dessen das Signal zu senden.
Wenn ich es richtig verstehe willst Du vom Kind-Prozess ein SIGUSR[12] an den Eltern-Prozess schicken? Wenn ja dann sende über den Kanal über den die 2 Prozesse miteinander kommunizieren ein Command (Wie der ausschaut ist Dir überlassen) und werte diesem im Vater-Prozess aus, wenn dieser Command also den Wert hat der signalisiert das es sich um einen SIGUSR[12] handelt, dann sende diese vom Eltern-Prozess aus direkt weiter und terminiere den Prozess.
Es ist so: Vater schickt dem Kind jede 2 Sek ne Nachricht, dass er lebt (einfach ein bool). Darauf antwortet das Kind, dass dieser auch noch lebt. So geht das Ganze hin und her, und zwar über zwei pipes.
Ich kann jetzt selber SIGUSR1 oder SIGUSR2 senden um den Vater (mit SIGUSR1) oder das Kind (mit SIGUSR2) zu terminieren. Der jeweils andere Prozess kriegt zunächst davon nichts mit und sendet trotzdem seine Nachricht in die pipe. Erst wenn keine Antwort kommt, terminiert dieser auch.
So. Ich glaub ich habe irgendeinen Denkfehler, denn bei mir steht fast die ganze Logik im Signal-handler. Aber mir fällt nicht ein wie ich das andrs lösen soll. Denn ausgelöst wird diese alive-Nachricht durch SIGALRM.
Also das Du die Kommunikation jetzt über Pipes machst ist zwar nicht schlimm jedoch denke ich an Deiner Stelle nicht die richtige Lösung
Schonmal über Sockets nachgedacht? Dann können Sich beliebig viele Kindprozesse „einklinken“ und Ping/Pong Commands zum Eltern-Prozess senden. Ebenfalls hast Du dann die Möglichkeit mit einem weiterem Programm dich in die Kommunikation einzuklinken und kannst dann die Nachricht loswerden die das beenden Deiner Prozesse veranlassen soll (so verstehe ich jetzt zumindestens Deine Anmerkung im Startpost das ein User dies veranlassen soll).
Ich hab auch mir mittlerweile einen Code ausgedacht.
#include<unistd.h>
#include<stdbool.h>
#include<sys/types.h>
#include<stdlib.h>
#include<signal.h>
typedef void (*sighandler_t)(int);
int pid = 1;
int mype1[2];
int mype2[2];
char input;
static bool status = true;
struct sigaction sa;
void sigalrm4f(int sig){
if(status == true){
status = false;
write(mype2[1], &status, sizeof(bool));
printf("Father: Hello, my child. I'm fine, and you?");
alarm(2);
}
else {
printf("Father: Oh woe! My child has died. *commits suicide*");
exit(0);
}
}
void sigalrm4c(int sig){
printf("Child: My father died! Cannot live anymore!");
exit(0);
}
void installsighandler(int sig, sighandler_t han){ //FEHLER
sa.sa_handler = han(sig);
// sigemptyset(&sa.sa_mask);
sa.sa_flags = 0;
sigaction(sig, &sa, NULL);
}
int main(){
pipe(mype1);
pipe(mype2);
pid = fork();
/*
father 0<---mype1---1child
father 1---mype2--->0 child
*/
if(pid != 0){
dup(mype1[0]);
dup(mype2[1]);
close(mype1[0]);
close(mype1[1]);
close(mype2[0]);
close(mype2[1]);
installsighandler(SIGALRM, sigalrm4f);
read(mype1[0], &status, sizeof(bool));
alarm(2);
}
if(pid == 0){
dup(mype1[1]);
dup(mype2[0]);
close(mype2[0]);
close(mype2[1]);
close(mype1[0]);
close(mype1[1]);
installsighandler(SIGALRM, sigalrm4c);
read(mype2[0], &status, sizeof(bool));
while(true){
if(status == false){
status = true;
write(mype1[1], &status, sizeof(bool));
printf("Child: Im alive, my father");
}
else if (status == true){
alarm(2);
}
}
}
return 0;
}
Im Grunde passiert das was ich ob schon beschrieben habe. Der ganze Austausch läuft über die status-variable. Beim Vater läutet der Wecker, und dann sieht er nach. Wenn status == true, dann lebt das Kind. Das Kind macht mit ner schleife, aber im Grunde das Gleiche. Hier lebt der Vater, wenn status == false.
Das mit SIGUSR hab ich noch nicht implementiert.
Ich bokomme aber Fehlermeldungen:
evgeni@D620:~$ bscc signal1.c
signal1.c: In function ‘installsighandler’:
signal1.c:40: error: invalid use of undefined type ‘struct sigaction’
signal1.c:42: error: invalid use of undefined type ‘struct sigaction’
signal1.c:43: warning: implicit declaration of function ‘sigaction’
Über die Ferien hab ich mir vorgenommen mal meinen Code zu revidieren, zu kommentieren und zu verschönern. In diesem Fall gibt es sogar ein ungelöstes Mysterium. Hoffe ihr könnt mir helfen zu kapieren was da passiert (bzw. nicht passiert).
Hab wieder dieses Programm mit Vater und Kind. Wie gehabt: Die beiden schicken sich Lebenszeichen in Form eines bool (genaueres im Kommentar).
So. Mit SIGUSRx kann ich einen der Prozesse killen, und der Andere sollte dessen Ableben mit ner Trauermeldung würdigen und dann selbst terminieren.
Wenn ich nun den Vater kille, jammert das Kind wie vorgesehen und terminiert. Wenn ich aber das Kind kille, passiert Folgendes: der Vater erkundigt sich wie es dem Kind gehe und…terminiert. Ohne dem Kind nachzuweinen. Und das ist mein Mysterium: warum terminiert dieser und durch was? SIGPIPE könnte man jetzt sagen, aber SIGPIPE blockiere ich in der sigmask.
Warum ich noch nicht glaube dass es an Pipes liegt, ist die Ausgabe:
(alarm recieved habe ich nur zu “Debugging”-Zwecken drin)
Father: Hello, my child. I’m fine, and you?
Child: Im alive, my father
alarm recieved
Father: Hello, my child. I’m fine, and you?
Child: Im alive, my father <- hier meldet sich das Kind zum letzten Mal
alarm recieved
Father: Hello, my child. I’m fine, and you? <- das ist die tatsächlich letzte Ausgabe, aber an dieser Stelle würde ich ein weiteres alarm recieved erwarten, gefolgt von:
Father: Oh woe! My poor child died. Cant go on like this!
Wer weiß Rat?
Meinen Code häng ich an.
Die SIGUSR-signale kann man mit dem Befehl 'kill -usr<1oder2> ’ senden (Linux-Shell!!).
SIGUSR1 terminiert den Vater
SIGUSR2 terminiert das Kind
(Würde eigentlich sowas mit der Windows-cmd auch gehen?)
Ich hab es jetzt nicht testen können, aber was mir gleich einfiel, es könnte eventuell daran liegen das der stdout noch nicht „geflushed“ wurde und Dir die Meldung von puts() damit verloren geht. Sowas hatte ich selbst schonmal und konnte ich durch nutzen von fprintf und einem darauffolgendem fflush beheben. Meine Vermutungen beliefen sich dann darauf das puts/putchar/printf gepuffert werden und erst nach erreichen einer bestimmten Puffergröße geflushed werden.
Usage:
fprintf(stdout, "a message with params like %d
", 5);
fflush(stdout);
Mit fflush(stdout) hab ichs schon probiert, das hab ich vergessen dazuzuschreiben, sorry. Gebracht hat es nichts Allerdings hab ich kein fprintf verwendet…aber das wär doch egal, da puts() ja stdout verwendet?
Was noch dagegen sprechen würde, dass noch etwas im Puffer übrigbleibt, ist dass eigentlich zwei Ausgaben fehlen. Es kann doch nicht sein dass da beide unterschlagen werden? Bevor die ein Ausgabe gepuffert wird, muss ja dieser geleert werden, oder irre ich mich?
Also es wird ja nicht nach Zeile gepuffert, sondern nach bytes. Und ich geh mal stark von aus das es auch am kill liegt warum keine Ausgabe mehr kommt, auch wenn Sie berechtigt wäre. Möglichweise unterschlägt Dir das Betriebssystem die Ausgabe (Eventuell weil dadurch Speicherlecks ausgenutzt werden könnten oder so).
Ich habe bei meinem vorherigen Post das kill völlig ausser acht gelassen, denn mein Problem damals was ich mit fflush beheben konnte war eben nicht weil ich einen Prozess gekillt hatte sondern weil dieser aus Java gestartet war und es an der Stelle zuviel gepuffert hat wonach Ausgaben zum Teil viel zu spät kamen als erwartet.
Wie gesagt denke ich mal es liegt am kill. Beim normalem terminieren des Programms sollte alles gehen wie erwartet. Versuch daher mal ohne kill zu arbeiten sondern nur mit senden des signals und terminiere Dein Programm wenn ein Signal ankam (Was ich eigentlich dachte das Du das von vornherein erreichen wolltest? ^^).
Naja, kill IST hier die normale Terminierung. Lass dich nicht vom Wort täuschen! Der Befehl kill sendet einfach ein Signal, was nicht heißen muss dass dieses Signal den Prozess abwürgt! Man könnte auch kill -alrm 1234, dann würde der Prozess 1234 einen SIGALRM erhalten. Ich weiß nicht wieso der Befehl so heißt, ich finde das extrem verwirrend. Vielleicht weil die Mehrheit der Signale den Prozess wirklich terminieren lassen oder wenn man beim kill nur die pid angibt (kill 1234) , das Default-Signal gesendet wird, und das wäre SIGTERM. Aber es sollte besser sendsig oder irgendwie so heißen.
Also ich “kille” den Prozess nicht, ich signalisiere ihm nur sich selber zu beenden.
Aber wieso sich der Vater beendet hab ich immernoch keinen Plan!.
EDIT: Gibt es einen anderen Weg ein Signal von der Konsole zu senden?
Da wird auch von einem Befehl „signal“(denke mal nicht in jeder Distribution vorhanden bzw. muss es nachinstalliert werden) gesprochen und bei kill von "kill -s ". Vllt. hilft Dir das weiter. habe leider kein Linux hier um es zu testen.
Gut Schuß
VuuRWerK
Edit: Doch, ich hab ein Linux hier, ein Debian Server. Werde den mal starten und selber einfach mal testen.
Ich habe Ubuntu hier, und zu signal gibts nur in Abschnitt 2 was, und das ist nur für die sighandler.
Bei kill aber steht in der Manpage dass man ‚kill -signal pid‘ oder ‚kill -s signal pid‘ schreiben kann.
P.S. Bei mir haben am Anfang diverse Manpages einfach gefehlt…musste lange nach den Paketen suchen, um diese nachzuinstallieren. Falls es auf deinem Server auch so sein sollte, das sind die 3: ‚manpages-dev‘ (es gibt auch ‚manpages-de-dev‘, aber die sind bissl dürftig), ‚manpages-posix‘ und ‚manpages-posix-dev‘. Hab nicht getestet inwieweit sich die beiden posix-pakete überschneiden, bei mir ist jedenfalls jetzt so ziemlich alles drauf was ich brauche