Exemplo n.º 1
0
    def unregister(self, fd):
        """
        Unregister a previously registered descriptor

        :param fd:
            The descriptor to unregister
        :raises ValueError:
            If :meth:`closed()` is True
        :raises OSError:
            If the underlying ``epoll_ctl(2)`` fails. The error message matches
            those found in the manual page.

        .. note::
            For feature parity with Python 3.4, unlike what ``epoll_ctl(2)``
            would do, we are silently ignoring ``EBADF`` which is raised if
        """
        if self._epfd < 0:
            _err_closed()
        ev = epoll_event()
        try:
            epoll_ctl(self._epfd, EPOLL_CTL_DEL, fd, byref(ev))
        except OSError as exc:
            # Allow fd to be closed, matching Python 3.4
            if exc.errno != EBADF:
                raise
Exemplo n.º 2
0
    def unregister(self, fd):
        """
        Unregister a previously registered descriptor

        :param fd:
            The descriptor to unregister
        :raises ValueError:
            If :meth:`closed()` is True
        :raises OSError:
            If the underlying ``epoll_ctl(2)`` fails. The error message matches
            those found in the manual page.

        .. note::
            For feature parity with Python 3.4, unlike what ``epoll_ctl(2)``
            would do, we are silently ignoring ``EBADF`` which is raised if
        """
        if self._epfd < 0:
            _err_closed()
        ev = epoll_event()
        try:
            epoll_ctl(self._epfd, EPOLL_CTL_DEL, fd, byref(ev))
        except OSError as exc:
            # Allow fd to be closed, matching Python 3.4
            if exc.errno != EBADF:
                raise
Exemplo n.º 3
0
    def modify(self, fd, eventmask):
        """
        Change the bit-mask of events associated with a previously-registered
        descriptor.

        :param fd:
            The descriptor to modify.
        :param eventmask:
            New bit-mask of events that will be monitored.
        :raises ValueError:
            If :meth:`closed()` is True
        :raises OSError:
            If the underlying ``epoll_ctl(2)`` fails. The error message matches
            those found in the manual page.
        """
        if self._epfd < 0:
            _err_closed()
        ev = epoll_event()
        ev.events = eventmask
        ev.data.fd = fd
        epoll_ctl(self._epfd, EPOLL_CTL_MOD, fd, byref(ev))
Exemplo n.º 4
0
    def modify(self, fd, eventmask):
        """
        Change the bit-mask of events associated with a previously-registered
        descriptor.

        :param fd:
            The descriptor to modify.
        :param eventmask:
            New bit-mask of events that will be monitored.
        :raises ValueError:
            If :meth:`closed()` is True
        :raises OSError:
            If the underlying ``epoll_ctl(2)`` fails. The error message matches
            those found in the manual page.
        """
        if self._epfd < 0:
            _err_closed()
        ev = epoll_event()
        ev.events = eventmask
        ev.data.fd = fd
        epoll_ctl(self._epfd, EPOLL_CTL_MOD, fd, byref(ev))
Exemplo n.º 5
0
def main():
    # Block signals so that they aren't handled
    # according to their default dispositions
    mask = sigset_t()
    fdsi = signalfd_siginfo()
    sigemptyset(mask)
    sigaddset(mask, SIGINT)
    sigaddset(mask, SIGQUIT)
    sigprocmask(SIG_BLOCK, mask, None)
    # Get a signalfd descriptor
    sfd = signalfd(-1, mask, SFD_CLOEXEC)
    # Get a epoll descriptor
    epollfd = epoll_create1(EPOLL_CLOEXEC)
    ev = epoll_event()
    ev.events = EPOLLIN
    ev.data.fd = sfd
    epoll_ctl(epollfd, EPOLL_CTL_ADD, sfd, byref(ev))
    MAX_EVENTS = 10
    events = (epoll_event * MAX_EVENTS)()
    with fdopen(sfd, 'rb', 0) as sfd_stream:
        while True:
            nfds = epoll_wait(
                epollfd, cast(byref(events), POINTER(epoll_event)),
                MAX_EVENTS, -1)
            for event_id in range(nfds):
                if events[event_id].data.fd == sfd:
                    # Read the next delivered signal
                    sfd_stream.readinto(fdsi)
                    if fdsi.ssi_signo == SIGINT:
                        print("Got SIGINT")
                    elif fdsi.ssi_signo == SIGQUIT:
                        print("Got SIGQUIT")
                        return
                    else:
                        print("Read unexpected signal")
                else:
                    raise Exception("unexpected fd?")
    close(sfd)
    close(epollfd)
