Commits

Trent Nelson committed 7d25d21 Draft

Working checkpoint commit (test_primitives and test_work).

Comments (0)

Files changed (12)

     void   *px;                         \
     size_t  px_flags;                   \
     void   *srw_lock;                   \
+    void   *event;                      \
     struct _object *_ob_next;           \
     struct _object *_ob_prev;
 
     (void *)_Py_NOT_PARALLEL,           \
     0,                                  \
     NULL,                               \
+    NULL,                               \
     (struct _object *)_Py_NOT_PARALLEL, \
     (struct _object *)_Py_NOT_PARALLEL,
 #endif /* WITH_PARALLEL */

Include/objimpl.h

     op->px    = _Py_NOT_PARALLEL;
     op->px_flags = 0;
     op->srw_lock = NULL;
+    op->event    = NULL;
 #ifdef Py_TRACE_REFS
     op->_ob_next = NULL;
     op->_ob_prev = NULL;

Include/pyparallel.h

 
 #define Py_PXFLAGS_DEFAULT              (0)
 #define Py_PXFLAGS_ISPX                 (1UL <<  1)
-#define Py_PXFLAGS_SRWLOCK              (1UL <<  2)
+#define Py_PXFLAGS_RWLOCK               (1UL <<  2)
+#define Py_PXFLAGS_EVENT                (1UL <<  3)
+
+#define Py_HAS_RWLOCK(o)  (Py_PXFLAGS((o)) & Py_PXFLAGS_RWLOCK)
+#define Py_HAS_EVENT(o)   (Py_PXFLAGS((o)) & Py_PXFLAGS_EVENT)
 
 PyAPI_DATA(long) Py_MainThreadId;
 PyAPI_DATA(long) Py_MainProcessId;
 
 PyAPI_FUNC(int)     _Px_TEST(void *p);
 #ifdef Py_DEBUG
-
 PyAPI_FUNC(int)     _Py_ISPY(void *ob);
 PyAPI_FUNC(int)     _Py_PXCTX(void);
 

Lib/async/__init__.py

 import _async
 
-from _async import (
-    run,
-    client,
-    server,
-    run_once,
-    protect,
-    unprotect,
-    protected,
-)
+from _async import *
 
 def call_from_main_thread_and_wait(f):
     def decorator(*_args, **_kwds):
         _async.call_from_main_thread(f, _args, _kwds)
     return decorator
 
-RECEIVE_MODE_DATA = 1
-RECEIVE_MODE_LINE = 2
+def synchronized(f):
+    cs = _async.critical_section()
+    def decorator(*_args, **_kwds):
+        cs.enter()
+        f(*_args, **_kwds)
+        cs.leave()
+    return decorator
+
+def submit_work(func, args=None, kwds=None, callback=None, errback=None):
+    _async.submit_work(func, args, kwds, callback, errback)
+
+def submit_wait(obj, func, args=None, kwds=None, callback=None, errback=None):
+    raise NotImplementedError
+    _async.submit_wait(obj, func, args, kwds, callback, errback)
+
+def wait_any(waits):
+    raise NotImplementedError
+
+def wait_all(waits):
+    raise NotImplementedError
 
 # vim:set ts=8 sw=4 sts=4 tw=78 et:

Lib/async/test/test_primitives.py

+import unittest
+import async
+import time
+
+class _object(dict):
+    def __init__(self, **kwds):
+        self.__dict__.update(**kwds)
+
+class TestProtect(unittest.TestCase):
+
+    def test_protect_basic(self):
+        o = _object()
+        async.protect(o)
+        self.assertEqual(async.protected(o), True)
+        async.unprotect(o)
+        self.assertEqual(async.protected(o), False)
+
+    def test_protect_getattr(self):
+        o = _object(foo='bar')
+        async.protect(o)
+        self.assertEqual(async.protected(o), True)
+        self.assertEqual(o.foo, 'bar')
+        async.unprotect(o)
+        self.assertEqual(o.foo, 'bar')
+        self.assertEqual(async.protected(o), False)
+
+    def test_protect_setattr(self):
+        o = _object(foo=None)
+        async.protect(o)
+        self.assertEqual(async.protected(o), True)
+        o.foo = 'bar'
+        self.assertEqual(o.foo, 'bar')
+        async.unprotect(o)
+        self.assertEqual(o.foo, 'bar')
+        o.foo = 'foo'
+        self.assertEqual(o.foo, 'foo')
+        self.assertEqual(async.protected(o), False)
+
+    def test_protect_both(self):
+        o = _object(foo='bar', cat=None)
+        async.protect(o)
+        self.assertEqual(async.protected(o), True)
+        o.cat = 'dog'
+        self.assertEqual(o.foo, 'bar')
+        self.assertEqual(o.cat, 'dog')
+        async.unprotect(o)
+        self.assertEqual(o.foo, 'bar')
+        self.assertEqual(o.cat, 'dog')
+        self.assertEqual(async.protected(o), False)
+
+class TestProtectionError(unittest.TestCase):
+    def test_protection_error_basic(self):
+        o = _object()
+        self.assertRaises(async.ProtectionError, async.read_lock, o)
+        self.assertRaises(async.ProtectionError, async.read_unlock, o)
+        self.assertRaises(async.ProtectionError, async.try_read_lock, o)
+
+        self.assertRaises(async.ProtectionError, async.write_lock, o)
+        self.assertRaises(async.ProtectionError, async.write_unlock, o)
+        self.assertRaises(async.ProtectionError, async.try_write_lock, o)
+
+    def test_protection_error_in_async_callback(self):
+        def callback():
+            o = _object()
+            self.assertRaises(async.ProtectionError, async.protect, o)
+            self.assertRaises(async.ProtectionError, async.unprotect, o)
+            self.assertRaises(async.ProtectionError, async.wait, o)
+
+        async.submit_work(callback)
+        async.run()
+
+class TestAsyncSignalAndWait(unittest.TestCase):
+    def test_nowaiters_error(self):
+        o = async.protect(object())
+        self.assertRaises(async.NoWaitersError, async.signal, o)
+
+    def test_nowaiters_error_from_callback(self):
+        o = async.protect(object())
+
+        def callback():
+            self.assertRaises(async.NoWaitersError, async.signal, o)
+        async.submit_work(callback)
+        async.run()
+
+    def test_wait_error_from_callback(self):
+        o = async.protect(object())
+
+        def callback():
+            self.assertRaises(async.WaitError, async.wait, o)
+
+        async.submit_work(callback)
+        async.run()
+
+class TestAsyncProtection(unittest.TestCase):
+    def _test_basic(self):
+        d = {}
+        o = object()
+        async.protect(o)
+
+        @async.call_from_main_thread_and_wait
+        def _timestamp(name):
+            d[name] = async.rdtsc()
+
+        def reader(name):
+            async.read_lock(o)
+            async.signal(o)         # start writer callback
+            async.wait(o)           # wait for writer callback
+            _timestamp(name)
+            async.read_unlock(o)
+
+        def writer(name):
+            async.signal(o)         # tell the reader we've entered
+            async.write_lock(o)     # will be blocked until reader unlocks
+            _timestamp(name)
+            async.write_unlock(o)
+            async.signal(o)         # tell the main thread we're done
+
+        async.submit_wait(o, writer, 'w')
+        async.submit_work(reader, 'r')
+        async.run()
+        self.assertGreater(d['w'], d['r'])
+
+if __name__ == '__main__':
+    unittest.main()
+
+# vim:set ts=8 sw=4 sts=4 tw=78 et:

