[pypy-commit] pypy default: Move the callback logic to C code instead of using RPython code

arigo noreply at buildbot.pypy.org
Mon Jun 11 14:38:53 CEST 2012


Author: Armin Rigo <arigo at tunes.org>
Branch: 
Changeset: r55575:34b3b5aac082
Date: 2012-06-11 14:38 +0200
http://bitbucket.org/pypy/pypy/changeset/34b3b5aac082/

Log:	Move the callback logic to C code instead of using RPython code
	here. It should avoid issues with the GIL.

diff --git a/pypy/module/_ssl/__init__.py b/pypy/module/_ssl/__init__.py
--- a/pypy/module/_ssl/__init__.py
+++ b/pypy/module/_ssl/__init__.py
@@ -31,5 +31,6 @@
     def startup(self, space):
         from pypy.rlib.ropenssl import init_ssl
         init_ssl()
-        from pypy.module._ssl.interp_ssl import setup_ssl_threads
-        setup_ssl_threads()
+        if space.config.objspace.usemodules.thread:
+            from pypy.module._ssl.thread_lock import setup_ssl_threads
+            setup_ssl_threads()
diff --git a/pypy/module/_ssl/interp_ssl.py b/pypy/module/_ssl/interp_ssl.py
--- a/pypy/module/_ssl/interp_ssl.py
+++ b/pypy/module/_ssl/interp_ssl.py
@@ -880,38 +880,3 @@
             libssl_X509_free(x)
     finally:
         libssl_BIO_free(cert)
-
-# this function is needed to perform locking on shared data
-# structures. (Note that OpenSSL uses a number of global data
-# structures that will be implicitly shared whenever multiple threads
-# use OpenSSL.) Multi-threaded applications will crash at random if
-# it is not set.
-#
-# locking_function() must be able to handle up to CRYPTO_num_locks()
-# different mutex locks. It sets the n-th lock if mode & CRYPTO_LOCK, and
-# releases it otherwise.
-#
-# filename and line are the file number of the function setting the
-# lock. They can be useful for debugging.
-_ssl_locks = []
-
-def _ssl_thread_locking_function(mode, n, filename, line):
-    n = intmask(n)
-    if n < 0 or n >= len(_ssl_locks):
-        return
-
-    if intmask(mode) & CRYPTO_LOCK:
-        _ssl_locks[n].acquire(True)
-    else:
-        _ssl_locks[n].release()
-
-def _ssl_thread_id_function():
-    from pypy.module.thread import ll_thread
-    return rffi.cast(rffi.LONG, ll_thread.get_ident())
-
-def setup_ssl_threads():
-    from pypy.module.thread import ll_thread
-    for i in range(libssl_CRYPTO_num_locks()):
-        _ssl_locks.append(ll_thread.allocate_lock())
-    libssl_CRYPTO_set_locking_callback(_ssl_thread_locking_function)
-    libssl_CRYPTO_set_id_callback(_ssl_thread_id_function)
diff --git a/pypy/module/_ssl/thread_lock.py b/pypy/module/_ssl/thread_lock.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/_ssl/thread_lock.py
@@ -0,0 +1,78 @@
+from pypy.rlib.ropenssl import *
+from pypy.rpython.lltypesystem import lltype, rffi
+from pypy.translator.tool.cbuild import ExternalCompilationInfo
+
+# CRYPTO_set_locking_callback:
+#
+# this function is needed to perform locking on shared data
+# structures. (Note that OpenSSL uses a number of global data
+# structures that will be implicitly shared whenever multiple threads
+# use OpenSSL.) Multi-threaded applications will crash at random if
+# it is not set.
+#
+# locking_function() must be able to handle up to CRYPTO_num_locks()
+# different mutex locks. It sets the n-th lock if mode & CRYPTO_LOCK, and
+# releases it otherwise.
+#
+# filename and line are the file number of the function setting the
+# lock. They can be useful for debugging.
+
+
+# This logic is moved to C code so that the callbacks can be invoked
+# without caring about the GIL.
+
+separate_module_source = """
+
+#include <openssl/crypto.h>
+
+static unsigned int _ssl_locks_count = 0;
+static struct RPyOpaque_ThreadLock *_ssl_locks;
+
+static unsigned long _ssl_thread_id_function(void) {
+    return RPyThreadGetIdent();
+}
+
+static void _ssl_thread_locking_function(int mode, int n, const char *file,
+                                         int line) {
+    if ((_ssl_locks == NULL) ||
+        (n < 0) || ((unsigned)n >= _ssl_locks_count))
+        return;
+
+    if (mode & CRYPTO_LOCK) {
+        RPyThreadAcquireLock(_ssl_locks[n], 1);
+    } else {
+        RPyThreadReleaseLock(_ssl_locks[n]);
+    }
+}
+
+int _PyPy_SSL_SetupThreads(void)
+{
+    unsigned int i;
+    _ssl_locks_count = CRYPTO_num_locks();
+    _ssl_locks = calloc(_ssl_locks_count, sizeof(struct RPyOpaque_ThreadLock));
+    if (_ssl_locks == NULL)
+        return 0;
+    for (i=0; i<_ssl_locks_count; i++) {
+        if (RPyThreadLockInit(_ssl_locks + i) == 0)
+            return 0;
+    }
+    CRYPTO_set_locking_callback(_ssl_thread_locking_function);
+    CRYPTO_set_id_callback(_ssl_thread_id_function);
+    return 1;
+}
+"""
+
+
+eci = ExternalCompilationInfo(
+    separate_module_sources=[separate_module_source],
+    export_symbols=['_PyPy_SSL_SetupThreads'],
+)
+
+_PyPy_SSL_SetupThreads = rffi.llexternal('_PyPy_SSL_SetupThreads',
+                                         [], rffi.INT,
+                                         compilation_info=eci)
+
+def setup_ssl_threads():
+    result = _PyPy_SSL_SetupThreads()
+    if rffi.cast(lltype.Signed, result) == 0:
+        raise MemoryError


More information about the pypy-commit mailing list