[pypy-commit] pypy default: Issue1175: PyThread_{get, set, delete}_key_value should work without the GIL held.

amauryfa noreply at buildbot.pypy.org
Sat Jul 21 20:32:46 CEST 2012


Author: Amaury Forgeot d'Arc <amauryfa at gmail.com>
Branch: 
Changeset: r56378:531f677554ee
Date: 2012-07-21 20:28 +0200
http://bitbucket.org/pypy/pypy/changeset/531f677554ee/

Log:	Issue1175: PyThread_{get,set,delete}_key_value should work without
	the GIL held. Patch by marienz.

diff --git a/pypy/module/cpyext/__init__.py b/pypy/module/cpyext/__init__.py
--- a/pypy/module/cpyext/__init__.py
+++ b/pypy/module/cpyext/__init__.py
@@ -28,7 +28,6 @@
 
 
 # import these modules to register api functions by side-effect
-import pypy.module.cpyext.thread
 import pypy.module.cpyext.pyobject
 import pypy.module.cpyext.boolobject
 import pypy.module.cpyext.floatobject
diff --git a/pypy/module/cpyext/api.py b/pypy/module/cpyext/api.py
--- a/pypy/module/cpyext/api.py
+++ b/pypy/module/cpyext/api.py
@@ -48,8 +48,10 @@
 pypydir = py.path.local(autopath.pypydir)
 include_dir = pypydir / 'module' / 'cpyext' / 'include'
 source_dir = pypydir / 'module' / 'cpyext' / 'src'
+translator_c_dir = pypydir / 'translator' / 'c'
 include_dirs = [
     include_dir,
+    translator_c_dir,
     udir,
     ]
 
@@ -372,6 +374,8 @@
     'PyObject_AsReadBuffer', 'PyObject_AsWriteBuffer', 'PyObject_CheckReadBuffer',
 
     'PyOS_getsig', 'PyOS_setsig',
+    'PyThread_get_thread_ident', 'PyThread_allocate_lock', 'PyThread_free_lock',
+    'PyThread_acquire_lock', 'PyThread_release_lock',
     'PyThread_create_key', 'PyThread_delete_key', 'PyThread_set_key_value',
     'PyThread_get_key_value', 'PyThread_delete_key_value',
     'PyThread_ReInitTLS',
@@ -715,7 +719,8 @@
             global_objects.append('%s %s = NULL;' % (typ, name))
     global_code = '\n'.join(global_objects)
 