Lib/async/test/test_protect.py

 import unittest
 import async
+import time
+
+class _object(dict):
+    def __init__(self, **kwds):
+        self.__dict__.update(**kwds)
 
 class TestProtect(unittest.TestCase):
 
     def test_protect_basic(self):
-        o = object()
+        o = _object()
         async.protect(o)
         self.assertEqual(async.protected(o), True)
         async.unprotect(o)
         self.assertEqual(async.protected(o), False)
 
+    def test_protect_getattr(self):
+        o = _object(foo='bar')
+        async.protect(o)
+        self.assertEqual(async.protected(o), True)
+        self.assertEqual(o.foo, 'bar')
+        async.unprotect(o)
+        self.assertEqual(o.foo, 'bar')
+        self.assertEqual(async.protected(o), False)
+
+    def test_protect_setattr(self):
+        o = _object(foo=None)
+        async.protect(o)
+        self.assertEqual(async.protected(o), True)
+        o.foo = 'bar'
+        self.assertEqual(o.foo, 'bar')
+        async.unprotect(o)
+        self.assertEqual(o.foo, 'bar')
+        o.foo = 'foo'
+        self.assertEqual(o.foo, 'foo')
+        self.assertEqual(async.protected(o), False)
+
+    def test_protect_both(self):
+        o = _object(foo='bar', cat=None)
+        async.protect(o)
+        self.assertEqual(async.protected(o), True)
+        o.cat = 'dog'
+        self.assertEqual(o.foo, 'bar')
+        self.assertEqual(o.cat, 'dog')
+        async.unprotect(o)
+        self.assertEqual(o.foo, 'bar')
+        self.assertEqual(o.cat, 'dog')
+        self.assertEqual(async.protected(o), False)
+
+class TestProtectionError(unittest.TestCase):
+    def test_protection_error_basic(self):
+        o = _object()
+        self.assertRaises(async.ProtectionError, async.read_lock, o)
+        self.assertRaises(async.ProtectionError, async.read_unlock, o)
+        self.assertRaises(async.ProtectionError, async.try_read_lock, o)
+
+        self.assertRaises(async.ProtectionError, async.write_lock, o)
+        self.assertRaises(async.ProtectionError, async.write_unlock, o)
+        self.assertRaises(async.ProtectionError, async.try_write_lock, o)
+
+    def test_protection_error_in_async_callback(self):
+        def callback():
+            o = _object()
+            self.assertRaises(async.ProtectionError, async.protect, o)
+            self.assertRaises(async.ProtectionError, async.unprotect, o)
+            self.assertRaises(async.ProtectionError, async.wait, o)
+
+        async.submit_work(callback)
+        async.run()
+
+class TestAsyncSignalAndWait(unittest.TestCase):
+    def test_nowaiters_error_from_callback(self):
+        o = _object()
+        def callback():
+            self.assertRaises(async.NoWaitersError, async.signal, o)
+
+        async.submit_work(callback)
+        async.run()
+
+    def test_nowaiters_error_from_callback(self):
+        o = _object()
+        def callback():
+            self.assertRaises(async.NoWaitersError, async.signal, o)
+
+        async.submit_work(callback)
+        async.run()
+
+class TestAsyncProtection(unittest.TestCase):
+    def test_basic(self):
+        d = {}
+        o = object()
+        async.protect(o)
+
+        @async.call_from_main_thread_and_wait
+        def _timestamp(name):
+            d[name] = async.rdtsc()
+
+        def reader(name):
+            async.read_lock(o)
+            async.signal(o)         # start writer callback
+            async.wait(o)           # wait for writer callback
+            _timestamp(name)
+            async.read_unlock(o)
+
+        def writer(name):
+            async.signal(o)         # tell the reader we've entered
+            async.write_lock(o)     # will be blocked until reader unlocks
+            _timestamp(name)
+            async.write_unlock(o)
+            async.signal(o)         # tell the main thread we're done
+
+        async.submit_wait(o, writer, 'w')
+        async.submit_work(reader, 'r')
+        async.run()
+        self.assertGreater(d['w'], d['r'])
+
 if __name__ == '__main__':
     unittest.main()
 

Lib/async/test/test_work.py

         _async.submit_work(f, None, None, None, eb)
         _async.run()
 
-class TestProtect(unittest.TestCase):
-
-    def test_protect_basic(self):
-        o = object()
-        async.protect(o)
-        self.assertEqual(async.protected(o), True)
-        async.unprotect(o)
-        self.assertEqual(async.protected(o), False)
-
-
 
 if __name__ == '__main__':
     unittest.main()

Lib/distutils/command/wininst-10.0-amd64.exe

Binary file modified.
     _Py_NOT_PARALLEL,
     0,
     NULL,
+    NULL,
     &refchain,
     &refchain
 };
 PyObject *
 PyObject_GenericGetAttr(PyObject *obj, PyObject *name)
 {
-    if (!obj->px_flags & Py_PXFLAGS_SRWLOCK)
+    if (!obj->px_flags & Py_PXFLAGS_RWLOCK)
         return _PyObject_GenericGetAttrWithDict(obj, name, NULL);
 
     AcquireSRWLockShared((PSRWLOCK)&(obj->srw_lock));
         );
         return -1;
     }
-    if (!obj->px_flags & Py_PXFLAGS_SRWLOCK)
+    if (!obj->px_flags & Py_PXFLAGS_RWLOCK)
         return _PyObject_GenericSetAttrWithDict(obj, name, value, NULL);
 
     AcquireSRWLockExclusive((PSRWLOCK)&(obj->srw_lock));

PCbuild/pcbuild.sln

 		{F0E0541E-F17D-430B-97C4-93ADF0DD284E}.Debug|Win32.ActiveCfg = Debug|Win32
 		{F0E0541E-F17D-430B-97C4-93ADF0DD284E}.Debug|Win32.Build.0 = Debug|Win32
 		{F0E0541E-F17D-430B-97C4-93ADF0DD284E}.Debug|x64.ActiveCfg = Debug|Win32
-		{F0E0541E-F17D-430B-97C4-93ADF0DD284E}.Debug|x64.Build.0 = Debug|Win32
 		{F0E0541E-F17D-430B-97C4-93ADF0DD284E}.PGInstrument|Win32.ActiveCfg = Release|Win32
 		{F0E0541E-F17D-430B-97C4-93ADF0DD284E}.PGInstrument|Win32.Build.0 = Release|Win32
 		{F0E0541E-F17D-430B-97C4-93ADF0DD284E}.PGInstrument|x64.ActiveCfg = Release|Win32
 		{F4229CC3-873C-49AE-9729-DD308ED4CD4A}.Debug|Win32.ActiveCfg = Debug|Win32
 		{F4229CC3-873C-49AE-9729-DD308ED4CD4A}.Debug|Win32.Build.0 = Debug|Win32
 		{F4229CC3-873C-49AE-9729-DD308ED4CD4A}.Debug|x64.ActiveCfg = Debug|x64
