Skip to content

signal.set_wakeup_fd does not work unless you register a no-op signal handler for the relevant signal #131803

@jfly

Description

@jfly

Bug report

Bug description:

Consider this program that uses signal.signal.set_wakeup_fd:

demo.py:

import os
import signal
import struct


pipe_r, pipe_w = os.pipe()
os.set_blocking(pipe_w, False)
signal.set_wakeup_fd(pipe_w)

# Conditionally register a signal handler.
if os.environ["REGISTER_SIGNAL_HANDLER"] == "1":
    print("Registering a signal handler for SIGURG")
    signal.signal(signal.SIGURG, lambda signum, frame: None)
else:
    print("Not registering a signal handler for SIGURG")

# Send the signal!
print("Sending myself a SIGURG")
signal.raise_signal(signal.SIGURG)

# Verify that we wrote the signal to the pipe.
print("About to read from pipe_r")
data = os.read(pipe_r, 1)
(raised, ) = struct.unpack('%uB' % len(data), data)
if raised != signal.SIGURG:
    raise Exception("%r != %r" % (raised, signal.SIGURG))

os.close(pipe_r)
os.close(pipe_w)

print("Success!")

If I run this with REGISTER_SIGNAL_HANDLER=1, it works:

$ REGISTER_SIGNAL_HANDLER=1 python demo.py
Registering a signal handler for SIGURG
Sending myself a SIGURG
About to read from pipe_r
Success!

However, if I run this without registering the signal handler, it hangs indefinitely:

$ REGISTER_SIGNAL_HANDLER=0 python demo.py
Not registering a signal handler for SIGURG
Sending myself a SIGURG
About to read from pipe_r

All the real world usages I've been able to find of signal.set_wakeup_fd register a no-op signal handler for the signal(s) they're interested in. For example, see this CPython test:

signal.signal(signal.SIGALRM, handler)
.

I don't know if we would consider this is a bug in the implementation or a bug in the documentation, but IMO, it's a pretty confusing experience for people who don't know this. Some ideas:

  • Change signal.set_wakeup_fd to register a no-op signal handler for you if there isn't a corresponding signal handler already registered.
  • Change signal.set_wakeup_fd to error out if there is no signal handler already registered.
  • Update the docs to mention this requirement: https://docs.python.org/3/library/signal.html#signal.set_wakeup_fd

I'd be happy to implement some of these ideas if folks tell me what seems best!

CPython versions tested on:

3.12

Operating systems tested on:

Linux

Linked PRs

Metadata

Metadata

Assignees

No one assigned

    Labels

    extension-modulesC modules in the Modules dirtype-bugAn unexpected behavior, bug, or error

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions