Author: Armin Rigo <ar...@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 _______________________________________________ pypy-commit mailing list pypy-commit@python.org http://mail.python.org/mailman/listinfo/pypy-commit