-		{F4229CC3-873C-49AE-9729-DD308ED4CD4A}.Debug|x64.Build.0 = Debug|x64
 		{F4229CC3-873C-49AE-9729-DD308ED4CD4A}.PGInstrument|Win32.ActiveCfg = PGInstrument|Win32
 		{F4229CC3-873C-49AE-9729-DD308ED4CD4A}.PGInstrument|Win32.Build.0 = PGInstrument|Win32
 		{F4229CC3-873C-49AE-9729-DD308ED4CD4A}.PGInstrument|x64.ActiveCfg = PGInstrument|x64
 		{E9E0A1F6-0009-4E8C-B8F8-1B8F5D49A058}.Debug|Win32.ActiveCfg = Debug|Win32
 		{E9E0A1F6-0009-4E8C-B8F8-1B8F5D49A058}.Debug|Win32.Build.0 = Debug|Win32
 		{E9E0A1F6-0009-4E8C-B8F8-1B8F5D49A058}.Debug|x64.ActiveCfg = Debug|x64
-		{E9E0A1F6-0009-4E8C-B8F8-1B8F5D49A058}.Debug|x64.Build.0 = Debug|x64
 		{E9E0A1F6-0009-4E8C-B8F8-1B8F5D49A058}.PGInstrument|Win32.ActiveCfg = PGInstrument|Win32
 		{E9E0A1F6-0009-4E8C-B8F8-1B8F5D49A058}.PGInstrument|Win32.Build.0 = PGInstrument|Win32
 		{E9E0A1F6-0009-4E8C-B8F8-1B8F5D49A058}.PGInstrument|x64.ActiveCfg = PGInstrument|x64
 		{C73F0EC1-358B-4177-940F-0846AC8B04CD}.Debug|Win32.ActiveCfg = Release|Win32
 		{C73F0EC1-358B-4177-940F-0846AC8B04CD}.Debug|Win32.Build.0 = Release|Win32
 		{C73F0EC1-358B-4177-940F-0846AC8B04CD}.Debug|x64.ActiveCfg = Release|Win32
-		{C73F0EC1-358B-4177-940F-0846AC8B04CD}.Debug|x64.Build.0 = Release|Win32
 		{C73F0EC1-358B-4177-940F-0846AC8B04CD}.PGInstrument|Win32.ActiveCfg = Release|Win32
 		{C73F0EC1-358B-4177-940F-0846AC8B04CD}.PGInstrument|Win32.Build.0 = Release|Win32
 		{C73F0EC1-358B-4177-940F-0846AC8B04CD}.PGInstrument|x64.ActiveCfg = Release|Win32
 		{28B5D777-DDF2-4B6B-B34F-31D938813856}.Debug|Win32.ActiveCfg = Debug|Win32
 		{28B5D777-DDF2-4B6B-B34F-31D938813856}.Debug|Win32.Build.0 = Debug|Win32
 		{28B5D777-DDF2-4B6B-B34F-31D938813856}.Debug|x64.ActiveCfg = Debug|x64
-		{28B5D777-DDF2-4B6B-B34F-31D938813856}.Debug|x64.Build.0 = Debug|x64
 		{28B5D777-DDF2-4B6B-B34F-31D938813856}.PGInstrument|Win32.ActiveCfg = PGInstrument|Win32
 		{28B5D777-DDF2-4B6B-B34F-31D938813856}.PGInstrument|Win32.Build.0 = PGInstrument|Win32
 		{28B5D777-DDF2-4B6B-B34F-31D938813856}.PGInstrument|x64.ActiveCfg = PGInstrument|x64
 		{0E9791DB-593A-465F-98BC-681011311617}.Debug|Win32.ActiveCfg = Debug|Win32
 		{0E9791DB-593A-465F-98BC-681011311617}.Debug|Win32.Build.0 = Debug|Win32
 		{0E9791DB-593A-465F-98BC-681011311617}.Debug|x64.ActiveCfg = Debug|x64
-		{0E9791DB-593A-465F-98BC-681011311617}.Debug|x64.Build.0 = Debug|x64
 		{0E9791DB-593A-465F-98BC-681011311617}.PGInstrument|Win32.ActiveCfg = PGInstrument|Win32
 		{0E9791DB-593A-465F-98BC-681011311617}.PGInstrument|Win32.Build.0 = PGInstrument|Win32
 		{0E9791DB-593A-465F-98BC-681011311617}.PGInstrument|x64.ActiveCfg = PGInstrument|x64
 		{0E9791DB-593A-465F-98BC-681011311618}.Debug|Win32.ActiveCfg = Debug|Win32
 		{0E9791DB-593A-465F-98BC-681011311618}.Debug|Win32.Build.0 = Debug|Win32
 		{0E9791DB-593A-465F-98BC-681011311618}.Debug|x64.ActiveCfg = Debug|x64
-		{0E9791DB-593A-465F-98BC-681011311618}.Debug|x64.Build.0 = Debug|x64
 		{0E9791DB-593A-465F-98BC-681011311618}.PGInstrument|Win32.ActiveCfg = PGInstrument|Win32
 		{0E9791DB-593A-465F-98BC-681011311618}.PGInstrument|Win32.Build.0 = PGInstrument|Win32
 		{0E9791DB-593A-465F-98BC-681011311618}.PGInstrument|x64.ActiveCfg = PGInstrument|x64
 		{9EC7190A-249F-4180-A900-548FDCF3055F}.Debug|Win32.ActiveCfg = Debug|Win32
 		{9EC7190A-249F-4180-A900-548FDCF3055F}.Debug|Win32.Build.0 = Debug|Win32
 		{9EC7190A-249F-4180-A900-548FDCF3055F}.Debug|x64.ActiveCfg = Debug|x64
-		{9EC7190A-249F-4180-A900-548FDCF3055F}.Debug|x64.Build.0 = Debug|x64
 		{9EC7190A-249F-4180-A900-548FDCF3055F}.PGInstrument|Win32.ActiveCfg = PGInstrument|Win32
 		{9EC7190A-249F-4180-A900-548FDCF3055F}.PGInstrument|Win32.Build.0 = PGInstrument|Win32
 		{9EC7190A-249F-4180-A900-548FDCF3055F}.PGInstrument|x64.ActiveCfg = PGInstrument|x64
 		{17E1E049-C309-4D79-843F-AE483C264AEA}.Debug|Win32.ActiveCfg = Debug|Win32
 		{17E1E049-C309-4D79-843F-AE483C264AEA}.Debug|Win32.Build.0 = Debug|Win32
 		{17E1E049-C309-4D79-843F-AE483C264AEA}.Debug|x64.ActiveCfg = Debug|x64
-		{17E1E049-C309-4D79-843F-AE483C264AEA}.Debug|x64.Build.0 = Debug|x64
 		{17E1E049-C309-4D79-843F-AE483C264AEA}.PGInstrument|Win32.ActiveCfg = PGInstrument|Win32
 		{17E1E049-C309-4D79-843F-AE483C264AEA}.PGInstrument|Win32.Build.0 = PGInstrument|Win32
 		{17E1E049-C309-4D79-843F-AE483C264AEA}.PGInstrument|x64.ActiveCfg = PGInstrument|x64
 		{31FFC478-7B4A-43E8-9954-8D03E2187E9C}.Debug|Win32.ActiveCfg = Debug|Win32
 		{31FFC478-7B4A-43E8-9954-8D03E2187E9C}.Debug|Win32.Build.0 = Debug|Win32
 		{31FFC478-7B4A-43E8-9954-8D03E2187E9C}.Debug|x64.ActiveCfg = Debug|x64
