how do you implement a reactor without a select?

Antoon Pardon apardon at forel.vub.ac.be
Tue May 8 05:23:24 EDT 2007


On 2007-05-08, Michele Simionato <michele.simionato at gmail.com> wrote:
> On May 8, 4:53 am, a... at mac.com (Alex Martelli) wrote:
>> What do you expect from "timers on Linux" that you could not get with a
>> simple "sleep for the next N milliseconds"?  A timer (on Linux or
>> elsewhere) can jog your process N milliseconds from now, e.g. with a
>> SIGALRM or SIGPROF, and you can set one with the setitimer syscall
>> (presumably accessible via ctypes, worst case -- I've never used it from
>> Python, yet), but how would that help you (compared to plain sleep,
>> select, poll, or whatever else best fits your need)?
>
> I hoped there was a library such thay I could register a Python
> callable (say
> a thunk) and having it called by the linux timer at time t without
> blocking

I once played with the following module to do something similar.
Maybe it is usefull to you as is, or can give you an idea on how
to proceed. I only tested it on linux.

---------------------------- alarm.py --------------------


m signal import signal, SIG_IGN, SIGALRM
from time import time
from thread import allocate_lock
from heapq import heappush, heappop
from os import kill, getpid
import errno

from select import select, error as SelectException

from ctypes import *
libc = cdll.LoadLibrary("/lib/libc.so.6")

class _timeval(Structure):
  _fields_ = [("tv_sec" , c_long), ("tv_usec", c_long)]

def timeval(tm):
    sec = int(tm)
    usec = int(1000000 * (tm - sec))
    return _timeval(sec, usec)

class itimerval(Structure):
  _fields_ = [("it_interval", _timeval), ("it_value", _timeval)]
  

def alarm(tm):
  tv = timeval(tm)
  ti = timeval(0.0)
  ntv = itimerval(ti, tv)
  otv = itimerval(timeval(0.0), timeval(0.0))
  rt = libc.setitimer(0, byref(ntv), byref(otv))
  #print otv.it_value.tv_sec , otv.it_value.tv_usec
  if rt:
    raise ValueError
  else:
    return otv.it_value.tv_sec + otv.it_value.tv_usec / 1000000.0

def sleep(tm):
  wakeup = time() + tm
  while tm >= 0:
    try:
      select([],[],[],tm)
    except SelectException , Err_Info:
      #print dir(Err_Info)
      if Err_Info[0] != errno.EINTR:
        raise
    tm = wakeup - time()

alarms = []
alarm_lock = allocate_lock()

def AlarmHandler(sgnr, frame):
  alarm_lock.acquire()
  now = time()
  while alarms and alarms[0].moment <= now:
    current = heappop(alarms)
    if not current.canceled:
      current.func(*current.args, **current.kwds)
      current.executed = True
    now = time()
  alarm_lock.release()
  if alarms:
    #print alarms[0].moment - now, alarms
    alarm(alarms[0].moment - now)

signal(SIGALRM, AlarmHandler)

class Alarm(object):
  def __init__(self, tp, func, *args, **kwds):
    alarm(0)
    try:
      alarm_lock.acquire()
      self.canceled = False
      self.executed = False
      self.func = func
      self.args = args
      self.kwds = kwds
      self.moment = tp
      heappush(alarms, self)
      now = time()
      delta = alarms[0].moment - now
      #print alarms
    finally:
      alarm_lock.release()
    if delta <= 0:
      pass
      kill(getpid(), SIGALRM)
    else:
      alarm(delta)

  def __cmp__(self, other):
    return cmp(self.moment, other.moment)

  def __str__(self):
    return "<Alarm for %d>" % self.moment

  __repr__ = __str__

  def Cancel(self):
    try:
      alarm_lock.acquire()
      if self.executed:
        raise ValueError, "Cancelation was too late"
      else:
        self.canceled = True
    except:
      alarm_lock.release()

-----------------------------------------------------------------------------------------------

You use it as follows:

from alarm import Alarm

alert = Alarm(exucutemoment, function, positionalarguments, keywordarguments)

# unless alert.Cancel is called before the alert went off, the function
# with its arguments will be called at the specified time.

# If you are using threads, you are advised to do most of the work in a
# different thread and leave the main thread to only treat the alarms.



More information about the Python-list mailing list