
from __future__ import absolute_import
from __future__ import division
import errno
import os
import select
import signal

from vdsm.common import filecontrol

_signal_poller = None
_signal_read_fd = None


def register():

    global _signal_poller
    global _signal_read_fd

    if _signal_poller is not None:
        raise RuntimeError('register was already called')

    read_fd, write_fd = os.pipe()

    filecontrol.set_non_blocking(write_fd)

    filecontrol.set_non_blocking(read_fd)

    filecontrol.set_close_on_exec(write_fd)
    filecontrol.set_close_on_exec(read_fd)

    signal.set_wakeup_fd(write_fd)

    poller = select.poll()
    poller.register(read_fd, select.POLLIN)

    _signal_poller = poller
    _signal_read_fd = read_fd


def wait_for_signal(timeout=None):
    if _signal_poller is None:
        raise RuntimeError("Attempt to wait on signal before calling register")

    if timeout is not None:
        timeout *= 1000

    try:
        cleanup = [] != _signal_poller.poll(timeout)
    except select.error as e:
        if e[0] != errno.EINTR:
            raise
        cleanup = True

    if cleanup:
        _empty_pipe()


def _read(fd, length):
    while True:
        try:
            return os.read(fd, length)
        except OSError as e:
            if e.errno == errno.EINTR:
                continue
            elif e.errno == errno.EAGAIN:
                return ''
            raise


def _empty_pipe():
    while len(_read(_signal_read_fd, 128)) == 128:
        pass
