Fixed a deadlock when using the same connection from multiple threads

This commit is contained in:
Federico Di Gregorio 2009-10-04 12:02:02 +02:00
parent 1c9fa1355d
commit 7022269b3d
3 changed files with 47 additions and 16 deletions

View File

@ -1,3 +1,8 @@
2009-10-04 Federico Di Gregorio <fog@initd.org>
* psycopg/connection_int.c: applied patch from Richard Davies to avoid
deadlocks with multiple threads using the same connection.
2009-08-08 Federico Di Gregorio <fog@initd.org>
* Release 2.0.12.

View File

@ -64,11 +64,14 @@ conn_notice_callback(void *args, const char *message)
void
conn_notice_process(connectionObject *self)
{
Py_BEGIN_ALLOW_THREADS;
pthread_mutex_lock(&self->lock);
struct connectionObject_notice *notice = self->notice_pending;
while (notice != NULL) {
Py_BLOCK_THREADS;
PyObject *msg = PyString_FromString(notice->message);
Dprintf("conn_notice_process: %s", notice->message);
@ -80,10 +83,13 @@ conn_notice_process(connectionObject *self)
if (PyList_GET_SIZE(self->notice_list) > CONN_NOTICES_LIMIT)
PySequence_DelItem(self->notice_list, 0);
Py_UNBLOCK_THREADS;
notice = notice->next;
}
pthread_mutex_unlock(&self->lock);
Py_END_ALLOW_THREADS;
conn_notice_clean(self);
}
@ -91,6 +97,7 @@ conn_notice_process(connectionObject *self)
void
conn_notice_clean(connectionObject *self)
{
Py_BEGIN_ALLOW_THREADS;
pthread_mutex_lock(&self->lock);
struct connectionObject_notice *tmp, *notice = self->notice_pending;
@ -105,6 +112,7 @@ conn_notice_clean(connectionObject *self)
self->notice_pending = NULL;
pthread_mutex_unlock(&self->lock);
Py_END_ALLOW_THREADS;
}
/* conn_setup - setup and read basic information about the connection */
@ -112,6 +120,10 @@ conn_notice_clean(connectionObject *self)
int
conn_setup(connectionObject *self, PGconn *pgconn)
{
Py_BEGIN_ALLOW_THREADS;
pthread_mutex_lock(&self->lock);
Py_BLOCK_THREADS;
PGresult *pgres;
const char *data, *tmp;
const char *scs; /* standard-conforming strings */
@ -160,26 +172,32 @@ conn_setup(connectionObject *self, PGconn *pgconn)
Dprintf("conn_connect: server requires E'' quotes: %s",
self->equote ? "YES" : "NO");
Py_BEGIN_ALLOW_THREADS;
Py_UNBLOCK_THREADS;
pgres = PQexec(pgconn, datestyle);
Py_END_ALLOW_THREADS;
Py_BLOCK_THREADS;
if (pgres == NULL || PQresultStatus(pgres) != PGRES_COMMAND_OK ) {
PyErr_SetString(OperationalError, "can't set datestyle to ISO");
PQfinish(pgconn);
IFCLEARPGRES(pgres);
Py_UNBLOCK_THREADS;
pthread_mutex_unlock(&self->lock);
Py_BLOCK_THREADS;
return -1;
}
CLEARPGRES(pgres);
Py_BEGIN_ALLOW_THREADS;
Py_UNBLOCK_THREADS;
pgres = PQexec(pgconn, encoding);
Py_END_ALLOW_THREADS;
Py_BLOCK_THREADS;
if (pgres == NULL || PQresultStatus(pgres) != PGRES_TUPLES_OK) {
PyErr_SetString(OperationalError, "can't fetch client_encoding");
PQfinish(pgconn);
IFCLEARPGRES(pgres);
Py_UNBLOCK_THREADS;
pthread_mutex_unlock(&self->lock);
Py_BLOCK_THREADS;
return -1;
}
tmp = PQgetvalue(pgres, 0, 0);
@ -188,6 +206,9 @@ conn_setup(connectionObject *self, PGconn *pgconn)
PyErr_NoMemory();
PQfinish(pgconn);
IFCLEARPGRES(pgres);
Py_UNBLOCK_THREADS;
pthread_mutex_unlock(&self->lock);
Py_BLOCK_THREADS;
return -1;
}
for (i=0 ; i < strlen(tmp) ; i++)
@ -195,15 +216,18 @@ conn_setup(connectionObject *self, PGconn *pgconn)
self->encoding[i] = '\0';
CLEARPGRES(pgres);
Py_BEGIN_ALLOW_THREADS;
Py_UNBLOCK_THREADS;
pgres = PQexec(pgconn, isolevel);
Py_END_ALLOW_THREADS;
Py_BLOCK_THREADS;
if (pgres == NULL || PQresultStatus(pgres) != PGRES_TUPLES_OK) {
PyErr_SetString(OperationalError,
"can't fetch default_isolation_level");
PQfinish(pgconn);
IFCLEARPGRES(pgres);
Py_UNBLOCK_THREADS;
pthread_mutex_unlock(&self->lock);
Py_BLOCK_THREADS;
return -1;
}
data = PQgetvalue(pgres, 0, 0);
@ -217,6 +241,10 @@ conn_setup(connectionObject *self, PGconn *pgconn)
self->isolation_level = 2;
CLEARPGRES(pgres);
Py_UNBLOCK_THREADS;
pthread_mutex_unlock(&self->lock);
Py_END_ALLOW_THREADS;
return 0;
}

View File

@ -366,9 +366,7 @@ psyco_conn_reset(connectionObject *self)
if (pq_reset(self) < 0)
return NULL;
pthread_mutex_lock(&self->lock);
res = conn_setup(self, self->pgconn);
pthread_mutex_unlock(&self->lock);
if (res < 0)
return NULL;