@@ -107,10 +107,26 @@ static PyObject *db_put_field(PyObject *self, PyObject *args)
107107 if (dbNameToAddr (name , & dbAddr ))
108108 return PyErr_Format (
109109 PyExc_RuntimeError , "dbNameToAddr failed for %s" , name );
110- if (dbPutField (& dbAddr , dbrType , pbuffer , length ))
110+
111+ long put_result ;
112+ /* There are two important locks to consider at this point: The Global
113+ * Interpreter Lock (GIL) and the EPICS record lock. A deadlock is possible if
114+ * this thread holds the GIL and wants the record lock (which happens inside
115+ * dbPutField), and there exists another EPICS thread that has the record lock
116+ * and wants to call Python (which requires the GIL).
117+ * This can occur if this code is called as part of an asynchronous on_update
118+ * callback.
119+ * Therefore, we must ensure we relinquish the GIL while we perform this
120+ * EPICS call, to avoid potential deadlocks.
121+ * See https://github.com/dls-controls/pythonSoftIOC/issues/119. */
122+ Py_BEGIN_ALLOW_THREADS
123+ put_result = dbPutField (& dbAddr , dbrType , pbuffer , length );
124+ Py_END_ALLOW_THREADS
125+ if (put_result )
111126 return PyErr_Format (
112127 PyExc_RuntimeError , "dbPutField failed for %s ", name );
113- Py_RETURN_NONE ;
128+ else
129+ Py_RETURN_NONE ;
114130}
115131
116132static PyObject * db_get_field (PyObject * self , PyObject * args )
@@ -127,11 +143,17 @@ static PyObject *db_get_field(PyObject *self, PyObject *args)
127143 return PyErr_Format (
128144 PyExc_RuntimeError , "dbNameToAddr failed for %s" , name );
129145
146+ long get_result ;
130147 long options = 0 ;
131- if (dbGetField (& dbAddr , dbrType , pbuffer , & options , & length , NULL ))
148+ /* See reasoning for Python macros in long comment in db_put_field. */
149+ Py_BEGIN_ALLOW_THREADS
150+ get_result = dbGetField (& dbAddr , dbrType , pbuffer , & options , & length , NULL );
151+ Py_END_ALLOW_THREADS
152+ if (get_result )
132153 return PyErr_Format (
133154 PyExc_RuntimeError , "dbGetField failed for %s ", name );
134- Py_RETURN_NONE ;
155+ else
156+ Py_RETURN_NONE ;
135157}
136158
137159/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
0 commit comments