Sulla maggior parte delle implementazioni di thread POSIX, è necessaria un'inizializzazione nel thread appena creato prima che sia in uno stato coerente in grado di eseguire il codice dell'applicazione. Ciò può comportare lo sblocco dei blocchi nella struttura del thread, l'inizializzazione del "registro dei thread" nelle implementazioni che ne utilizzano uno, l'inizializzazione dei dati locali del thread (dati TLS a livello di compilatore o specifici del thread POSIX), ecc. Non riesco a trovare un chiaro garantire che tutta questa inizializzazione sarà terminata prima che il thread possa ricevere qualsiasi segnale; il più vicino che riesco a trovare è in 2.4.3:I segnali di garanzia POSIX non verranno consegnati a un thread parzialmente inizializzato?
La seguente tabella definisce un insieme di funzioni che devono essere sicure per il segnale asincrono. Pertanto, le applicazioni possono invocateli, senza restrizioni, funzioni di segnalazione cattura:
...
Presumibilmente, alcune di queste funzioni (almeno fork
, che deve ispezionare stato globale stabilito dal pthread_atfork
funzione) dipende dal fatto che il thread si trovi in uno stato coerente e inizializzato.
Una cosa che mi dà fastidio è che ho letto molto del codice glibc/nptl e non riesco a trovare alcuna sincronizzazione esplicita per impedire che un segnale venga gestito dal thread appena creato prima che sia completamente inizializzato. Mi aspetterei che il thread chiamasse pthread_create
per bloccare tutti i segnali prima di chiamare clone
, e per il nuovo thread per sbloccarli una volta che l'inizializzazione è terminata, ma non riesco a trovare alcun codice per quell'effetto né lo vedo nell'output strace
.
Wow, chiamare 'fork()' da un gestore di segnale quando i gestori di 'pthread_atfork()' sono stati impostati ... Dovresti * davvero * sapere cosa stai facendo (e fidarti della tua implementazione della libreria) per quello! Soprattutto se (come avviene normalmente) il gestore di prefork afferra un gruppo di lucchetti per garantire che i dati che rappresentano siano coerenti prima della forcella: in linea di principio questi blocchi potrebbero essere mantenuti (o peggio, nel processo di acquisizione) dal thread che gestisce il segnale, il che significa che i dati sono irreparabilmente incoerenti (o il processo potrebbe deadlock!). Tutto molto divertente :-) – psmears
Bene, 'fork' è elencato come una delle funzioni async-segnale-safe, ma sono d'accordo sul fatto che praticamente tutte le cose utili che una funzione' pthread_atfork'-registrata potrebbe fare non sono un segnale asincrono -sicuro. Esistono ancora alcuni usi validi, ad esempio se il tuo gestore 'pthread_atfork' semplicemente reinizializza i dati con valori fissi, distrugge i mutex controllanti e inizializza quelli nuovi (tutto ovviamente nel processo figlio). –
La cosa più disturbante è cosa succede se una libreria (non nota per essere trasmessa dall'applicazione chiamante, magari caricata anche in modo dinamico indirettamente come dipendenza da un'altra libreria) imposta i gestori di 'pthread_atexit' che non sono sicuri per il segnale asincrono. L'applicazione chiamante potrebbe aspettarsi che 'fork' sia async-signal-safe (come documentato) e lo chiami da un gestore di segnale. Immagino che quello che mi viene in mente da questo esperimento mentale sia che espone un difetto nel modello di librerie "usa e gira-filetto" per la creazione di "pthread_atfork". –