Posted on

Übung 3

UNIX-Signale, Nebenläufigkeit, Duplizieren von Dateideskriptoren, Aufgabe 3

FolienAufgabe (rush)API-Doku (rush)

DISCLAIMER: Die Beispiele stehen hier so, wie in der Übung gemeinsam erarbeitet. Der Code lässt sich nicht eins zu eins zur Abgabe kopieren. Der Einfachheit halber ist einiges abgekürzt und es fehlen unter anderem einige Fehlerbehandlungen.

Beispiel: sigexample

Ein Program, das auf drei SIGUSR1 Signale wartet und sich dann beendet:

#include <stdio.h>
#include <signal.h>

static volatile int event = 0;

static void handleSIGUSR1() {
	event++;
}

static void waitForSIGUSR1() {
	puts("Waiting for SIGUSR1...");
	sigset_t mask;
	sigset_t oldMask;
	sigemptyset(&mask);
	sigaddset(&mask, SIGUSR1);
	sigprocmask(SIG_BLOCK, &mask, &oldMask);
	while (event < 3) {
		sigsuspend(&oldMask);
		printf("%d...", event);
		fflush(stdout);
	}
	event = 0;
	sigprocmask(SIG_SETMASK, &oldMask, NULL);
	puts("Done");
}

int main() {
	struct sigaction action = {
		.sa_sigaction = handleSIGUSR1,
	};
	sigemptyset(&action.sa_mask);
	sigaction(SIGUSR1, &action, NULL);
	waitForSIGUSR1();
}

Was in der Signalbehandlung zu beachten ist:

  1. errno sichern, wenn sie während der Funktion überschrieben werden könnte
  2. Gemeinsame Datenstrukturen durch sigprocmask(3p) einseitig synchronisieren
  3. Keine Funktionen mit Filepointern verwenden, da diese mit einem Lock synchronisiert sind (Deadlock). Dies betrifft auch fprintf(3p) und Co.
  4. Im Signal-Handler selber sollten keine Signale mit sigprocmask(3p) mehr blockiert werden. Hierzu ist das sa_mask Feld des struct sigaction da. Das behandelte Signal ist in der Behandlung automatisch blockiert.
  5. Wenn das Signal während der Behandlung nochmal eintrifft wird es hinterher stets nur einmal zugestellt. Dementsprechend müssen manche Aufrufe (z.B. waitpid(3p)) in einer Schleife ausgeführt werden.

Der Unterschied sigprocmask(3p) und sigaction(3p):

Auf den ersten Blick scheinen sigprocmask(3p) und sigaction(3p) mit SIG_IGN einen ähnlichen Effekt zu haben. Tatsächlich sind diese Aufrufe jedoch keinesfalls gegenseitig auswechselbar.

sigaction(3p) mit SIG_IGN führt dazu, dass Signale vom entsprechenden Typen ignoriert werden. Auch wenn für Signal hinterher wieder Behandlungsroutine eingerichtet wird, werden verpasste Signale nicht nachträglich zugestellt.

sigprocmask(3p) blockiert ein Signal temporär. Sobald die ursprüngliche Signalmaske wiederhergestellt wird wird das Signal zugestellt.

Die Verwechselung der beiden kann dazu führen, dass entweder wichtige Signal verloren gehen oder Signale auf einmal zu einem unerwarteten Zeitpunkt, stark verzögert zugestellt werden (z.B. nachdem ein Kindprozess nach fork(3p) und execvp(3p) die Signalmaske zurücksetzt).

Mehr Informationen dazu gibt es auch auf Milans Seite.