qmsk/net/lib/event2/event.pyx
changeset 50 da394bb715af
parent 47 b45a6648931c
child 52 722fc70a197a
equal deleted inserted replaced
49:e2f79e68418a 50:da394bb715af
     1 from qmsk.net.lib.event2.event cimport *
     1 from qmsk.net.lib.event2.event cimport *
     2 from qmsk.net.lib.event2.base cimport event_base
     2 from qmsk.net.lib.event2.base cimport event_base
       
     3 cimport qmsk.net.py as py
     3 
     4 
     4 cdef lib.timeval* build_timeout (lib.timeval *tv, object timeout = None) except? <lib.timeval *>-1 :
     5 cdef lib.timeval* build_timeout (lib.timeval *tv, object timeout = None) except? <lib.timeval *>-1 :
     5     """
     6     """
     6         If a timeout is given, it is treated as a float and stored in *tv, which is returned. Otherwise, simply returns
     7         If a timeout is given, it is treated as a float and stored in *tv, which is returned. Otherwise, simply returns
     7         NULL.
     8         NULL.
    30     """
    31     """
    31     
    32     
    32     # unpack opaque arg
    33     # unpack opaque arg
    33     cdef event ev = <event>arg
    34     cdef event ev = <event>arg
    34 
    35 
       
    36     # drop self-ref if not pending anymore (keep the local ref)
       
    37     # XXX: does the event show up as non-pending here? :/
       
    38     ev._unmark()
       
    39 
    35     # invoke
    40     # invoke
    36     # XXX: logging?
    41     # XXX: logging?
    37     ev(fd, mask)
    42     ev(fd, mask)
    38 
    43     
    39 
    44 
    40 cdef class event :
    45 cdef class event :
    41 
    46 
    42     def __init__ (self, event_base base not None, lib.evutil_socket_t fd, short events) :
    47     def __init__ (self, event_base base not None, lib.evutil_socket_t fd, short events) :
       
    48         # we don't hold a self-reference yet
       
    49         self.alive = False
    43 
    50 
    44         # libevent seems to segfault otherwise...
    51         # libevent seems to segfault otherwise...
    45         if events & (lib.EV_READ | lib.EV_WRITE) and fd < 0 :
    52         if events & (lib.EV_READ | lib.EV_WRITE) and fd < 0 :
    46             raise ValueError(fd)
    53             raise ValueError(fd)
    47 
    54 
    56         """
    63         """
    57             Re-assign our event parameters to the given ones.
    64             Re-assign our event parameters to the given ones.
    58 
    65 
    59             It is illegal to call this method after calling .add() but before del()/callback!
    66             It is illegal to call this method after calling .add() but before del()/callback!
    60         """
    67         """
       
    68 
       
    69         if self.alive :
       
    70             raise RuntimeError("Cannot change event while active")
    61         
    71         
    62         # interesting... no error return code
    72         # interesting... no error return code
    63         lib.event_assign(self.ev, base.ev_base, fd, events, ev_callback, <void *>self)
    73         lib.event_assign(self.ev, base.ev_base, fd, events, ev_callback, <void *>self)
    64 
    74 
    65 
    75 
    77             XXX: "The event in the ev argument must be already initialized by event_set() and may not be used in calls to event_set() until it has timed out or been removed with event_del()" -- enforce
    87             XXX: "The event in the ev argument must be already initialized by event_set() and may not be used in calls to event_set() until it has timed out or been removed with event_del()" -- enforce
    78         """
    88         """
    79 
    89 
    80         cdef lib.timeval tv
    90         cdef lib.timeval tv
    81 
    91 
       
    92         # aquire self-ref
       
    93         self._mark()
       
    94 
    82         if lib.event_add(self.ev, build_timeout(&tv, timeout)) < 0 :
    95         if lib.event_add(self.ev, build_timeout(&tv, timeout)) < 0 :
    83             raise Exception("event_new")
    96             raise Exception("event_new")
    84 
    97 
    85 
    98 
    86     def delete (self) :
    99     def delete (self) :
    88             Remove this event from our event_base's set of monitored events.
   101             Remove this event from our event_base's set of monitored events.
    89 
   102 
    90             If this event has already executed or has never been added this call with have no effect.
   103             If this event has already executed or has never been added this call with have no effect.
    91         """
   104         """
    92 
   105 
       
   106 
    93         if lib.event_del(self.ev) < 0 :
   107         if lib.event_del(self.ev) < 0 :
    94             raise Exception("event_del")
   108             raise Exception("event_del")
    95 
   109 
       
   110         # release self-ref
       
   111         self._unmark()
       
   112 
    96 
   113 
    97     def activate (self, int fd, short mask) :
   114     def activate (self, int fd, short mask) :
    98         """
   115         """
    99             'Fake' this event as active, triggering the callback.
   116             'Fake' this event as active, triggering the callback.
   100         """
   117         """
       
   118         
       
   119         # aquire self-ref
       
   120         self._mark()
   101 
   121 
   102         lib.event_active(self.ev, fd, mask)
   122         lib.event_active(self.ev, fd, mask)
   103 
   123 
   104 
   124 
   105     def pending (self, short mask = 0xffff) :
   125     cpdef pending (self, short mask = 0xffff) :
   106         """
   126         """
   107             Returns a bool indicating if this event is pending (that is, has been .add()'d).
   127             Returns a bool indicating if this event is pending (that is, has been .add()'d).
   108 
   128 
   109             For convenience, this defaults to testing all possible flags, and so will return true if any events are
   129             For convenience, this defaults to testing all possible flags, and so will return true if any events are
   110             pending.
   130             pending.
   112             XXX: support returning timeout value?
   132             XXX: support returning timeout value?
   113         """
   133         """
   114 
   134 
   115         return bool(lib.event_pending(self.ev, mask, NULL))
   135         return bool(lib.event_pending(self.ev, mask, NULL))
   116 
   136 
       
   137 
       
   138     cdef object _mark (self) :
       
   139         """
       
   140             Refcount magic. Aquires an internal reference *if we don't have one yet*.
       
   141         """
       
   142         
       
   143         if not self.alive :
       
   144             self.alive = True
       
   145 
       
   146             py.Py_INCREF(self)
       
   147 
       
   148 
       
   149     cdef object _unmark (self) :
       
   150         """
       
   151             Refcout magic. Releses the internal reference *if we have one* and libevent doesn't think this event is
       
   152             pending anymore.
       
   153 
       
   154             XXX: this might cause ourselves to be destroyed... we can't break if that happens.
       
   155         """
       
   156 
       
   157         if self.alive and not self.pending() :
       
   158             py.Py_DECREF(self)
       
   159 
       
   160             self.alive = False
       
   161             
   117 
   162 
   118     property fd :
   163     property fd :
   119         def __get__ (self) :
   164         def __get__ (self) :
   120             """
   165             """
   121                 Get the OS file descriptor associated with this event.
   166                 Get the OS file descriptor associated with this event.
   139         pass
   184         pass
   140 
   185 
   141 
   186 
   142     def __dealloc__ (self) :
   187     def __dealloc__ (self) :
   143         """
   188         """
   144             Release the event object usign event_free. This should be completely safe as regards out event_base.
   189             Release the event object usign event_free. This should be completely safe as regards our event_base.
   145 
   190 
   146             XXX: what happens if event_base's __dealloc__ is triggered, but there are still event objects alive?
   191             XXX: what happens if event_base's __dealloc__ is triggered, but there are still event objects alive?
   147         """
   192         """
   148         
   193         
   149         if self.ev != NULL :
   194         if self.ev != NULL :