Moved grpc_shutdown to end of Py_Finalize()

We currently rely on the __del__ method of a module scope object
to call grpc_shutdown().  __del__ methods are not guaranteed
to be called, and furthermore there are no guarantees about
ordering, leading to shutdown race conditions.  This moves
grpc_shutdown to Py_Finalize(), which gets called after the
Python context is completely cleaned up.
pull/6941/head
Ken Payson 9 years ago
parent 68e5ecbee4
commit f4c1bff0d8
  1. 1
      src/python/grpcio/grpc/_cython/_cygrpc/grpc.pxi
  2. 32
      src/python/grpcio/grpc/_cython/cygrpc.pyx
  3. 7
      src/python/grpcio/grpc/_cython/loader.c
  4. 5
      src/python/grpcio/grpc/_cython/loader.h

@ -37,6 +37,7 @@ cdef extern from "grpc/_cython/loader.h":
ctypedef long int64_t
int pygrpc_load_core(char*)
int pygrpc_initialize_core()
void *gpr_malloc(size_t size) nogil
void gpr_free(void *ptr) nogil

@ -45,30 +45,20 @@ include "grpc/_cython/_cygrpc/security.pyx.pxi"
include "grpc/_cython/_cygrpc/server.pyx.pxi"
#
# Global state
# initialize gRPC
#
cdef class _ModuleState:
cdef bint is_loaded
def _initialize():
if 'win32' in sys.platform:
filename = pkg_resources.resource_filename(
'grpc._cython', '_windows/grpc_c.64.python')
if not pygrpc_load_core(filename):
raise ImportError('failed to load core gRPC library')
if not pygrpc_initialize_core():
raise ImportError('failed to initialize core gRPC library')
def __cinit__(self):
if 'win32' in sys.platform:
filename = pkg_resources.resource_filename(
'grpc._cython', '_windows/grpc_c.64.python')
if not pygrpc_load_core(filename):
raise ImportError('failed to load core gRPC library')
with nogil:
grpc_init()
self.is_loaded = True
with nogil:
grpc_set_ssl_roots_override_callback(
grpc_set_ssl_roots_override_callback(
<grpc_ssl_roots_override_callback>ssl_roots_override_callback)
def __dealloc__(self):
if self.is_loaded:
with nogil:
grpc_shutdown()
_module_state = _ModuleState()
_initialize()

@ -31,6 +31,7 @@
*
*/
#include <Python.h>
#include "loader.h"
#ifdef __cplusplus
@ -62,6 +63,12 @@ int pygrpc_load_core(char *path) { return 1; }
#endif /* !GPR_WINDOWS */
// Cython doesn't have Py_AtExit bindings, so we call the C_API directly
int pygrpc_initialize_core(void) {
grpc_init();
return Py_AtExit(grpc_shutdown) < 0 ? 0 : 1;
}
#ifdef __cplusplus
}
#endif /* __cpluslus */

@ -46,6 +46,11 @@ extern "C" {
/* Attempts to load the core if necessary, and return non-zero upon succes. */
int pygrpc_load_core(char *path);
/* Initializes grpc and registers grpc_shutdown() to be called right before
* interpreter exit. Returns non-zero upon success.
*/
int pygrpc_initialize_core(void);
#ifdef __cplusplus
}
#endif /* __cpluslus */

Loading…
Cancel
Save