-		{31FFC478-7B4A-43E8-9954-8D03E2187E9C}.Debug|x64.Build.0 = Debug|x64
 		{31FFC478-7B4A-43E8-9954-8D03E2187E9C}.PGInstrument|Win32.ActiveCfg = PGInstrument|Win32
 		{31FFC478-7B4A-43E8-9954-8D03E2187E9C}.PGInstrument|Win32.Build.0 = PGInstrument|Win32
 		{31FFC478-7B4A-43E8-9954-8D03E2187E9C}.PGInstrument|x64.ActiveCfg = PGInstrument|x64
 		{13CECB97-4119-4316-9D42-8534019A5A44}.Debug|Win32.ActiveCfg = Debug|Win32
 		{13CECB97-4119-4316-9D42-8534019A5A44}.Debug|Win32.Build.0 = Debug|Win32
 		{13CECB97-4119-4316-9D42-8534019A5A44}.Debug|x64.ActiveCfg = Debug|x64
-		{13CECB97-4119-4316-9D42-8534019A5A44}.Debug|x64.Build.0 = Debug|x64
 		{13CECB97-4119-4316-9D42-8534019A5A44}.PGInstrument|Win32.ActiveCfg = PGInstrument|Win32
 		{13CECB97-4119-4316-9D42-8534019A5A44}.PGInstrument|Win32.Build.0 = PGInstrument|Win32
 		{13CECB97-4119-4316-9D42-8534019A5A44}.PGInstrument|x64.ActiveCfg = PGInstrument|x64
 		{C6E20F84-3247-4AD6-B051-B073268F73BA}.Debug|Win32.ActiveCfg = Debug|Win32
 		{C6E20F84-3247-4AD6-B051-B073268F73BA}.Debug|Win32.Build.0 = Debug|Win32
 		{C6E20F84-3247-4AD6-B051-B073268F73BA}.Debug|x64.ActiveCfg = Debug|x64
-		{C6E20F84-3247-4AD6-B051-B073268F73BA}.Debug|x64.Build.0 = Debug|x64
 		{C6E20F84-3247-4AD6-B051-B073268F73BA}.PGInstrument|Win32.ActiveCfg = PGInstrument|Win32
 		{C6E20F84-3247-4AD6-B051-B073268F73BA}.PGInstrument|Win32.Build.0 = PGInstrument|Win32
 		{C6E20F84-3247-4AD6-B051-B073268F73BA}.PGInstrument|x64.ActiveCfg = PGInstrument|x64
 		{6901D91C-6E48-4BB7-9FEC-700C8131DF1D}.Debug|Win32.ActiveCfg = Debug|Win32
 		{6901D91C-6E48-4BB7-9FEC-700C8131DF1D}.Debug|Win32.Build.0 = Debug|Win32
 		{6901D91C-6E48-4BB7-9FEC-700C8131DF1D}.Debug|x64.ActiveCfg = Debug|x64
-		{6901D91C-6E48-4BB7-9FEC-700C8131DF1D}.Debug|x64.Build.0 = Debug|x64
 		{6901D91C-6E48-4BB7-9FEC-700C8131DF1D}.PGInstrument|Win32.ActiveCfg = PGInstrument|Win32
 		{6901D91C-6E48-4BB7-9FEC-700C8131DF1D}.PGInstrument|Win32.Build.0 = PGInstrument|Win32
 		{6901D91C-6E48-4BB7-9FEC-700C8131DF1D}.PGInstrument|x64.ActiveCfg = PGInstrument|x64
 		{36D0C52C-DF4E-45D0-8BC7-E294C3ABC781}.Debug|Win32.ActiveCfg = Debug|Win32
 		{36D0C52C-DF4E-45D0-8BC7-E294C3ABC781}.Debug|Win32.Build.0 = Debug|Win32
 		{36D0C52C-DF4E-45D0-8BC7-E294C3ABC781}.Debug|x64.ActiveCfg = Debug|x64
-		{36D0C52C-DF4E-45D0-8BC7-E294C3ABC781}.Debug|x64.Build.0 = Debug|x64
 		{36D0C52C-DF4E-45D0-8BC7-E294C3ABC781}.PGInstrument|Win32.ActiveCfg = PGInstrument|Win32
 		{36D0C52C-DF4E-45D0-8BC7-E294C3ABC781}.PGInstrument|Win32.Build.0 = PGInstrument|Win32
 		{36D0C52C-DF4E-45D0-8BC7-E294C3ABC781}.PGInstrument|x64.ActiveCfg = PGInstrument|x64
 		{4946ECAC-2E69-4BF8-A90A-F5136F5094DF}.Debug|Win32.ActiveCfg = Debug|Win32
 		{4946ECAC-2E69-4BF8-A90A-F5136F5094DF}.Debug|Win32.Build.0 = Debug|Win32
 		{4946ECAC-2E69-4BF8-A90A-F5136F5094DF}.Debug|x64.ActiveCfg = Debug|x64
-		{4946ECAC-2E69-4BF8-A90A-F5136F5094DF}.Debug|x64.Build.0 = Debug|x64
 		{4946ECAC-2E69-4BF8-A90A-F5136F5094DF}.PGInstrument|Win32.ActiveCfg = PGInstrument|Win32
 		{4946ECAC-2E69-4BF8-A90A-F5136F5094DF}.PGInstrument|Win32.Build.0 = PGInstrument|Win32
 		{4946ECAC-2E69-4BF8-A90A-F5136F5094DF}.PGInstrument|x64.ActiveCfg = PGInstrument|x64
 		{73FCD2BD-F133-46B7-8EC1-144CD82A59D5}.Debug|Win32.ActiveCfg = Debug|Win32
 		{73FCD2BD-F133-46B7-8EC1-144CD82A59D5}.Debug|Win32.Build.0 = Debug|Win32
 		{73FCD2BD-F133-46B7-8EC1-144CD82A59D5}.Debug|x64.ActiveCfg = Debug|x64
-		{73FCD2BD-F133-46B7-8EC1-144CD82A59D5}.Debug|x64.Build.0 = Debug|x64
 		{73FCD2BD-F133-46B7-8EC1-144CD82A59D5}.PGInstrument|Win32.ActiveCfg = PGInstrument|Win32
 		{73FCD2BD-F133-46B7-8EC1-144CD82A59D5}.PGInstrument|Win32.Build.0 = PGInstrument|Win32
 		{73FCD2BD-F133-46B7-8EC1-144CD82A59D5}.PGInstrument|x64.ActiveCfg = PGInstrument|x64
 		{18CAE28C-B454-46C1-87A0-493D91D97F03}.Debug|Win32.ActiveCfg = Debug|Win32
 		{18CAE28C-B454-46C1-87A0-493D91D97F03}.Debug|Win32.Build.0 = Debug|Win32
 		{18CAE28C-B454-46C1-87A0-493D91D97F03}.Debug|x64.ActiveCfg = Debug|x64
-		{18CAE28C-B454-46C1-87A0-493D91D97F03}.Debug|x64.Build.0 = Debug|x64
 		{18CAE28C-B454-46C1-87A0-493D91D97F03}.PGInstrument|Win32.ActiveCfg = PGInstrument|Win32
 		{18CAE28C-B454-46C1-87A0-493D91D97F03}.PGInstrument|Win32.Build.0 = PGInstrument|Win32
 		{18CAE28C-B454-46C1-87A0-493D91D97F03}.PGInstrument|x64.ActiveCfg = PGInstrument|x64
 		{F9D71780-F393-11E0-BE50-0800200C9A66}.Debug|Win32.ActiveCfg = Debug|Win32
 		{F9D71780-F393-11E0-BE50-0800200C9A66}.Debug|Win32.Build.0 = Debug|Win32
 		{F9D71780-F393-11E0-BE50-0800200C9A66}.Debug|x64.ActiveCfg = Debug|x64
