Disclaimer: Dieser Thread wurde aus dem alten Forum importiert. Daher werden eventuell nicht alle Formatierungen richtig angezeigt. Der ursprüngliche Thread beginnt im zweiten Post dieses Threads.
mother
Hallo allerseits ich hätte eine frage zur letzten Aufgabe mother:
Ich habe bis jetzt nur die connection-mt.c geschrieben, die request-http.c ist also aus der lib. Um mein Programm zu überprüfen bin ich mal mit valgrind ran, und bekomme folgenden output:
Zur Erklärung:
Zeile 93: Hier erstelle ich den jbuffer, dementsprechend wird hier natürlich allokiert
Zeile 113: Hier malloc ich speicher für ein array aus pthread objekten
Zeile 121: Hier werden die pthreads erzeugt und in das array aus zeile 113 eingetragen
Meine zwei fragen sind jetzt folgendes:
- Ist es nötig, dass ich mir einen sighandler schreibe, in dem ich dann vor dem beenden des Servers den jbuffer und mein malloc wieder free oder reicht das aus, das man sieht, dass diese strukturen bis zum ende des servers nicht verloren gegangen sind?
- Ist das normal, dass pthread_create in Zeile 121 eventuell speicher verliert oder könnte das an einem falschen nutzen der Funktion durch mich liegen?
was hast du mit den beiden semaphoren vor? und warum machst du ein array in das die threads eingetragen werden? denke das ist beides unnoetig - aber ohne gewaehr
dass der buffer und die threads noch speicherbedarf haben, sollte unvermeidlich sein. hast du [m]pthread_detach[/m] verwendet?
Die beiden Semaphoren stammen aus der Referenzimplementierung des jbuffers, die erstellt der beim create selbst
Ein array für die threads habe ich nur angelegt, damit ich eventuell noch eine Referenz für alle threads zur Verfügung habe, über die ich mit Ihnen interagieren kann, aber nachdem wir ansonsten eigentlich nichts mehr mit den Threads machen, könnte man das vermutlich auch einfach weglassen.
Nein [m]pthread_detach[/m] habe ich nicht verwendet, nachdem ich die man page davon gelesen habe könnte man das aber vermutlich gut machen^^
ja ok das mit den semaphoren macht sinn steht ja auch im valgrind output drin wo die herkommen… hab das leider nur unvollstaendig gelesen, weil ich mir ziemlich sicher war, dass die bei mir nicht auftauchen. leider kann ich das erst morgen nachpruefen
Die [m]mother[/m] ist ein Programm, das als sogenannter Dienst im System laufen soll - als ein Programm, das einmalig gestartet wird und dann quasi endlos läuft.
Eine Signalbehandlung für [m]SIGINT[/m] (Ctrl-C), die alles sauber abräumt, wäre zwar ne hübsche Sache, ist aber nicht notwendig. Wenn man’s ganz sauber machen wollte, bräuchte man dann auch gleich noch dieselbe Signalbehandlung für [m]SIGTERM[/m], … und für [m]SIGQUIT[/m], … und für [m]SIGUSR1[/m] und [m]SIGUSR2[/m], … und überhaupt! Ihr seht, wo das hinführt.
Essenziell ist, dass euer Programm kein fortschreitendes Speicherleck beinhaltet - das heißt, alle dynamisch allozierten Strukturen, die im Rahmen der Abarbeitung einer Verbindungsanfrage angelegt wurden, müssen nach deren Beendigung wieder restlos weggeräumt werden. Das gilt insbesondere auch für Fälle, in denen die Bearbeitung wegen eines Fehlers (z. B. 404) nicht abgeschlossen werden konnte.
Ansonsten geht eurem Programm - das wohlgemerkt für den Endlosbetrieb ausgelegt sein soll - früher oder später der Speicher aus.
Ok, ein fortschreitendes Leck ist nirgends zu beobachten^^
Inzwischen habe ich noch zwei Fragen:
- Warum ist beim clientSock den [m]handleConnection[/m] erhält nicht auch das [m]FD_CLOEXEC[/m] flag gesetzt? Sehe ich da etwas falsch, oder könnte es sehr leicht zu einer Racecondition mit dem exec aus der [m]handleRequest[/m] kommen bei der das exec passiert, bevor ich den clientSock auch auf [m]FD_CLOEXEC[/m] setzen kann?
- Gibt es eine möglichkeit einen socket zu [m]dup[/m]en und dabei direkt atomar [m]FD_CLOEXEC[/m] zu setzen, damit auch hierbei kein exec zwischen dem [m]dup[/m] und dem [m]fcntl[/m] reinpfuschen kann? Geht das eventuell mich [m]dup3[/m]?
Das siehst du richtig, das ist eine Racecondition. Das Problem ist, dass das [m]accept(3)[/m] dir den Dateideskriptor ohne [m]FD_CLOEXEC[/m] gibt, und du du das Flag erst setzen musst. Das ist also immer eine Racecondition. Die korrekte Lösung wäre [m]accept4(3)[/m], aber das ist Linux-spezifisch und nicht in POSIX.
Um die Racecondition klein zu halten, musst du [m]FD_CLOEXEC[/m] aber auf jeden Fall vor dem Einfügen in den Buffer setzen.
Selbes Problem wie beim [m]accept(3)[/m]. Ja, mit [m]dup3(3)[/m] geht das, aber auch das ist nicht in POSIX.
Wenn du motiviert bist, kannst du in dein Makefile einen Test einbauen, der nach [m]accept4(3)[/m] und [m]dup3(3)[/m] „sucht“ (einfach versuchen ein minimales Programm mit [m]accept4(3)[/m] zu linken, wenn das funktioniert, gibt es die Funktion; GNU autoconf macht das auch so - das kennst du vielleicht von den [m]./configure[/m] Ausgaben) und ein Makro definiert wenn es gefunden wird ([m]-DHAVE_ACCEPT4[/m] in den [m]CPPFLAGS[/m] z.B.). In deinem Programm schaust du dann, ob das Makro definiert ist ([m]#ifndef HAVE_ACCEPT4[/m]) und falls nicht, definierst du eine Fallbackfunktion mit selbem Namen, die das Flag manuell setzt (inklusive Racecondition).
Aber für die mother ist diese Racecondition akzeptabel, weil du das mit POSIX nicht wirklich lösen kannst.
Was hier so abenteuerlich klingt ist übrigens der Real World™-Ansatz, das Problem der Platformkompatibilität von Software zu lösen. Autotools, CMake, etc. machen das auch nicht anders.
Ja, es ist wirklich so frickelig, wie sichs anhört.
Okay vielen Dank erstmal für die Antworten, dann habe ich jetzt nur noch eine frage:
Wie genau sollte ich per [m]exec[/m] die Perl-Skripte starten?
Ich hab es bis jetzt wie folgt gemacht: [m]execl(path, “perl”, (char *) NULL)[/m] und das funktioniert, aber ich bin mir absolut nicht sicher, ob das so richtig ist, vor allem der teil für die args, also das “perl”…
Du solltest [m]perl[/m] (oder besser [m]/usr/bin/perl[/m]) mit dem Skript als erstes Argument starten.
Dein [m]execl()[/m] macht was anderes. Das startet das Skript mit [m]perl[/m] als [m]argv[0][/m]! Das ist nicht so sinnvoll.
Überleg dir aber trotzdem, warum deine Lösung funktioniert.
Einfach [m]execl(path, path, NULL);[/m].
Es dürfte trotzdem funktionieren, weil für die .pl-Dateien warscheinlich der Perl-Interpreter als Standard-Ausführer eingetragen ist?
Und wo genau befindet sich dieser Eintrag?
Tipp: Es hat nichts mit der Dateiendung zu tun (sowas gibt es unter Unix direkt erstmal nicht).
In der Datei. Schimpft sich Shebang
#!/usr/bin/perl
@kronos: Eigentlich sollte das EloquentProf herausfinden …
Hmm, ein Kernel mit [m]CONFIG_BINFMT_SCRIPT=n[/m] wäre doch auch mal eine Idee…
Aha… den Eintrag habe ich schon gesehen, wusste aber nicht wofür das gut ist xD
mit anderen worten ich kann in unix in praktisch jeder datei am anfang
#![path] benutzen um das ganze mit einem programm das unter path liegt auszuführen?
Exakt. Die Datei muss nur ausführbar sein.