-    prologue = "#include <Python.h>\n"
+    prologue = ("#include <Python.h>\n"
+                "#include <src/thread.h>\n")
     code = (prologue +
             struct_declaration_code +
             global_code +
diff --git a/pypy/module/cpyext/include/pythread.h b/pypy/module/cpyext/include/pythread.h
--- a/pypy/module/cpyext/include/pythread.h
+++ b/pypy/module/cpyext/include/pythread.h
@@ -3,13 +3,20 @@
 
 #define WITH_THREAD
 
+typedef void *PyThread_type_lock;
+
 #ifdef __cplusplus
 extern "C" {
 #endif
 
-typedef void *PyThread_type_lock;
+PyAPI_FUNC(long) PyThread_get_thread_ident(void);
+
+PyAPI_FUNC(PyThread_type_lock) PyThread_allocate_lock(void);
+PyAPI_FUNC(void) PyThread_free_lock(PyThread_type_lock);
+PyAPI_FUNC(int) PyThread_acquire_lock(PyThread_type_lock, int);
 #define WAIT_LOCK	1
 #define NOWAIT_LOCK	0
+PyAPI_FUNC(void) PyThread_release_lock(PyThread_type_lock);
 
 /* Thread Local Storage (TLS) API */
 PyAPI_FUNC(int) PyThread_create_key(void);
diff --git a/pypy/module/cpyext/src/thread.c b/pypy/module/cpyext/src/thread.c
--- a/pypy/module/cpyext/src/thread.c
+++ b/pypy/module/cpyext/src/thread.c
@@ -1,6 +1,55 @@
 #include <Python.h>
 #include "pythread.h"
 
+/* With PYPY_NOT_MAIN_FILE only declarations are imported */
+#define PYPY_NOT_MAIN_FILE
+#include "src/thread.h"
+
+long
+PyThread_get_thread_ident(void)
+{
+    return RPyThreadGetIdent();
+}
+
+PyThread_type_lock
+PyThread_allocate_lock(void)
+{
+    struct RPyOpaque_ThreadLock *lock;
+    lock = malloc(sizeof(struct RPyOpaque_ThreadLock));
+    if (lock == NULL)
+        return NULL;
+
+    if (RPyThreadLockInit(lock) == 0) {
+        free(lock);
+        return NULL;
+    }
+
+    return (PyThread_type_lock)lock;
+}
+
+void
+PyThread_free_lock(PyThread_type_lock lock)
+{
+    struct RPyOpaque_ThreadLock *real_lock = lock;
+    RPyThreadAcquireLock(real_lock, 0);
+    RPyThreadReleaseLock(real_lock);
+    RPyOpaqueDealloc_ThreadLock(real_lock);
+    free(lock);
+}
+
+int
+PyThread_acquire_lock(PyThread_type_lock lock, int waitflag)
+{
+    return RPyThreadAcquireLock((struct RPyOpaqueThreadLock*)lock, waitflag);
+}
+
+void
+PyThread_release_lock(PyThread_type_lock lock)
+{
+    RPyThreadReleaseLock((struct RPyOpaqueThreadLock*)lock);
+}
+
+
 /* ------------------------------------------------------------------------
 Per-thread data ("key") support.
 
diff --git a/pypy/module/cpyext/test/test_thread.py b/pypy/module/cpyext/test/test_thread.py
--- a/pypy/module/cpyext/test/test_thread.py
+++ b/pypy/module/cpyext/test/test_thread.py
@@ -1,18 +1,21 @@
 import py
 
-import thread
-import threading
-
-from pypy.module.thread.ll_thread import allocate_ll_lock
-from pypy.module.cpyext.test.test_api import BaseApiTest
 from pypy.module.cpyext.test.test_cpyext import AppTestCpythonExtensionBase
 
 
-class TestPyThread(BaseApiTest):
-    def test_get_thread_ident(self, space, api):
+class AppTestThread(AppTestCpythonExtensionBase):
+    def test_get_thread_ident(self):
+        module = self.import_extension('foo', [
+            ("get_thread_ident", "METH_NOARGS",
+             """
+                 /* Use the 'PyPy' prefix to ensure we access our functions */
+                 return PyInt_FromLong(PyPyThread_get_thread_ident());
+             """),
+            ])
+        import thread, threading
         results = []
         def some_thread():
-            res = api.PyThread_get_thread_ident()
+            res = module.get_thread_ident()
             results.append((res, thread.get_ident()))
 
         some_thread()
@@ -25,23 +28,46 @@
 
         assert results[0][0] != results[1][0]
 
-    def test_acquire_lock(self, space, api):
-        assert hasattr(api, 'PyThread_acquire_lock')
-        lock = api.PyThread_allocate_lock()
-        assert api.PyThread_acquire_lock(lock, 1) == 1
-        assert api.PyThread_acquire_lock(lock, 0) == 0
-        api.PyThread_free_lock(lock)
+    def test_acquire_lock(self):
+        module = self.import_extension('foo', [
+            ("test_acquire_lock", "METH_NOARGS",
+             """
+                 /* Use the 'PyPy' prefix to ensure we access our functions */
+                 PyThread_type_lock lock = PyPyThread_allocate_lock();
+                 if (PyPyThread_acquire_lock(lock, 1) != 1) {
+                     PyErr_SetString(PyExc_AssertionError, "first acquire");
+                     return NULL;
+                 }
+                 if (PyPyThread_acquire_lock(lock, 0) != 0) {
+                     PyErr_SetString(PyExc_AssertionError, "second acquire");
+                     return NULL;
+                 }
+                 PyPyThread_free_lock(lock);
 
-    def test_release_lock(self, space, api):
-        assert hasattr(api, 'PyThread_acquire_lock')
-        lock = api.PyThread_allocate_lock()
-        api.PyThread_acquire_lock(lock, 1)
-        api.PyThread_release_lock(lock)
-        assert api.PyThread_acquire_lock(lock, 0) == 1
-        api.PyThread_free_lock(lock)
+                 Py_RETURN_NONE;
+             """),
+            ])
+        module.test_acquire_lock()
 
+    def test_release_lock(self):
+        module = self.import_extension('foo', [
+            ("test_release_lock", "METH_NOARGS",
+             """
+                 /* Use the 'PyPy' prefix to ensure we access our functions */
+                 PyThread_type_lock lock = PyPyThread_allocate_lock();
+                 PyPyThread_acquire_lock(lock, 1);
+                 PyPyThread_release_lock(lock);
+                 if (PyPyThread_acquire_lock(lock, 0) != 1) {
+                     PyErr_SetString(PyExc_AssertionError, "first acquire");
+                     return NULL;
+                 }
+                 PyPyThread_free_lock(lock);
 
-class AppTestThread(AppTestCpythonExtensionBase):
+                 Py_RETURN_NONE;
+             """),
+            ])
+        module.test_release_lock()
+
     def test_tls(self):
         module = self.import_extension('foo', [
             ("create_key", "METH_NOARGS",
diff --git a/pypy/module/cpyext/thread.py b/pypy/module/cpyext/thread.py
deleted file mode 100644
--- a/pypy/module/cpyext/thread.py
+++ /dev/null
@@ -1,32 +0,0 @@
-
-from pypy.module.thread import ll_thread
-from pypy.module.cpyext.api import CANNOT_FAIL, cpython_api
-from pypy.rpython.lltypesystem import lltype, rffi
-
- at cpython_api([], rffi.LONG, error=CANNOT_FAIL)
-def PyThread_get_thread_ident(space):
-    return ll_thread.get_ident()
-
-LOCKP = rffi.COpaquePtr(typedef='PyThread_type_lock')
-
- at cpython_api([], LOCKP)
-def PyThread_allocate_lock(space):
-    lock = ll_thread.allocate_ll_lock()
-    return rffi.cast(LOCKP, lock)
-
- at cpython_api([LOCKP], lltype.Void)
-def PyThread_free_lock(space, lock):
-    lock = rffi.cast(ll_thread.TLOCKP, lock)
-    ll_thread.free_ll_lock(lock)
-
- at cpython_api([LOCKP, rffi.INT], rffi.INT, error=CANNOT_FAIL)
-def PyThread_acquire_lock(space, lock, waitflag):
-    lock = rffi.cast(ll_thread.TLOCKP, lock)
-    return ll_thread.c_thread_acquirelock(lock, waitflag)
-
- at cpython_api([LOCKP], lltype.Void)
-def PyThread_release_lock(space, lock):
-    lock = rffi.cast(ll_thread.TLOCKP, lock)
-    ll_thread.c_thread_releaselock(lock)
-
-


More information about the pypy-commit mailing list