[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