Exemplo n.º 6
0
    def register(self, fd, eventmask=None):
        """
        Register a new descriptor

        :param fd:
            The descriptor to register.
        :param eventmask:
            Bit-mask of events that will be monitored. By default EPOLLIN,
            EPOLLOUT and EPOLLPRI are used. Note that EPOLLHUP is implicit and
            doesn't need to be provided.
        :raises ValueError:
            If :meth:`closed()` is True
        :raises OSError:
            If the underlying ``epoll_ctl(2)`` fails. The error message matches
            those found in the manual page.
        """
        if self._epfd < 0:
            _err_closed()
        if eventmask is None:
            eventmask = EPOLLIN | EPOLLOUT | EPOLLPRI
        ev = epoll_event()
        ev.events = eventmask
        ev.data.fd = fd
        epoll_ctl(self._epfd, EPOLL_CTL_ADD, fd, byref(ev))
Exemplo n.º 7
0
    def register(self, fd, eventmask=None):
        """
        Register a new descriptor

        :param fd:
            The descriptor to register.
        :param eventmask:
            Bit-mask of events that will be monitored. By default EPOLLIN,
            EPOLLOUT and EPOLLPRI are used. Note that EPOLLHUP is implicit and
            doesn't need to be provided.
        :raises ValueError:
            If :meth:`closed()` is True
        :raises OSError:
            If the underlying ``epoll_ctl(2)`` fails. The error message matches
            those found in the manual page.
        """
        if self._epfd < 0:
            _err_closed()
        if eventmask is None:
            eventmask = EPOLLIN | EPOLLOUT | EPOLLPRI
        ev = epoll_event()
        ev.events = eventmask
        ev.data.fd = fd
        epoll_ctl(self._epfd, EPOLL_CTL_ADD, fd, byref(ev))
