mirror of
https://github.com/psycopg/psycopg2.git
synced 2025-02-12 07:10:33 +03:00
Fixed a deadlock when using the same connection from multiple threads
This commit is contained in:
parent
1c9fa1355d
commit
7022269b3d
|
@ -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>
|
2009-08-08 Federico Di Gregorio <fog@initd.org>
|
||||||
|
|
||||||
* Release 2.0.12.
|
* Release 2.0.12.
|
||||||
|
|
|
@ -64,11 +64,14 @@ conn_notice_callback(void *args, const char *message)
|
||||||
void
|
void
|
||||||
conn_notice_process(connectionObject *self)
|
conn_notice_process(connectionObject *self)
|
||||||
{
|
{
|
||||||
|
Py_BEGIN_ALLOW_THREADS;
|
||||||
pthread_mutex_lock(&self->lock);
|
pthread_mutex_lock(&self->lock);
|
||||||
|
|
||||||
struct connectionObject_notice *notice = self->notice_pending;
|
struct connectionObject_notice *notice = self->notice_pending;
|
||||||
|
|
||||||
while (notice != NULL) {
|
while (notice != NULL) {
|
||||||
|
Py_BLOCK_THREADS;
|
||||||
|
|
||||||
PyObject *msg = PyString_FromString(notice->message);
|
PyObject *msg = PyString_FromString(notice->message);
|
||||||
|
|
||||||
Dprintf("conn_notice_process: %s", 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)
|
if (PyList_GET_SIZE(self->notice_list) > CONN_NOTICES_LIMIT)
|
||||||
PySequence_DelItem(self->notice_list, 0);
|
PySequence_DelItem(self->notice_list, 0);
|
||||||
|
|
||||||
|
Py_UNBLOCK_THREADS;
|
||||||
|
|
||||||
notice = notice->next;
|
notice = notice->next;
|
||||||
}
|
}
|
||||||
|
|
||||||
pthread_mutex_unlock(&self->lock);
|
pthread_mutex_unlock(&self->lock);
|
||||||
|
Py_END_ALLOW_THREADS;
|
||||||
|
|
||||||
conn_notice_clean(self);
|
conn_notice_clean(self);
|
||||||
}
|
}
|
||||||
|
@ -91,6 +97,7 @@ conn_notice_process(connectionObject *self)
|
||||||
void
|
void
|
||||||
conn_notice_clean(connectionObject *self)
|
conn_notice_clean(connectionObject *self)
|
||||||
{
|
{
|
||||||
|
Py_BEGIN_ALLOW_THREADS;
|
||||||
pthread_mutex_lock(&self->lock);
|
pthread_mutex_lock(&self->lock);
|
||||||
|
|
||||||
struct connectionObject_notice *tmp, *notice = self->notice_pending;
|
struct connectionObject_notice *tmp, *notice = self->notice_pending;
|
||||||
|
@ -105,6 +112,7 @@ conn_notice_clean(connectionObject *self)
|
||||||
self->notice_pending = NULL;
|
self->notice_pending = NULL;
|
||||||
|
|
||||||
pthread_mutex_unlock(&self->lock);
|
pthread_mutex_unlock(&self->lock);
|
||||||
|
Py_END_ALLOW_THREADS;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* conn_setup - setup and read basic information about the connection */
|
/* conn_setup - setup and read basic information about the connection */
|
||||||
|
@ -112,6 +120,10 @@ conn_notice_clean(connectionObject *self)
|
||||||
int
|
int
|
||||||
conn_setup(connectionObject *self, PGconn *pgconn)
|
conn_setup(connectionObject *self, PGconn *pgconn)
|
||||||
{
|
{
|
||||||
|
Py_BEGIN_ALLOW_THREADS;
|
||||||
|
pthread_mutex_lock(&self->lock);
|
||||||
|
Py_BLOCK_THREADS;
|
||||||
|
|
||||||
PGresult *pgres;
|
PGresult *pgres;
|
||||||
const char *data, *tmp;
|
const char *data, *tmp;
|
||||||
const char *scs; /* standard-conforming strings */
|
const char *scs; /* standard-conforming strings */
|
||||||
|
@ -160,26 +172,32 @@ conn_setup(connectionObject *self, PGconn *pgconn)
|
||||||
Dprintf("conn_connect: server requires E'' quotes: %s",
|
Dprintf("conn_connect: server requires E'' quotes: %s",
|
||||||
self->equote ? "YES" : "NO");
|
self->equote ? "YES" : "NO");
|
||||||
|
|
||||||
Py_BEGIN_ALLOW_THREADS;
|
Py_UNBLOCK_THREADS;
|
||||||
pgres = PQexec(pgconn, datestyle);
|
pgres = PQexec(pgconn, datestyle);
|
||||||
Py_END_ALLOW_THREADS;
|
Py_BLOCK_THREADS;
|
||||||
|
|
||||||
if (pgres == NULL || PQresultStatus(pgres) != PGRES_COMMAND_OK ) {
|
if (pgres == NULL || PQresultStatus(pgres) != PGRES_COMMAND_OK ) {
|
||||||
PyErr_SetString(OperationalError, "can't set datestyle to ISO");
|
PyErr_SetString(OperationalError, "can't set datestyle to ISO");
|
||||||
PQfinish(pgconn);
|
PQfinish(pgconn);
|
||||||
IFCLEARPGRES(pgres);
|
IFCLEARPGRES(pgres);
|
||||||
|
Py_UNBLOCK_THREADS;
|
||||||
|
pthread_mutex_unlock(&self->lock);
|
||||||
|
Py_BLOCK_THREADS;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
CLEARPGRES(pgres);
|
CLEARPGRES(pgres);
|
||||||
|
|
||||||
Py_BEGIN_ALLOW_THREADS;
|
Py_UNBLOCK_THREADS;
|
||||||
pgres = PQexec(pgconn, encoding);
|
pgres = PQexec(pgconn, encoding);
|
||||||
Py_END_ALLOW_THREADS;
|
Py_BLOCK_THREADS;
|
||||||
|
|
||||||
if (pgres == NULL || PQresultStatus(pgres) != PGRES_TUPLES_OK) {
|
if (pgres == NULL || PQresultStatus(pgres) != PGRES_TUPLES_OK) {
|
||||||
PyErr_SetString(OperationalError, "can't fetch client_encoding");
|
PyErr_SetString(OperationalError, "can't fetch client_encoding");
|
||||||
PQfinish(pgconn);
|
PQfinish(pgconn);
|
||||||
IFCLEARPGRES(pgres);
|
IFCLEARPGRES(pgres);
|
||||||
|
Py_UNBLOCK_THREADS;
|
||||||
|
pthread_mutex_unlock(&self->lock);
|
||||||
|
Py_BLOCK_THREADS;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
tmp = PQgetvalue(pgres, 0, 0);
|
tmp = PQgetvalue(pgres, 0, 0);
|
||||||
|
@ -188,6 +206,9 @@ conn_setup(connectionObject *self, PGconn *pgconn)
|
||||||
PyErr_NoMemory();
|
PyErr_NoMemory();
|
||||||
PQfinish(pgconn);
|
PQfinish(pgconn);
|
||||||
IFCLEARPGRES(pgres);
|
IFCLEARPGRES(pgres);
|
||||||
|
Py_UNBLOCK_THREADS;
|
||||||
|
pthread_mutex_unlock(&self->lock);
|
||||||
|
Py_BLOCK_THREADS;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
for (i=0 ; i < strlen(tmp) ; i++)
|
for (i=0 ; i < strlen(tmp) ; i++)
|
||||||
|
@ -195,15 +216,18 @@ conn_setup(connectionObject *self, PGconn *pgconn)
|
||||||
self->encoding[i] = '\0';
|
self->encoding[i] = '\0';
|
||||||
CLEARPGRES(pgres);
|
CLEARPGRES(pgres);
|
||||||
|
|
||||||
Py_BEGIN_ALLOW_THREADS;
|
Py_UNBLOCK_THREADS;
|
||||||
pgres = PQexec(pgconn, isolevel);
|
pgres = PQexec(pgconn, isolevel);
|
||||||
Py_END_ALLOW_THREADS;
|
Py_BLOCK_THREADS;
|
||||||
|
|
||||||
if (pgres == NULL || PQresultStatus(pgres) != PGRES_TUPLES_OK) {
|
if (pgres == NULL || PQresultStatus(pgres) != PGRES_TUPLES_OK) {
|
||||||
PyErr_SetString(OperationalError,
|
PyErr_SetString(OperationalError,
|
||||||
"can't fetch default_isolation_level");
|
"can't fetch default_isolation_level");
|
||||||
PQfinish(pgconn);
|
PQfinish(pgconn);
|
||||||
IFCLEARPGRES(pgres);
|
IFCLEARPGRES(pgres);
|
||||||
|
Py_UNBLOCK_THREADS;
|
||||||
|
pthread_mutex_unlock(&self->lock);
|
||||||
|
Py_BLOCK_THREADS;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
data = PQgetvalue(pgres, 0, 0);
|
data = PQgetvalue(pgres, 0, 0);
|
||||||
|
@ -217,6 +241,10 @@ conn_setup(connectionObject *self, PGconn *pgconn)
|
||||||
self->isolation_level = 2;
|
self->isolation_level = 2;
|
||||||
CLEARPGRES(pgres);
|
CLEARPGRES(pgres);
|
||||||
|
|
||||||
|
Py_UNBLOCK_THREADS;
|
||||||
|
pthread_mutex_unlock(&self->lock);
|
||||||
|
Py_END_ALLOW_THREADS;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -366,9 +366,7 @@ psyco_conn_reset(connectionObject *self)
|
||||||
if (pq_reset(self) < 0)
|
if (pq_reset(self) < 0)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
pthread_mutex_lock(&self->lock);
|
|
||||||
res = conn_setup(self, self->pgconn);
|
res = conn_setup(self, self->pgconn);
|
||||||
pthread_mutex_unlock(&self->lock);
|
|
||||||
if (res < 0)
|
if (res < 0)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user