Don't close connections from forked processes

On Py3 subprocessing will actually GC the objects and the FD is open,
resulting in connections closed in different processes.

The behaviour is verified in py 3.4 to 3.7 at least,
This commit is contained in:
Daniele Varrazzo 2019-03-18 00:27:16 +00:00
parent 62a078fe0c
commit 17b0c61338
3 changed files with 28 additions and 3 deletions

View File

@ -33,6 +33,18 @@
# define HIDDEN
#endif
/* support for getpid() */
#if defined( __GNUC__)
#define CONN_CHECK_PID
#include <sys/types.h>
#include <unistd.h>
#endif
#ifdef _WIN32
/* Windows doesn't seem affected by bug #829: just make it compile. */
#define pid_t int
#endif
/* debug printf-like function */
#ifdef PSYCOPG_DEBUG
extern HIDDEN int psycopg_debug_enabled;
@ -40,8 +52,6 @@ extern HIDDEN int psycopg_debug_enabled;
#if defined( __GNUC__) && !defined(__APPLE__)
#ifdef PSYCOPG_DEBUG
#include <sys/types.h>
#include <unistd.h>
#define Dprintf(fmt, args...) \
if (!psycopg_debug_enabled) ; else \
fprintf(stderr, "[%d] " fmt "\n", (int) getpid() , ## args)

View File

@ -141,6 +141,9 @@ struct connectionObject {
int isolevel;
int readonly;
int deferrable;
/* the pid this connection was created into */
pid_t procpid;
};
/* map isolation level values into a numeric const */

View File

@ -1367,6 +1367,10 @@ connection_setup(connectionObject *self, const char *dsn, long int async)
self->isolevel = ISOLATION_LEVEL_DEFAULT;
self->readonly = STATE_DEFAULT;
self->deferrable = STATE_DEFAULT;
#ifdef CONN_CHECK_PID
self->procpid = getpid();
#endif
/* other fields have been zeroed by tp_alloc */
pthread_mutex_init(&(self->lock), NULL);
@ -1420,7 +1424,15 @@ connection_dealloc(PyObject* obj)
* resulting in a double-free segfault (ticket #166). */
PyObject_GC_UnTrack(self);
conn_close(self);
/* close the connection only if this is the same process it was created
* into, otherwise using multiprocessing we may close the connection
* belonging to another process. */
#ifdef CONN_CHECK_PID
if (self->procpid == getpid())
#endif
{
conn_close(self);
}
if (self->weakreflist) {
PyObject_ClearWeakRefs(obj);