Kiedy uruchomić ten skrypt Pythona z os.system
na Ubuntu 12.04:W jaki sposób Python blokuje sygnały podczas os.system ("sleep ...")?
import os, signal
signal.signal(signal.SIGABRT, lambda *args: os.write(2, 'HANDLER\n'))
print 'status=%r' % os.system('sleep 5')
, a potem wysłać SIGABRT do procesu skryptu wiele razy w ciągu 5 sekund, pojawia się następujący komunikat:
status=0
HANDLER
Oznacza to, że dostarczenie sygnału zostało zablokowane do czasu zakończenia sleep 5
, a następnie dostarczono tylko jeden sygnał.
Jednak z subprocess.call
:
import os, signal, subprocess
signal.signal(signal.SIGABRT, lambda *args: os.write(2, 'HANDLER\n'))
print 'cstatus=%r' % subprocess.call('sleep 5', shell=True)
, wszystkie poszczególne sygnały są dostarczane wcześnie:
HANDLER
HANDLER
HANDLER
cstatus=0
Aby odróżnić magię w glibc od magii w Pythonie, przepisałem skrypt Pythona w C , więc os.system
stał się system (3):
#include <errno.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
static void handler(int signum) { (void)signum; write(2, "HANDLER\n", 8); }
int main(int argc, char **argv) {
int got;
struct sigaction sa;
(void)argc; (void)argv;
memset(&sa, 0, sizeof sa);
sa.sa_handler = handler;
if (0 != sigaction(SIGABRT, &sa, NULL)) return 3;
got = system("sleep 5");
return !printf("system=0x%x\n", got);
}
Sygnały został dostarczony na początku:
HANDLER
HANDLER
HANDLER
system=0x0
więc wywnioskować, że magia jest w Pythonie 2.7, nie w eglibc. Ale gdzie jest magia? Opierając się na wyjściu strace i patrząc na funkcję posix_system
w Modules/posixmodule.c
, nie mogłem dowiedzieć się, jak Python blokuje sygnał do momentu powrotu do os.system
.
odpowiedni kod z Modules/posixmodule.c
:
static PyObject *posix_system(PyObject *self, PyObject *args) {
char *command;
long sts;
if (!PyArg_ParseTuple(args, "s:system", &command)) return NULL;
Py_BEGIN_ALLOW_THREADS
sts = system(command);
Py_END_ALLOW_THREADS
return PyInt_FromLong(sts);
}
Może magia jest w Py_BEGIN_ALLOW_THREADS
?
Czy poprawnie rozumiem, że moja obsługa sygnału w języku Python (skonfigurowana przez signal.signal
) jest niemożliwa do wykonania, dopóki nie zostanie zwrócony os.system
?
Czy to dlatego, że procedury obsługi sygnału są blokowane (na poziomie Pythona, a nie na poziomie systemu operacyjnego), dopóki nie powróci Py_END_ALLOW_THREADS
?
Oto wyjście strace kodu Pythona z os.system
: http://pastebin.com/Wjn9KBye