This issue tracker has been migrated to GitHub, and is currently read-only.
For more information, see the GitHub FAQs in the Python's Developer Guide.

Author vstinner
Recipients njs, pitrou, serhiy.storchaka, vstinner
Date 2017-12-12.09:05:50
SpamBayes Score -1.0
Marked as misclassified Yes
Message-id <1513069551.02.0.213398074469.issue30050@psf.upfronthosting.co.za>
In-reply-to
Content
> it would be extremely difficult to implement since at the point where the error occurs, we don't have and can't take the GIL.

The signal handler uses Py_AddPendingCall() which calls a C function "later", but it can be anytime, between two Python instruction. If the callback fails, it can be annoying to get an error "anywhere". It can be even worse if the callback only fails if we are calling a specific function.

Handling signals is very tricky, it's hard to "get it right".

For example, Py_AddPendingCall() has an hardcoded queue of 32 callbacks. If the queue is full... the callback is lost...

Py_AddPendingCall() also tries to acquire a lock... from a signal handler... Probably the worst idea... But that's another idea :-)

    /* try a few times for the lock.  Since this mechanism is used
     * for signal handling (on the main thread), there is a (slim)
     * chance that a signal is delivered on the same thread while we
     * hold the lock during the Py_MakePendingCalls() function.
     * This avoids a deadlock in that case.
     * Note that signals can be delivered on any thread.  In particular,
     * on Windows, a SIGINT is delivered on a system-created worker
     * thread.
     * We also check for lock being NULL, in the unlikely case that
     * this function is called before any bytecode evaluation takes place.
     */
    if (lock != NULL) {
        for (i = 0; i<100; i++) {
            if (PyThread_acquire_lock(lock, NOWAIT_LOCK))
                break;
        }
        if (i == 100)
            return -1;
    }

We may also get a new signal while handling a signal...

Currently, the Windows implementation of the signal handler remembers if there is pending call to report_wakeup_send_error(), so it doesn't fill the pending call callback queue. But the Linux implementation doesn't.

With Nathaniel's PR, the queue is always filled. I'm not sure that it's ideal, but it's also hard to handle synchronization here so I didn't complain :-) Always calling Py_AddPendingCall() does work for the signal module, but it may prevent other functions to schedule a pending call later. In practice, in CPython, only the signal handler calls Py_AddPendingCall() :-)
History
Date User Action Args
2017-12-12 09:05:51vstinnersetrecipients: + vstinner, pitrou, njs, serhiy.storchaka
2017-12-12 09:05:51vstinnersetmessageid: <1513069551.02.0.213398074469.issue30050@psf.upfronthosting.co.za>
2017-12-12 09:05:51vstinnerlinkissue30050 messages
2017-12-12 09:05:50vstinnercreate