[pypy-svn] pypy default: fix test_semaphore_wait on Mac OS, which was failing due to missing sem_timedwait function

bivab commits-noreply at bitbucket.org
Sat Jan 22 12:10:43 CET 2011


Author: David Schneider <david.schneider at picle.org>
Branch: 
Changeset: r41206:001dbe4241e4
Date: 2011-01-22 11:30 +0100
http://bitbucket.org/pypy/pypy/changeset/001dbe4241e4/

Log:	fix test_semaphore_wait on Mac OS, which was failing due to missing
	sem_timedwait function

diff --git a/pypy/module/_multiprocessing/interp_semaphore.py b/pypy/module/_multiprocessing/interp_semaphore.py
--- a/pypy/module/_multiprocessing/interp_semaphore.py
+++ b/pypy/module/_multiprocessing/interp_semaphore.py
@@ -1,3 +1,4 @@
+from __future__ import with_statement
 from pypy.interpreter.baseobjspace import ObjSpace, Wrappable, W_Root
 from pypy.interpreter.typedef import TypeDef, GetSetProperty
 from pypy.interpreter.gateway import interp2app, Arguments, unwrap_spec
@@ -50,15 +51,17 @@
                                                        ('tv_nsec', rffi.LONG)])
         SEM_FAILED = platform.ConstantInteger('SEM_FAILED')
         SEM_VALUE_MAX = platform.ConstantInteger('SEM_VALUE_MAX')
+        SEM_TIMED_WAIT = platform.Has('sem_timedwait')
 
     config = platform.configure(CConfig)
-    TIMEVAL       = config['TIMEVAL']
-    TIMESPEC      = config['TIMESPEC']
-    TIMEVALP      = rffi.CArrayPtr(TIMEVAL)
-    TIMESPECP     = rffi.CArrayPtr(TIMESPEC)
-    SEM_T         = rffi.COpaquePtr('sem_t', compilation_info=eci)
-    SEM_FAILED    = rffi.cast(SEM_T, config['SEM_FAILED'])
-    SEM_VALUE_MAX = config['SEM_VALUE_MAX']
+    TIMEVAL        = config['TIMEVAL']
+    TIMESPEC       = config['TIMESPEC']
+    TIMEVALP       = rffi.CArrayPtr(TIMEVAL)
+    TIMESPECP      = rffi.CArrayPtr(TIMESPEC)
+    SEM_T          = rffi.COpaquePtr('sem_t', compilation_info=eci)
+    SEM_FAILED     = rffi.cast(SEM_T, config['SEM_FAILED'])
+    SEM_VALUE_MAX  = config['SEM_VALUE_MAX']
+    SEM_TIMED_WAIT = config['SEM_TIMED_WAIT']
     HAVE_BROKEN_SEM_GETVALUE = False
 
     def external(name, args, result):
@@ -71,12 +74,14 @@
     _sem_unlink = external('sem_unlink', [rffi.CCHARP], rffi.INT)
     _sem_wait = external('sem_wait', [SEM_T], rffi.INT)
     _sem_trywait = external('sem_trywait', [SEM_T], rffi.INT)
-    _sem_timedwait = external('sem_timedwait', [SEM_T, TIMESPECP], rffi.INT)
     _sem_post = external('sem_post', [SEM_T], rffi.INT)
     _sem_getvalue = external('sem_getvalue', [SEM_T, rffi.INTP], rffi.INT)
 
     _gettimeofday = external('gettimeofday', [TIMEVALP, rffi.VOIDP], rffi.INT)
 
+    _select = external('select', [rffi.INT, rffi.VOIDP, rffi.VOIDP, rffi.VOIDP,
+                                                          TIMEVALP], rffi.INT)
+
     def sem_open(name, oflag, mode, value):
         res = _sem_open(name, oflag, mode, value)
         if res == SEM_FAILED:
@@ -103,6 +108,48 @@
         if res < 0:
             raise OSError(rposix.get_errno(), "sem_timedwait failed")
 
+    def _sem_timedwait_save(sem, deadline):
+        delay = 0
+        void = lltype.nullptr(rffi.VOIDP.TO)
+        with lltype.scoped_alloc(TIMEVALP.TO, 1) as tvdeadline:
+            while True:
+                # poll
+                if _sem_trywait(sem) == 0:
+                    return 0
+                elif rposix.get_errno() != errno.EAGAIN:
+                    return -1
+
+                now = gettimeofday()
+                c_tv_sec = rffi.getintfield(deadline[0], 'c_tv_sec')
+                c_tv_nsec = rffi.getintfield(deadline[0], 'c_tv_nsec')
+                if (c_tv_sec < now[0] or
+                    (c_tv_sec == now[0] and c_tv_nsec <= now[1])):
+                    rposix.set_errno(errno.ETIMEDOUT)
+                    return -1
+
+
+                # calculate how much time is left
+                difference = ((c_tv_sec - now[0]) * 1000000 +
+                                    (c_tv_nsec - now[1]))
+
+                # check delay not too long -- maximum is 20 msecs
+                if delay > 20000:
+                    delay = 20000
+                if delay > difference:
+                    delay = difference
+                delay += 1000
+
+                # sleep
+                rffi.setintfield(tvdeadline[0], 'c_tv_sec', delay / 1000000)
+                rffi.setintfield(tvdeadline[0], 'c_tv_usec', delay % 1000000)
+                if _select(0, void, void, void, tvdeadline) < 0:
+                    return -1
+
+    if SEM_TIMED_WAIT:
+        _sem_timedwait = external('sem_timedwait', [SEM_T, TIMESPECP], rffi.INT)
+    else:
+        _sem_timedwait = _sem_timedwait_save
+
     def sem_post(sem):
         res = _sem_post(sem)
         if res < 0:


More information about the Pypy-commit mailing list