summaryrefslogtreecommitdiff
path: root/psycopg/pqpath.c
diff options
context:
space:
mode:
Diffstat (limited to 'psycopg/pqpath.c')
-rw-r--r--psycopg/pqpath.c43
1 files changed, 32 insertions, 11 deletions
diff --git a/psycopg/pqpath.c b/psycopg/pqpath.c
index 0f5beb1..e7bed66 100644
--- a/psycopg/pqpath.c
+++ b/psycopg/pqpath.c
@@ -19,6 +19,12 @@
* Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
+/* IMPORTANT NOTE: no function in this file do its own connection locking
+ except for pg_execute and pq_fetch (that are somehow high-level. This means
+ that all the othe functions should be called while holding a lock to the
+ connection.
+*/
+
#include <Python.h>
#include <string.h>
@@ -33,7 +39,9 @@
#include "psycopg/pgtypes.h"
#include "psycopg/pgversion.h"
-/* pq_raise - raise a python exception of the right kind */
+/* pq_raise - raise a python exception of the right kind
+
+ This function should be called while holding the GIL. */
void
pq_raise(connectionObject *conn, cursorObject *curs, PyObject *exc, char *msg)
@@ -106,7 +114,8 @@ pq_raise(connectionObject *conn, cursorObject *curs, PyObject *exc, char *msg)
critical condition like out of memory or lost connection. it save the error
message and mark the connection as 'wanting cleanup'.
- both functions do not call any Py_*_ALLOW_THREADS macros. */
+ both functions do not call any Py_*_ALLOW_THREADS macros.
+ pq_resolve_critical should be called while holding the GIL. */
void
pq_set_critical(connectionObject *conn, const char *msg)
@@ -140,6 +149,7 @@ pq_resolve_critical(connectionObject *conn, int close)
note that this function does block because it needs to wait for the full
result sets of the previous query to clear them.
+
this function does not call any Py_*_ALLOW_THREADS macros */
void
@@ -149,6 +159,7 @@ pq_clear_async(connectionObject *conn)
do {
pgres = PQgetResult(conn->pgconn);
+ Dprintf("pq_clear_async: clearing PGresult at %p", pgres);
IFCLEARPGRES(pgres);
} while (pgres != NULL);
}
@@ -291,7 +302,10 @@ pq_abort(connectionObject *conn)
a status of 1 means that a call to pq_fetch will block, while a status of 0
means that there is data available to be collected. -1 means an error, the
- exception will be set accordingly. */
+ exception will be set accordingly.
+
+ this fucntion locks the connection object
+ this function call Py_*_ALLOW_THREADS macros */
int
pq_is_busy(connectionObject *conn)
@@ -299,9 +313,15 @@ pq_is_busy(connectionObject *conn)
PGnotify *pgn;
Dprintf("pq_is_busy: consuming input");
+
+ Py_BEGIN_ALLOW_THREADS;
+ pthread_mutex_lock(&(conn->lock));
+
if (PQconsumeInput(conn->pgconn) == 0) {
Dprintf("pq_is_busy: PQconsumeInput() failed");
PyErr_SetString(OperationalError, PQerrorMessage(conn->pgconn));
+ pthread_mutex_unlock(&(conn->lock));
+ Py_BLOCK_THREADS;
return -1;
}
@@ -315,11 +335,12 @@ pq_is_busy(connectionObject *conn)
notify = PyTuple_New(2);
PyTuple_SET_ITEM(notify, 0, PyInt_FromLong((long)pgn->be_pid));
PyTuple_SET_ITEM(notify, 1, PyString_FromString(pgn->relname));
- pthread_mutex_lock(&(conn->lock));
PyList_Append(conn->notifies, notify);
- pthread_mutex_unlock(&(conn->lock));
free(pgn);
}
+
+ pthread_mutex_unlock(&(conn->lock));
+ Py_END_ALLOW_THREADS;
return PQisBusy(conn->pgconn);
}
@@ -656,14 +677,14 @@ pq_fetch(cursorObject *curs)
Dprintf("pq_fetch: no data: entering polling loop");
- Py_BEGIN_ALLOW_THREADS;
- pthread_mutex_lock(&(curs->conn->lock));
-
while (pq_is_busy(curs->conn) > 0) {
fd_set rfds;
struct timeval tv;
int sval, sock;
+ Py_BEGIN_ALLOW_THREADS;
+ pthread_mutex_lock(&(curs->conn->lock));
+
sock = PQsocket(curs->conn->pgconn);
FD_ZERO(&rfds);
FD_SET(sock, &rfds);
@@ -677,14 +698,14 @@ pq_fetch(cursorObject *curs)
Dprintf("pq_fetch: entering PDflush() loop");
while (PQflush(curs->conn->pgconn) != 0);
sval = select(sock+1, &rfds, NULL, NULL, &tv);
+
+ pthread_mutex_unlock(&(curs->conn->lock));
+ Py_END_ALLOW_THREADS;
}
Dprintf("pq_fetch: data is probably ready");
IFCLEARPGRES(curs->pgres);
curs->pgres = PQgetResult(curs->conn->pgconn);
-
- pthread_mutex_unlock(&(curs->conn->lock));
- Py_END_ALLOW_THREADS;
}
/* check for PGRES_FATAL_ERROR result */