Re: Lock-ups with multi-threading - draft patch

Richard Davies <[email protected]>
Newsgroups gmane.comp.python.db.psycopg.devel
Message-ID <[email protected]>
> > This needs double-checking, in particular for whether Py_BLOCK_THREADS
> > and Py_UNBLOCK_THREADS should be used inside any of these sections to
> > protect any non-thread-safe code.
..
> Thank you for tracking this down and providing a patch.  I think you
> are right about this being an issue with the dependency between
> Python's GIL and psycopg2's connection locks, but the patch itself has
> problems.
> 
> Namely, calling any Python API functions without holding the GIL is an
> error and can corrupt the interpreter's internal state.  A simple fix
> would be to reaquire the GIL after acquiring the connection lock (I
> think this should be okay).

OK, I'm attaching a second patch, in which I take this approach, using
Py_BLOCK_THREADS. I think this is now good for conn_notice_process() and
conn_notice_clean() in connection_int.c


I'm less sure about the change to psyco_conn_reset() in connection_type.c -
there is a lot of code inside the sub-call to conn_setup(), including nested
uses of Py_BEGIN_ALLOW_THREADS (which I think is prohibited in Python?).

What do you think about moving the locking of the connection from
psyco_conn_reset() to inside conn_setup(), where it could be done inside on
of the existing Py_BEGIN_ALLOW_THREADS blocks?

Cheers,

Richard.

==================================
diff -uNr psycopg2-2.0.12/psycopg/connection_int.c psycopg2-2.0.12.patch/psycopg/connection_int.c
--- psycopg2-2.0.12/psycopg/connection_int.c	2009-08-09 15:09:46.000000000 +0100
+++ psycopg2-2.0.12.patch/psycopg/connection_int.c	2009-09-28 17:37:41.000000000 +0100
@@ -64,11 +64,13 @@
 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 +82,12 @@
         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 +95,7 @@
 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 +110,7 @@
     self->notice_pending = NULL;
     
     pthread_mutex_unlock(&self->lock);    
+    Py_END_ALLOW_THREADS;
 }
 
 /* conn_setup - setup and read basic information about the connection */
diff -uNr psycopg2-2.0.12/psycopg/connection_type.c psycopg2-2.0.12.patch/psycopg/connection_type.c
--- psycopg2-2.0.12/psycopg/connection_type.c	2009-08-09 15:08:59.000000000 +0100
+++ psycopg2-2.0.12.patch/psycopg/connection_type.c	2009-09-28 17:32:22.000000000 +0100
@@ -366,9 +366,16 @@
     if (pq_reset(self) < 0)
         return NULL;
 
+    Py_BEGIN_ALLOW_THREADS;
     pthread_mutex_lock(&self->lock);
+    Py_BLOCK_THREADS;
+
     res = conn_setup(self, self->pgconn);
+
+    Py_UNBLOCK_THREADS;
     pthread_mutex_unlock(&self->lock);
+    Py_END_ALLOW_THREADS;
+
     if (res < 0)
         return NULL;
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.