
from __future__ import absolute_import
from __future__ import division
"""
This is a module to implement a python wrapper for eventfd(2).

Please check the man page for complete information on eventfd(2).

Flags:

- EFD_CLOEXEC: Set the close-on-exec (FD_CLOEXEC) flag on the new file
  descriptor.
- EFD_NONBLOCK: Set the O_NONBLOCK file status flag on the new open file
  description.
- EFD_SEMAPHORE: Provide semaphore-like semantics for reads from the new file
  descriptor.
"""
import ctypes
import os


libc = ctypes.CDLL("libc.so.6", use_errno=True)

EFD_SEMAPHORE = 0o0000001
EFD_CLOEXEC = 0o2000000
EFD_NONBLOCK = 0o0004000


class EventFD(object):
    def __init__(self, initial_value=0, flags=0):
        fd = libc.eventfd(
            ctypes.c_uint(initial_value),
            ctypes.c_int(flags)
        )
        self._verify_code(fd)
        self._fd = fd

    def fileno(self):
        return self._fd

    def read(self):
        n = ctypes.c_uint64()
        rv = libc.read(self._fd, ctypes.pointer(n),
                       ctypes.sizeof(ctypes.c_uint64))
        self._verify_code(rv)

        return int(n.value)

    def write(self, value=1):
        n = ctypes.c_uint64(value)
        rv = libc.write(self._fd, ctypes.pointer(n),
                        ctypes.sizeof(ctypes.c_uint64))
        self._verify_code(rv)

    def _verify_code(self, code):
        if code < 0:
            err = ctypes.get_errno()
            if err != 0:
                msg = os.strerror(err)
                raise OSError(err, msg)

    def close(self):
        if self._fd != -1:
            libc.close(self._fd)
            self._fd = -1

    def __del__(self):
        self.close()