def main():
    # Block signals so that they aren't handled
    # according to their default dispositions
    mask = sigset_t()
    fdsi = signalfd_siginfo()
    sigemptyset(mask)
    sigaddset(mask, SIGINT)
    sigaddset(mask, SIGQUIT)
    sigaddset(mask, SIGCHLD)
    sigaddset(mask, SIGPIPE)
    print("Blocking signals")
    sigprocmask(SIG_BLOCK, mask, None)
    # Get a signalfd descriptor
    sfd = signalfd(-1, mask, SFD_CLOEXEC)
    print("Got signalfd", sfd)
    # Get a epoll descriptor
    epollfd = epoll_create1(EPOLL_CLOEXEC)
    print("Got epollfd", epollfd)
    ev = epoll_event()
    ev.events = EPOLLIN
    ev.data.fd = sfd
    print("Adding signalfd fd {} to epoll".format(sfd))
    epoll_ctl(epollfd, EPOLL_CTL_ADD, sfd, byref(ev))
    # Get two pair of pipes, one for stdout and one for stderr
    stdout_pair = (c_int * 2)()
    pipe2(byref(stdout_pair), O_CLOEXEC)
    print("Got stdout pipe pair", stdout_pair[0], stdout_pair[1])
    stderr_pair = (c_int * 2)()
    pipe2(byref(stderr_pair), O_CLOEXEC)
    print("Got stderr pipe pair", stderr_pair[0], stderr_pair[1])
    prog = argv[1:]
    if not prog:
        prog = ['echo', 'usage: demo.py PROG [ARGS]']
    print("Going to start program:", prog)
    # Fork :-)
    pid = fork()
    if pid == 0:  # Child.
        # NOTE: we are not closing any of the pipe ends. Why? Because they are
        # all O_CLOEXEC and will thus not live across the execlp call down
        # below.
        dup3(stdout_pair[1], 1, 0)
        dup3(stderr_pair[1], 2, 0)
        execlp(prog[0], *prog)
    else:
        for pair in stdout_pair, stderr_pair:
            read_end, write_end = pair
            # We need to close the write sides of both pipes
            close(write_end)
            # And add the read side to epoll
            ev.events = c_uint32(EPOLLIN | EPOLLHUP |
                                 EPOLLERR | EPOLLRDHUP |
                                 EPOLLOUT | EPOLLPRI)
            ev.data.fd = read_end
            print("Adding pipe fd {} to epoll".format(read_end))
            epoll_ctl(epollfd, EPOLL_CTL_ADD, read_end, byref(ev))
        stdout_pipe_fd = stdout_pair[0]
        stderr_pipe_fd = stderr_pair[0]
    with fdopen(sfd, 'rb', 0) as sfd_stream:
        MAX_EVENTS = 10
        event_array = (epoll_event * MAX_EVENTS)()
        waiting_for = set(['stdout', 'stderr', 'proc'])
        while waiting_for:
            print("Waiting for events...", waiting_for, flush=True)
            nfds = epoll_wait(epollfd, cast(
                byref(event_array), POINTER(epoll_event)
            ), MAX_EVENTS, -1)
            print("epoll_wait() read {} events".format(nfds))
            for event_id in range(nfds):
                event = event_array[event_id]
                print("[event {}]".format(event_id))
                event_bits = []
                if event.events & EPOLLIN == EPOLLIN:
                    event_bits.append('EPOLLIN')
                if event.events & EPOLLOUT == EPOLLOUT:
                    event_bits.append('EPOLLOUT')
                if event.events & EPOLLRDHUP == EPOLLRDHUP:
                    event_bits.append('EPOLLRDHUP')
                if event.events & EPOLLPRI == EPOLLPRI:
                    event_bits.append('EPOLLPRI')
                if event.events & EPOLLERR == EPOLLERR:
                    event_bits.append('EPOLLERR')
                if event.events & EPOLLHUP == EPOLLHUP:
                    event_bits.append('EPOLLHUP')
                if event.data.fd == sfd:
                    fd_name = 'signalfd()'
                elif event.data.fd == stdout_pipe_fd:
                    fd_name = 'stdout pipe2()'
                elif event.data.fd == stderr_pipe_fd:
                    fd_name = 'stderr pipe2()'
                else:
                    fd_name = "???"
                print(" events: {} ({})".format(
                    event.events, ' | '.join(event_bits)))
                print(" fd: {} ({})".format(event.data.fd, fd_name))
                if event.data.fd == sfd:
                    print("signalfd() descriptor ready")
                    if event.events & EPOLLIN:
                        print("Reading data from signalfd()...")
                        # Read the next delivered signal
                        sfd_stream.readinto(fdsi)
                        if fdsi.ssi_signo == SIGINT:
                            print("Got SIGINT")
                        elif fdsi.ssi_signo == SIGQUIT:
                            print("Got SIGQUIT")
                            raise SystemExit("exiting prematurly")
                        elif fdsi.ssi_signo == SIGCHLD:
                            print("Got SIGCHLD")
                            waitid_result = waitid(
                                P_PID, pid,
                                WNOHANG |
                                WEXITED | WSTOPPED | WCONTINUED |
                                WUNTRACED)
                            if waitid_result is None:
                                print("child not ready")
                            else:
                                print("child event")
                                print("si_pid:", waitid_result.si_pid)
                                print("si_uid:", waitid_result.si_uid)
                                print("si_signo:", waitid_result.si_signo)
                                assert waitid_result.si_signo == SIGCHLD
                                print("si_status:", waitid_result.si_status)
                                print("si_code:", waitid_result.si_code)
                                if waitid_result.si_code == CLD_EXITED:
                                    # assert WIFEXITED(waitid_result.si_status)
                                    print("child exited normally")
                                    print("exit code:",
                                          WEXITSTATUS(waitid_result.si_status))
                                    waiting_for.remove('proc')
                                    if 'stdout' in waiting_for:
                                        epoll_ctl(epollfd, EPOLL_CTL_DEL,
                                                  stdout_pipe_fd, None)
                                        close(stdout_pipe_fd)
                                        waiting_for.remove('stdout')
                                    if 'stderr' in waiting_for:
                                        epoll_ctl(epollfd, EPOLL_CTL_DEL,
                                                  stderr_pipe_fd, None)
                                        close(stderr_pipe_fd)
                                        waiting_for.remove('stderr')
                                elif waitid_result.si_code == CLD_KILLED:
                                    assert WIFSIGNALED(waitid_result.si_status)
                                    print("child was killed by signal")
                                    print("death signal:",
                                          waitid_result.si_status)
                                    waiting_for.remove('proc')
                                elif waitid_result.si_code == CLD_DUMPED:
                                    assert WIFSIGNALED(waitid_result.si_status)
                                    print("core:",
                                          WCOREDUMP(waitid_result.si_status))
                                elif waitid_result.si_code == CLD_STOPPED:
                                    print("child was stopped")
                                    print("stop signal:",
                                          waitid_result.si_status)
                                elif waitid_result.si_code == CLD_TRAPPED:
                                    print("child was trapped")
                                    # TODO: we could explore trap stuff here
                                elif waitid_result.si_code == CLD_CONTINUED:
                                    print("child was continued")
                                else:
                                    raise SystemExit(
                                        "Unknown CLD_ code: {}".format(
                                            waitid_result.si_code))
                        elif fdsi.ssi_signo == SIGPIPE:
                            print("Got SIGPIPE")
                        else:
                            print("Read unexpected signal: {}".format(
                                fdsi.ssi_signo))
                elif event.data.fd == stdout_pipe_fd:
                    print("pipe() (stdout) descriptor ready")
                    if event.events & EPOLLIN:
                        print("Reading data from stdout...")
                        data = read(stdout_pipe_fd, PIPE_BUF)
                        print("Read {} bytes from stdout".format(len(data)))
                        print(data)
                    if event.events & EPOLLHUP:
                        print("Removing stdout pipe from epoll")
                        epoll_ctl(epollfd, EPOLL_CTL_DEL, stdout_pipe_fd, None)
                        print("Closing stdout pipe")
                        close(stdout_pipe_fd)
                        waiting_for.remove('stdout')
                elif event.data.fd == stderr_pipe_fd:
                    print("pipe() (stderr) descriptor ready")
                    if event.events & EPOLLIN:
                        print("Reading data from stdout...")
                        data = read(stderr_pipe_fd, PIPE_BUF)
                        print("Read {} bytes from stderr".format(len(data)))
                        print(data)
                    if event.events & EPOLLHUP:
                        print("Removing stderr pipe from epoll")
                        epoll_ctl(epollfd, EPOLL_CTL_DEL, stderr_pipe_fd, None)
                        print("Closing stderr pipe")
                        close(stderr_pipe_fd)
                        waiting_for.remove('stderr')
                else:
                    # FIXME: we are still getting weird activation events on fd
                    # 0 (stdin) with events == 0 (nothing). I cannot explain
                    # this yet.
                    print("Unexpected descriptor ready:",
                          event.data.fd)
    assert not waiting_for
    print("Closing epollfd", epollfd)
    close(epollfd)
    print("Unblocking signals")
    sigprocmask(SIG_UNBLOCK, mask, None)
    print("Exiting normally")