pika/pika — pull request #500 by shiroyuki (2014-09-10 04:47:06+00:00)
Title: Fix the select.poll concurrent invocation issue in python 2.7.6 and newer

When a multi-thread application tries to use one or many blocking channel in any threads, the method `ready` in `pika.adapters.blocking_connection.ReadPoller` raises `RuntimeError` originated from the internal poller (`self.poller.poll(...)`).

According to Python's [issue8865](http://bugs.python.org/issue8865), last year, Python developers add `RuntimeError` to address the thread safety issue.

```diff
diff --git a/Modules/selectmodule.c b/Modules/selectmodule.c
--- a/Modules/selectmodule.c
+++ b/Modules/selectmodule.c
@@ -332,6 +332,7 @@
int ufd_uptodate;
int ufd_len;
struct pollfd *ufds;
+ int poll_running;
} pollObject;

static PyTypeObject poll_Type;
@@ -528,16 +529,27 @@
return NULL;
}

+ /* Avoid concurrent poll() invocation, issue 8865 */
+ if (self->poll_running) {
+ PyErr_SetString(PyExc_RuntimeError,
+ "concurrent poll() invocation");
+ return NULL;
+ }
+
/* Ensure the ufd array is up to date */
if (!self->ufd_uptodate)
if (update_ufd_array(self) == 0)
return NULL;

+ self->poll_running = 1;
+
/* call poll() */
Py_BEGIN_ALLOW_THREADS
poll_result = poll(self->ufds, self->ufd_len, timeout);
Py_END_ALLOW_THREADS

+ self->poll_running = 0;
+
if (poll_result < 0) {
PyErr_SetFromErrno(PyExc_OSError);
return NULL;
@@ -614,6 +626,7 @@
array pointed to by ufds matches the contents of the dictionary. */
self->ufd_uptodate = 0;
self->ufds = NULL;
+ self->poll_running = 0;
self->dict = PyDict_New();
if (self->dict == NULL) {
Py_DECREF(self);
```

So, the solution is just to re-initialize the poller.