-		{F9D71780-F393-11E0-BE50-0800200C9A66}.Debug|x64.Build.0 = Debug|x64
 		{F9D71780-F393-11E0-BE50-0800200C9A66}.PGInstrument|Win32.ActiveCfg = PGInstrument|Win32
 		{F9D71780-F393-11E0-BE50-0800200C9A66}.PGInstrument|Win32.Build.0 = PGInstrument|Win32
 		{F9D71780-F393-11E0-BE50-0800200C9A66}.PGInstrument|x64.ActiveCfg = PGInstrument|x64
 		{ECC7CEAC-A5E5-458E-BB9E-2413CC847881}.Debug|Win32.ActiveCfg = Debug|Win32
 		{ECC7CEAC-A5E5-458E-BB9E-2413CC847881}.Debug|Win32.Build.0 = Debug|Win32
 		{ECC7CEAC-A5E5-458E-BB9E-2413CC847881}.Debug|x64.ActiveCfg = Debug|x64
-		{ECC7CEAC-A5E5-458E-BB9E-2413CC847881}.Debug|x64.Build.0 = Debug|x64
 		{ECC7CEAC-A5E5-458E-BB9E-2413CC847881}.PGInstrument|Win32.ActiveCfg = PGInstrument|Win32
 		{ECC7CEAC-A5E5-458E-BB9E-2413CC847881}.PGInstrument|Win32.Build.0 = PGInstrument|Win32
 		{ECC7CEAC-A5E5-458E-BB9E-2413CC847881}.PGInstrument|x64.ActiveCfg = PGInstrument|x64
 		{D06B6426-4762-44CC-8BAD-D79052507F2F}.Debug|Win32.ActiveCfg = Debug|Win32
 		{D06B6426-4762-44CC-8BAD-D79052507F2F}.Debug|Win32.Build.0 = Debug|Win32
 		{D06B6426-4762-44CC-8BAD-D79052507F2F}.Debug|x64.ActiveCfg = Debug|x64
-		{D06B6426-4762-44CC-8BAD-D79052507F2F}.Debug|x64.Build.0 = Debug|x64
 		{D06B6426-4762-44CC-8BAD-D79052507F2F}.PGInstrument|Win32.ActiveCfg = PGInstrument|Win32
 		{D06B6426-4762-44CC-8BAD-D79052507F2F}.PGInstrument|Win32.Build.0 = PGInstrument|Win32
 		{D06B6426-4762-44CC-8BAD-D79052507F2F}.PGInstrument|x64.ActiveCfg = PGInstrument|x64
 		{D06B6426-4762-44CC-8BAD-D79052507F2F}.Release|x64.Build.0 = Release|x64
 		{EB1C19C1-1F18-421E-9735-CAEE69DC6A3C}.Debug|Win32.ActiveCfg = Release|Win32
 		{EB1C19C1-1F18-421E-9735-CAEE69DC6A3C}.Debug|x64.ActiveCfg = Release|x64
-		{EB1C19C1-1F18-421E-9735-CAEE69DC6A3C}.Debug|x64.Build.0 = Release|x64
 		{EB1C19C1-1F18-421E-9735-CAEE69DC6A3C}.PGInstrument|Win32.ActiveCfg = Release|Win32
 		{EB1C19C1-1F18-421E-9735-CAEE69DC6A3C}.PGInstrument|x64.ActiveCfg = Release|x64
 		{EB1C19C1-1F18-421E-9735-CAEE69DC6A3C}.PGUpdate|Win32.ActiveCfg = Release|Win32
 		{447F05A8-F581-4CAC-A466-5AC7936E207E}.Debug|Win32.ActiveCfg = Debug|Win32
 		{447F05A8-F581-4CAC-A466-5AC7936E207E}.Debug|Win32.Build.0 = Debug|Win32
 		{447F05A8-F581-4CAC-A466-5AC7936E207E}.Debug|x64.ActiveCfg = Debug|x64
-		{447F05A8-F581-4CAC-A466-5AC7936E207E}.Debug|x64.Build.0 = Debug|x64
 		{447F05A8-F581-4CAC-A466-5AC7936E207E}.PGInstrument|Win32.ActiveCfg = PGInstrument|Win32
 		{447F05A8-F581-4CAC-A466-5AC7936E207E}.PGInstrument|Win32.Build.0 = PGInstrument|Win32
 		{447F05A8-F581-4CAC-A466-5AC7936E207E}.PGInstrument|x64.ActiveCfg = PGInstrument|x64
 		{A1A295E5-463C-437F-81CA-1F32367685DA}.Debug|Win32.ActiveCfg = Debug|Win32
 		{A1A295E5-463C-437F-81CA-1F32367685DA}.Debug|Win32.Build.0 = Debug|Win32
 		{A1A295E5-463C-437F-81CA-1F32367685DA}.Debug|x64.ActiveCfg = Debug|x64
-		{A1A295E5-463C-437F-81CA-1F32367685DA}.Debug|x64.Build.0 = Debug|x64
 		{A1A295E5-463C-437F-81CA-1F32367685DA}.PGInstrument|Win32.ActiveCfg = PGInstrument|Win32
 		{A1A295E5-463C-437F-81CA-1F32367685DA}.PGInstrument|Win32.Build.0 = PGInstrument|Win32
 		{A1A295E5-463C-437F-81CA-1F32367685DA}.PGInstrument|x64.ActiveCfg = PGInstrument|x64
 		{9E48B300-37D1-11DD-8C41-005056C00008}.Debug|Win32.ActiveCfg = Debug|Win32
 		{9E48B300-37D1-11DD-8C41-005056C00008}.Debug|Win32.Build.0 = Debug|Win32
 		{9E48B300-37D1-11DD-8C41-005056C00008}.Debug|x64.ActiveCfg = Debug|x64
-		{9E48B300-37D1-11DD-8C41-005056C00008}.Debug|x64.Build.0 = Debug|x64
 		{9E48B300-37D1-11DD-8C41-005056C00008}.PGInstrument|Win32.ActiveCfg = PGInstrument|Win32
 		{9E48B300-37D1-11DD-8C41-005056C00008}.PGInstrument|Win32.Build.0 = PGInstrument|Win32
 		{9E48B300-37D1-11DD-8C41-005056C00008}.PGInstrument|x64.ActiveCfg = PGInstrument|x64
 		{E5B04CC0-EB4C-42AB-B4DC-18EF95F864B0}.Debug|Win32.ActiveCfg = Debug|Win32
 		{E5B04CC0-EB4C-42AB-B4DC-18EF95F864B0}.Debug|Win32.Build.0 = Debug|Win32
 		{E5B04CC0-EB4C-42AB-B4DC-18EF95F864B0}.Debug|x64.ActiveCfg = Debug|x64
-		{E5B04CC0-EB4C-42AB-B4DC-18EF95F864B0}.Debug|x64.Build.0 = Debug|x64
 		{E5B04CC0-EB4C-42AB-B4DC-18EF95F864B0}.PGInstrument|Win32.ActiveCfg = PGInstrument|Win32
 		{E5B04CC0-EB4C-42AB-B4DC-18EF95F864B0}.PGInstrument|Win32.Build.0 = PGInstrument|Win32
 		{E5B04CC0-EB4C-42AB-B4DC-18EF95F864B0}.PGInstrument|x64.ActiveCfg = PGInstrument|x64
 		{6DE10744-E396-40A5-B4E2-1B69AA7C8D31}.Debug|Win32.ActiveCfg = Debug|Win32
 		{6DE10744-E396-40A5-B4E2-1B69AA7C8D31}.Debug|Win32.Build.0 = Debug|Win32
 		{6DE10744-E396-40A5-B4E2-1B69AA7C8D31}.Debug|x64.ActiveCfg = Debug|x64
-		{6DE10744-E396-40A5-B4E2-1B69AA7C8D31}.Debug|x64.Build.0 = Debug|x64
 		{6DE10744-E396-40A5-B4E2-1B69AA7C8D31}.PGInstrument|Win32.ActiveCfg = Release|Win32
 		{6DE10744-E396-40A5-B4E2-1B69AA7C8D31}.PGInstrument|Win32.Build.0 = Release|Win32
 		{6DE10744-E396-40A5-B4E2-1B69AA7C8D31}.PGInstrument|x64.ActiveCfg = Release|x64
 		{885D4898-D08D-4091-9C40-C700CFE3FC5A}.Release|x64.Build.0 = Release|x64
 		{F749B822-B489-4CA5-A3AD-CE078F5F338A}.Debug|Win32.ActiveCfg = Release|Win32
 		{F749B822-B489-4CA5-A3AD-CE078F5F338A}.Debug|x64.ActiveCfg = Release|x64
-		{F749B822-B489-4CA5-A3AD-CE078F5F338A}.Debug|x64.Build.0 = Release|x64
 		{F749B822-B489-4CA5-A3AD-CE078F5F338A}.PGInstrument|Win32.ActiveCfg = PGInstrument|Win32
 		{F749B822-B489-4CA5-A3AD-CE078F5F338A}.PGInstrument|Win32.Build.0 = PGInstrument|Win32
 		{F749B822-B489-4CA5-A3AD-CE078F5F338A}.PGInstrument|x64.ActiveCfg = PGInstrument|x64
 		{A2697BD3-28C1-4AEC-9106-8B748639FD16}.Debug|Win32.ActiveCfg = Debug|Win32
 		{A2697BD3-28C1-4AEC-9106-8B748639FD16}.Debug|Win32.Build.0 = Debug|Win32
 		{A2697BD3-28C1-4AEC-9106-8B748639FD16}.Debug|x64.ActiveCfg = Debug|x64
-		{A2697BD3-28C1-4AEC-9106-8B748639FD16}.Debug|x64.Build.0 = Debug|x64
 		{A2697BD3-28C1-4AEC-9106-8B748639FD16}.PGInstrument|Win32.ActiveCfg = PGInstrument|Win32
 		{A2697BD3-28C1-4AEC-9106-8B748639FD16}.PGInstrument|Win32.Build.0 = PGInstrument|Win32
 		{A2697BD3-28C1-4AEC-9106-8B748639FD16}.PGInstrument|x64.ActiveCfg = PGInstrument|x64
 		{7B2727B5-5A3F-40EE-A866-43A13CD31446}.Debug|Win32.ActiveCfg = Debug|Win32
 		{7B2727B5-5A3F-40EE-A866-43A13CD31446}.Debug|Win32.Build.0 = Debug|Win32
 		{7B2727B5-5A3F-40EE-A866-43A13CD31446}.Debug|x64.ActiveCfg = Debug|x64
-		{7B2727B5-5A3F-40EE-A866-43A13CD31446}.Debug|x64.Build.0 = Debug|x64
 		{7B2727B5-5A3F-40EE-A866-43A13CD31446}.PGInstrument|Win32.ActiveCfg = PGInstrument|Win32
 		{7B2727B5-5A3F-40EE-A866-43A13CD31446}.PGInstrument|Win32.Build.0 = PGInstrument|Win32
 		{7B2727B5-5A3F-40EE-A866-43A13CD31446}.PGInstrument|x64.ActiveCfg = PGInstrument|Win32
 		{1D4B18D3-7C12-4ECB-9179-8531FF876CE6}.Debug|Win32.ActiveCfg = Debug|Win32
 		{1D4B18D3-7C12-4ECB-9179-8531FF876CE6}.Debug|Win32.Build.0 = Debug|Win32
 		{1D4B18D3-7C12-4ECB-9179-8531FF876CE6}.Debug|x64.ActiveCfg = Debug|x64
-		{1D4B18D3-7C12-4ECB-9179-8531FF876CE6}.Debug|x64.Build.0 = Debug|x64
 		{1D4B18D3-7C12-4ECB-9179-8531FF876CE6}.PGInstrument|Win32.ActiveCfg = PGInstrument|Win32
 		{1D4B18D3-7C12-4ECB-9179-8531FF876CE6}.PGInstrument|Win32.Build.0 = PGInstrument|Win32
 		{1D4B18D3-7C12-4ECB-9179-8531FF876CE6}.PGInstrument|x64.ActiveCfg = PGInstrument|Win32
 		{19C0C13F-47CA-4432-AFF3-799A296A4DDC}.Debug|Win32.ActiveCfg = Debug|Win32
 		{19C0C13F-47CA-4432-AFF3-799A296A4DDC}.Debug|Win32.Build.0 = Debug|Win32
 		{19C0C13F-47CA-4432-AFF3-799A296A4DDC}.Debug|x64.ActiveCfg = Debug|x64
-		{19C0C13F-47CA-4432-AFF3-799A296A4DDC}.Debug|x64.Build.0 = Debug|x64
 		{19C0C13F-47CA-4432-AFF3-799A296A4DDC}.PGInstrument|Win32.ActiveCfg = Release|Win32
 		{19C0C13F-47CA-4432-AFF3-799A296A4DDC}.PGInstrument|x64.ActiveCfg = Release|Win32
 		{19C0C13F-47CA-4432-AFF3-799A296A4DDC}.PGUpdate|Win32.ActiveCfg = Release|Win32
 		{254A0C05-6696-4B08-8CB2-EF7D533AEE01}.Debug|Win32.ActiveCfg = Debug|Win32
 		{254A0C05-6696-4B08-8CB2-EF7D533AEE01}.Debug|Win32.Build.0 = Debug|Win32
 		{254A0C05-6696-4B08-8CB2-EF7D533AEE01}.Debug|x64.ActiveCfg = Debug|x64
-		{254A0C05-6696-4B08-8CB2-EF7D533AEE01}.Debug|x64.Build.0 = Debug|x64
 		{254A0C05-6696-4B08-8CB2-EF7D533AEE01}.PGInstrument|Win32.ActiveCfg = PGInstrument|Win32
 		{254A0C05-6696-4B08-8CB2-EF7D533AEE01}.PGInstrument|Win32.Build.0 = PGInstrument|Win32
 		{254A0C05-6696-4B08-8CB2-EF7D533AEE01}.PGInstrument|x64.ActiveCfg = PGInstrument|x64

Python/pyparallel.c

 
 void *_PyHeap_Malloc(Context *c, size_t n, size_t align);
 
+static PyObject *PyExc_AsyncError;
+static PyObject *PyExc_ProtectionError;
+static PyObject *PyExc_NoWaitersError;
+static PyObject *PyExc_WaitError;
+
 __inline
 PyThreadState *
 get_main_thread_state(void)
     assert(Py_REFCNT(n) == -1);
     assert(is_varobj == 0 || is_varobj == 1);
 
+    Py_EVENT(n) = NULL;
     Py_PXFLAGS(n) = Py_PXFLAGS_ISPX;
 
     if (is_varobj)
 {
     Heap *h;
     Stats *s;
+    Object *o;
     register Context *c;
     Context *prev, *next;
     PxListItem *item;
             item = next;
         }
 
+        for (o = c->events.first; o != NULL; o = o->next) {
+            assert(Py_HAS_EVENT(o));
+            assert(Py_EVENT(o));
+            PyEvent_DESTROY(o);
+        }
+
 #ifdef Py_DEBUG
         _PxContext_UnregisterHeaps(c);
 #endif
     return _call_from_main_thread(self, args, 1);
 }
 
+/* protection */
+
+__inline
+char
+_protected(PyObject *obj)
+{
+    return (obj->px_flags & Py_PXFLAGS_RWLOCK);
+}
+
+PyObject *
+_async_protected(PyObject *self, PyObject *obj)
+{
+    Py_INCREF(obj);
+    Py_RETURN_BOOL(_protected(obj));
+}
+
+__inline
+PyObject *
+_protect(PyObject *obj)
+{
+    if (!_protected(obj)) {
+        InitializeSRWLock((PSRWLOCK)&(obj->srw_lock));
+        obj->px_flags |= Py_PXFLAGS_RWLOCK;
+    }
+    return obj;
+}
+
 PyObject *
 _async_protect(PyObject *self, PyObject *obj)
 {
-    if (!(obj->px_flags & Py_PXFLAGS_SRWLOCK)) {
-        InitializeSRWLock((PSRWLOCK)&(obj->srw_lock));
-        obj->px_flags |= Py_PXFLAGS_SRWLOCK;
+    Py_INCREF(obj);
+    if (Py_ISPX(obj)) {
+        PyErr_SetNone(PyExc_ProtectionError);
+        return NULL;
     }
-
-    Py_RETURN_NONE;
+    return _protect(obj);
+}
+
+__inline
+PyObject *
+_unprotect(PyObject *obj)
+{
+    if (_protected(obj)) {
+        obj->px_flags &= ~Py_PXFLAGS_RWLOCK;
+        obj->srw_lock = NULL;
+    }
+    return obj;
 }
 
 PyObject *
 _async_unprotect(PyObject *self, PyObject *obj)
 {
-    if (obj->px_flags & Py_PXFLAGS_SRWLOCK) {
-        obj->px_flags &= ~Py_PXFLAGS_SRWLOCK;
-        obj->srw_lock = NULL;
+    Py_INCREF(obj);
+    if (Py_ISPX(obj)) {
+        PyErr_SetNone(PyExc_ProtectionError);
+        return NULL;
     }
-
-    Py_RETURN_NONE;
+    return _unprotect(obj);
 }
 
+__inline
 PyObject *
-_async_protected(PyObject *self, PyObject *obj)
+_read_lock(PyObject *obj)
 {
-    if (obj->px_flags & Py_PXFLAGS_SRWLOCK)
-        Py_RETURN_TRUE;
+    AcquireSRWLockShared((PSRWLOCK)&(obj->srw_lock));
+    return obj;
+}
+
+PyObject *
+_async_read_lock(PyObject *self, PyObject *obj)
+{
+    Px_PROTECTION_GUARD(obj);
+    Py_INCREF(obj);
+    return _read_lock(obj);
+}
+
+__inline
+PyObject *
+_read_unlock(PyObject *obj)
+{
+    ReleaseSRWLockShared((PSRWLOCK)&(obj->srw_lock));
+    return obj;
+}
+
+PyObject *
+_async_read_unlock(PyObject *self, PyObject *obj)
+{
+    Px_PROTECTION_GUARD(obj);
+    Py_INCREF(obj);
+    return _read_unlock(obj);
+}
+
+__inline
+char
+_try_read_lock(PyObject *obj)
+{
+    return TryAcquireSRWLockShared((PSRWLOCK)&(obj->srw_lock));
+}
+
+PyObject *
+_async_try_read_lock(PyObject *self, PyObject *obj)
+{
+    Px_PROTECTION_GUARD(obj);
+    Py_INCREF(obj);
+    Py_RETURN_BOOL(_try_read_lock(obj));
+}
+
+__inline
+PyObject *
+_write_lock(PyObject *obj)
+{
+    AcquireSRWLockExclusive((PSRWLOCK)&(obj->srw_lock));
+    return obj;
+}
+
+PyObject *
+_async_write_lock(PyObject *self, PyObject *obj)
+{
+    Px_PROTECTION_GUARD(obj);
+    Py_INCREF(obj);
+    return _write_lock(obj);
+}
+
+__inline
+PyObject *
+_write_unlock(PyObject *obj)
+{
+    ReleaseSRWLockExclusive((PSRWLOCK)&(obj->srw_lock));
+    return obj;
+}
+
+PyObject *
+_async_write_unlock(PyObject *self, PyObject *obj)
+{
+    Px_PROTECTION_GUARD(obj);
+    Py_INCREF(obj);
+    return _write_unlock(obj);
+}
+
+__inline
+char
+_try_write_lock(PyObject *obj)
+{
+    return TryAcquireSRWLockExclusive((PSRWLOCK)&(obj->srw_lock));
+}
+
+PyObject *
+_async_try_write_lock(PyObject *self, PyObject *obj)
+{
+    Px_PROTECTION_GUARD(obj);
+    Py_INCREF(obj);
+    Py_RETURN_BOOL(_try_write_lock(obj));
+}
+
+__inline
+char
+_PyEvent_TryCreate(PyObject *o)
+{
+    char result = 0;
+    assert(Py_HAS_RWLOCK(o));
+    _write_lock(o);
+    if (!Py_HAS_EVENT(o)) {
+        result = 1;
+        if (Py_ISPX(o))
+            PyErr_SetNone(PyExc_WaitError);
+        if (!PyEvent_CREATE(o))
+            PyErr_SetFromWindowsErr(0);
+        else
+            result = 0;
+    }
+    _write_unlock(o);
+    return result;
+}
+
+PyObject *
+_async_wait(PyObject *self, PyObject *o)
+{
+    DWORD result;
+    Px_PROTECTION_GUARD(o);
+    Py_INCREF(o);
+    if (!_PyEvent_TryCreate(o))
+        return NULL;
+
+    result = WaitForSingleObject((HANDLE)o->event, INFINITE);
+
+    if (result == WAIT_OBJECT_0)
+        Py_RETURN_NONE;
+
+    else if (result == WAIT_ABANDONED)
+        PyErr_SetString(PyExc_SystemError, "wait abandoned");
+
+    else if (result == WAIT_TIMEOUT)
+        PyErr_SetString(PyExc_SystemError, "infinite wait timed out?");
+
+    else if (result == WAIT_FAILED)
+        PyErr_SetFromWindowsErr(0);
+
     else
-        Py_RETURN_FALSE;
+        PyErr_SetString(PyExc_SystemError, "unexpected result from wait");
+
+    return NULL;
+}
+
+PyObject *
+_async_signal(PyObject *self, PyObject *o)
+{
+    PyObject *result = NULL;
+    Px_PROTECTION_GUARD(o);
+    Py_INCREF(o);
+    _write_lock(o);
+
+    if (!Py_HAS_EVENT(o))
+        PyErr_SetNone(PyExc_NoWaitersError);
+    else if (!PyEvent_SIGNAL(o))
+        PyErr_SetFromWindowsErr(0);
+    else
+        result = Py_None;
+
+    _write_unlock(o);
+    Py_XINCREF(result);
+    return result;
 }
 
 PyDoc_STRVAR(_async_doc,
 Unregisters an asynchronous object.");
 
 PyDoc_STRVAR(_async_map_doc, "XXX TODO\n");
+PyDoc_STRVAR(_async_wait_doc, "XXX TODO\n");
 PyDoc_STRVAR(_async_rdtsc_doc, "XXX TODO\n");
 PyDoc_STRVAR(_async_client_doc, "XXX TODO\n");
 PyDoc_STRVAR(_async_server_doc, "XXX TODO\n");
+PyDoc_STRVAR(_async_signal_doc, "XXX TODO\n");
 PyDoc_STRVAR(_async_protect_doc, "XXX TODO\n");
 PyDoc_STRVAR(_async_run_once_doc, "XXX TODO\n");
 PyDoc_STRVAR(_async_unprotect_doc, "XXX TODO\n");
 PyDoc_STRVAR(_async_protected_doc, "XXX TODO\n");
 PyDoc_STRVAR(_async_is_active_doc, "XXX TODO\n");
+PyDoc_STRVAR(_async_read_lock_doc, "XXX TODO\n");
+PyDoc_STRVAR(_async_read_unlock_doc, "XXX TODO\n");
+PyDoc_STRVAR(_async_try_read_lock_doc, "XXX TODO\n");
+PyDoc_STRVAR(_async_write_lock_doc, "XXX TODO\n");
+PyDoc_STRVAR(_async_write_unlock_doc, "XXX TODO\n");
+PyDoc_STRVAR(_async_try_write_lock_doc, "XXX TODO\n");
 PyDoc_STRVAR(_async_submit_io_doc, "XXX TODO\n");
 PyDoc_STRVAR(_async_submit_work_doc, "XXX TODO\n");
 PyDoc_STRVAR(_async_submit_wait_doc, "XXX TODO\n");
 PyMethodDef _async_methods[] = {
     _ASYNC_V(map),
     _ASYNC_N(run),
+    _ASYNC_O(wait),
     _ASYNC_N(rdtsc),
+    _ASYNC_O(signal),
     _ASYNC_K(client),
     _ASYNC_K(server),
     _ASYNC_O(protect),
+    //_ASYNC_O(wait_any),
+    //_ASYNC_O(wait_all),
     _ASYNC_N(run_once),
     _ASYNC_O(unprotect),
     _ASYNC_O(protected),
     _ASYNC_N(is_active),
     _ASYNC_V(submit_io),
+    _ASYNC_O(read_lock),
+    _ASYNC_O(write_lock),
     _ASYNC_V(submit_work),
     _ASYNC_V(submit_wait),
+    _ASYNC_O(read_unlock),
+    _ASYNC_O(write_unlock),
     _ASYNC_N(is_active_ex),
     _ASYNC_N(active_count),
     _ASYNC_V(submit_timer),
     _ASYNC_O(submit_class),
     _ASYNC_O(submit_client),
     _ASYNC_O(submit_server),
+    _ASYNC_O(try_read_lock),
+    _ASYNC_O(try_write_lock),
     _ASYNC_N(active_contexts),
     _ASYNC_N(is_parallel_thread),
     _ASYNC_V(call_from_main_thread),
     if (PyModule_AddObject(m, "socket", (PyObject *)&PxSocket_Type))
         return NULL;
 
+    PyExc_AsyncError = PyErr_NewException("_async.AsyncError", NULL, NULL);
+    if (!PyExc_AsyncError)
+        return NULL;
+
+    PyExc_ProtectionError = \
+        PyErr_NewException("_async.ProtectionError", PyExc_AsyncError, NULL);
+    if (!PyExc_ProtectionError)
+        return NULL;
+
+    PyExc_NoWaitersError = \
+        PyErr_NewException("_async.NoWaitersError", PyExc_AsyncError, NULL);
+    if (!PyExc_NoWaitersError)
+        return NULL;
+
+    PyExc_WaitError = \
+        PyErr_NewException("_async.WaitError", PyExc_AsyncError, NULL);
+    if (!PyExc_WaitError)
+        return NULL;
+
+    if (PyModule_AddObject(m, "AsyncError", PyExc_AsyncError))
+        return NULL;
+
+    if (PyModule_AddObject(m, "ProtectionError", PyExc_ProtectionError))
+        return NULL;
+
+    if (PyModule_AddObject(m, "NoWaitersError", PyExc_NoWaitersError))
+        return NULL;
+
+    if (PyModule_AddObject(m, "WaitError", PyExc_WaitError))
+        return NULL;
+
+    Py_INCREF(PyExc_AsyncError);
+    Py_INCREF(PyExc_ProtectionError);
+    Py_INCREF(PyExc_NoWaitersError);
+    Py_INCREF(PyExc_WaitError);
+
+    /* Uncomment the following (during development) as needed. */
+    /*
     if (Py_VerboseFlag)
         printf("sizeof(PxSocket): %d\n", sizeof(PxSocket));
+    */
 
     return m;
 }

Python/pyparallel_private.h

 
 #define Py_ASPX(ob) ((PxObject *)(((PyObject*)(ob))->px))
 
+#ifdef MS_WINDOWS
+#define PyEvent     HANDLE
+#define PyEventType HANDLE
+
+#define Py_EVENT(o)         ((PyEventType)(((PyObject *)(o))->event))
+#define PyEvent_CREATE(o)   (Py_EVENT(o) = CreateEvent(0, 0, 0, 0))
+#define PyEvent_INIT(o)     /* N/A */
+#define PyEvent_SIGNAL(o)   (SetEvent(Py_EVENT(o)))
+#define PyEvent_DESTROY(o)  (CloseHandle(Py_EVENT(o)))
+
+#define PyRWLock            SRWLOCK
+#define Py_RWLOCK(o)        ((PyRWLock *)&(((PyObject *)(o))->srw_lock))
+
+#define PyRWLock_CREATE(o)  /* N/A */
+#define PyRWLock_INIT(o)    (InitializeSRWLock((PSRWLOCK)&(o->srw_lock)))
+#define PyRWLock_DESTROY(o) /* N/A */
+#endif
+
 #include "pxlist.h"
 
 typedef struct _cpuinfo {
 
     Objects objects;
     Objects varobjs;
+    Objects events;
 
     char  tbuf[_PX_TMPBUF_SIZE];
     void *tbuf_base;
 
 #define PXS2S(s) ((PySocketSockObject *)s)
 
+#define Py_RETURN_BOOL(expr) return (             \
+    ((expr) ? (Py_INCREF(Py_True), Py_True) :     \
+              (Py_INCREF(Py_False), Py_False))    \
+)
+
+#define Px_PROTECTION_GUARD(o)                    \
+    do {                                          \
+        if (!_protected(o)) {                     \
+            PyErr_SetNone(PyExc_ProtectionError); \
+            return NULL;                          \
+        }                                         \
+    } while (0)
+
 #ifdef __cpplus
 }
 #endif