-
-
Notifications
You must be signed in to change notification settings - Fork 30.7k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
On FreeBSD, signal.NSIG is smaller than biggest signal value #64783
Comments
On FreeBSD, signal.NSIG is smaller than what the documentation promises: "One more than the number of the highest signal number". On Linux, the highest numerical signal value is smaller/equal signal.NSIG (expected behavior): >>> import signal
>>> signals = [s for s in dir(signal) if s.startswith("SIG")]
>>> max([(getattr(signal, s), s) for s in signals])
(64, 'SIGRTMAX')
>>> signal.NSIG
65 On FreeBSD (since version 7, when SIGRTMIN/MAX have been introduced), Python's signal.NSIG is either 32 (if defined by the system, depending on __BSD_VISIBLE, see http://svnweb.freebsd.org/base/head/sys/sys/signal.h?revision=233519&view=markup#l331) or 64 (if chosen by signalmodule.c as a fallback). In any case, on FreeBSD the numerical values of SIGRTMIN/MAX are 65 and 126 and therefore both greater than Python's signal.NSIG: Consequently, Python's signal module exposes a number NSIG which is not 'true'. Two disadvantages:
I see three arguments here:
Regarding the latter point: if Python misses to check for a valid signal on a certain platform, then this actively derived NSIG value would not be entirely correct, either, seen from the platform's perspective. But the signal module would then at least be consistent with itself. In case of FreeBSD, I am actually not sure if signal.NSIG *is* provided by the system or determined by the fallback method in signalmodule.c (I can't get my hands on a FreeBSD machine at the moment). What do you think? Btw, parts of this have already been mentioned here: http://bugs.python.org/issue12060 |
As a follow-up, relevant output from FreeBSD 9: $ python
Python 2.7.5 (default, Dec 20 2013, 21:12:37)
[GCC 4.2.1 20070831 patched [FreeBSD]] on freebsd9
Type "help", "copyright", "credits" or "license" for more information.
>>> import signal
>>> signals = [s for s in dir(signal) if s.startswith("SIG")]
>>> max((getattr(signal, s), s) for s in signals)
(126, 'SIGRTMAX')
>>> signal.NSIG
32
>>> signal.signal(signal.SIGRTMAX, lambda *a: None)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: signal number out of range Hence, it's not the fallback to 64, it's FreeBSD's signal.h telling that NSIG is 32. |
If you are thinking TL;DR: This fails on FreeBSD: >>> signal.signal(signal.SIGRTMAX, lambda *a: None)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: signal number out of range Although of infrequent use, I doubt that this is expected or desired behavior. |
The current implementation of _signal requires a limit on the number of signals to its internal array used to store Python callback: static volatile struct {
sig_atomic_t tripped;
PyObject *func;
} Handlers[NSIG]; If you want to kill the arbitrary limit, you need to change this structure. Maybe we need to find NSIG value differently on FreeBSD? For example try to use _SIG_MAXSIG. Please try attached on FreeBSD. |
Or the structure could simply host up to 256 handlers, regardless of NSIG. |
Agreed. #ifndef NSIG
# if defined(_NSIG)
# define NSIG _NSIG /* For BSD/SysV */
# elif defined(_SIGMAX)
# define NSIG (_SIGMAX + 1) /* For QNX */
# elif defined(SIGMAX)
# define NSIG (SIGMAX + 1) /* For djgpp */
# else
# define NSIG 64 /* Use a reasonable default value */
# endif
#endif |
Extract of system signal.h: #if __BSD_VISIBLE
#define NSIG 32 /* number of old signals (counting 0) */
#endif whereas <sys/_sigset.h> contains: #define _SIG_MAXSIG 128 In signalmodule.c, NSIG is still important in the function sigset_to_set(): we need to have the exact maximum signal number of a sigset. I prefer to make signalmodule.c a little big uglier to fix the NSIG value. I tested attached signal_nsig_freebsd-2.patch on FreeBSD 9. I suggest to backport this fix to Python 2.7 and 3.4. |
We should match the unit test with the documentation for signal.NSIG. Either the code or the docs or both need to change. Currently the docs say that signal.NSIG is "One more than the number of the highest signal number." ("https://docs.python.org/3.4/library/signal.html#signal.NSIG). In case of FreeBSD's _SIG_MAXSIG (128) the documentation is still wrong: the highest signal value MAX is 126 (see http://bugs.python.org/issue20584#msg210892). According to the docs, NSIG should then be 127. In signal_nsig_freebsd-2.patch the test So, either
The current patch + a documentation change would implement the latter case. What is the exact meaning of _SIG_MAXSIG, where is that meaning defined? |
Salut!, amis français! (Und auch sonst so, natürlich.) POSIX has recently standardized a NSIG_MAX constant in <limits.h> [1]: The value of {NSIG_MAX} shall be no greater than the number of signals that the sigset_t type (see [cross-ref to <signal.h>]) is capable of representing, ignoring any restrictions imposed by sigfillset() or sigaddset(). I'm personally following an advise of Rich Felker in the meantime: #ifdef NSIG_MAX
# undef NSIG
# define NSIG NSIG_MAX
#elif !defined NSIG
# define NSIG ((sizeof(sigset_t) * 8) - 1)
#endif That is for "old" signals only, there; maybe reducing this to #undef NSIG
#ifdef NSIG_MAX
# define NSIG NSIG_MAX
#else
# define NSIG ((sizeof(sigset_t) * 8) - 1)
#endif should do the trick for Python on any POSIX system? |
Yeah, but it doesn't matter.
This assumes that sigset_t is implemented as a raw bitmap, which isn't So I think we should go for the above patch (Steffen's), with a doc |
Just an update to say that the mismatch on FreeBSD still exists.
|
#91145 seems to be a duplicate. |
I wrote #91929 to fix this issue and update the NSIG documentation. |
I marked #91145 as a duplicate of this issue. |
Fix signal.NSIG value on FreeBSD to accept signal numbers greater than 32, like signal.SIGRTMIN and signal.SIGRTMAX. * Add Py_NSIG constant. * Add pycore_signal.h internal header file. * _Py_Sigset_Converter() now includes the range of valid signals in the error message.
Note: these values reflect the state of the issue at the time it was migrated and might not reflect the current state.
Show more details
GitHub fields:
bugs.python.org fields:
The text was updated successfully, but these errors were encountered: