[Freeswitch-trunk] [commit] r13721 - freeswitch/trunk/src/mod/languages/mod_python
FreeSWITCH SVN
mikej at freeswitch.org
Tue Jun 9 08:09:39 PDT 2009
Author: mikej
Date: Tue Jun 9 10:09:39 2009
New Revision: 13721
Log:
mod_python: fix seg on unload when scripts are running (MODLANG-107)
Modified:
freeswitch/trunk/src/mod/languages/mod_python/mod_python.c
Modified: freeswitch/trunk/src/mod/languages/mod_python/mod_python.c
==============================================================================
--- freeswitch/trunk/src/mod/languages/mod_python/mod_python.c (original)
+++ freeswitch/trunk/src/mod/languages/mod_python/mod_python.c Tue Jun 9 10:09:39 2009
@@ -59,7 +59,17 @@
char *xml_handler;
} globals;
-static void eval_some_python(const char *funcname, char *args, switch_core_session_t *session, switch_stream_handle_t *stream, switch_event_t *params, char **str)
+struct switch_py_thread {
+ struct switch_py_thread *prev, *next;
+ char *cmd;
+ char *args;
+ switch_memory_pool_t *pool;
+ PyThreadState *tstate;
+};
+struct switch_py_thread *thread_pool_head = NULL;
+static switch_mutex_t *THREAD_POOL_LOCK = NULL;
+
+static void eval_some_python(const char *funcname, char *args, switch_core_session_t *session, switch_stream_handle_t *stream, switch_event_t *params, char **str, struct switch_py_thread *pt)
{
PyThreadState *tstate = NULL;
char *dupargs = NULL;
@@ -110,6 +120,11 @@
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "error acquiring tstate\n");
goto done;
}
+
+ /* Save state in thread struct so we can terminate it later if needed */
+ if (pt)
+ pt->tstate = tstate;
+
// swap in thread state
PyEval_AcquireThread(tstate);
init_freeswitch();
@@ -178,7 +193,8 @@
if (str) {
*str = strdup((char *) PyString_AsString(result));
}
- } else {
+ } else if (!PyErr_ExceptionMatches(PyExc_SystemExit)) {
+ // Print error, but ignore SystemExit
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error calling python script\n");
PyErr_Print();
PyErr_Clear();
@@ -224,7 +240,7 @@
switch_assert(mycmd);
- eval_some_python("xml_fetch", mycmd, NULL, NULL, params, &str);
+ eval_some_python("xml_fetch", mycmd, NULL, NULL, params, &str, NULL);
if (str) {
if (switch_strlen_zero(str)) {
@@ -278,21 +294,36 @@
SWITCH_STANDARD_APP(python_function)
{
- eval_some_python("handler", (char *) data, session, NULL, NULL, NULL);
+ eval_some_python("handler", (char *) data, session, NULL, NULL, NULL, NULL);
}
-struct switch_py_thread {
- char *args;
- switch_memory_pool_t *pool;
-};
-
static void *SWITCH_THREAD_FUNC py_thread_run(switch_thread_t *thread, void *obj)
{
switch_memory_pool_t *pool;
struct switch_py_thread *pt = (struct switch_py_thread *) obj;
- eval_some_python("runtime", pt->args, NULL, NULL, NULL, NULL);
+ /* Put thread in pool so we keep track of our threads */
+ switch_mutex_lock(THREAD_POOL_LOCK);
+ pt->next = thread_pool_head;
+ pt->prev = NULL;
+ if (pt->next)
+ pt->next->prev = pt;
+ thread_pool_head = pt;
+ switch_mutex_unlock(THREAD_POOL_LOCK);
+
+ /* Run the python script */
+ eval_some_python("runtime", pt->args, NULL, NULL, NULL, NULL, pt);
+
+ /* Thread is dead, remove from pool */
+ switch_mutex_lock(THREAD_POOL_LOCK);
+ if (pt->next)
+ pt->next->prev = pt->prev;
+ if (pt->prev)
+ pt->prev->next = pt->next;
+ if (thread_pool_head == pt)
+ thread_pool_head = pt->next;
+ switch_mutex_unlock(THREAD_POOL_LOCK);
pool = pt->pool;
switch_core_destroy_memory_pool(&pool);
@@ -303,7 +334,7 @@
SWITCH_STANDARD_API(api_python)
{
- eval_some_python("fsapi", (char *) cmd, session, stream, NULL, NULL);
+ eval_some_python("fsapi", (char *) cmd, session, stream, NULL, NULL, NULL);
return SWITCH_STATUS_SUCCESS;
}
@@ -383,6 +414,8 @@
PyEval_ReleaseLock();
}
+ switch_mutex_init(&THREAD_POOL_LOCK, SWITCH_MUTEX_NESTED, pool);
+
do_config();
/* connect my internal structure to the blank pointer passed to me */
@@ -402,6 +435,53 @@
{
PyInterpreterState *mainInterpreterState;
PyThreadState *myThreadState;
+ int thread_cnt = 0;
+ struct switch_py_thread *pt = NULL;
+ struct switch_py_thread *nextpt;
+ int i;
+
+ /* Kill all remaining threads */
+ pt = thread_pool_head;
+ PyEval_AcquireLock();
+ while (pt) {
+ thread_cnt ++;
+ nextpt = pt->next;
+
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING,
+ "Forcibly terminating script [%s]\n", pt->args);
+
+ /* Kill python script */
+ PyThreadState_Swap(pt->tstate);
+ PyThreadState_SetAsyncExc(pt->tstate->thread_id, PyExc_SystemExit);
+
+ pt = nextpt;
+ }
+ PyThreadState_Swap(mainThreadState);
+ PyEval_ReleaseLock();
+ switch_yield(1000000);
+
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING,
+ "Had to kill %d threads\n", thread_cnt);
+
+ /* Give threads a few seconds to terminate.
+ Not using switch_thread_join() since if threads refuse to die
+ then freeswitch will hang */
+ for (i=0; i < 10 && thread_pool_head; i++) {
+ switch_yield(1000000);
+ }
+ if (thread_pool_head) {
+ /* Not all threads died in time */
+ pt = thread_pool_head;
+ while (pt) {
+ nextpt = pt->next;
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR,
+ "Script [%s] didn't exit in time\n", pt->args);
+ pt = nextpt;
+ }
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR,
+ "Forcing python shutdown. This might cause freeswitch to crash!\n");
+ }
+
PyEval_AcquireLock();
mainInterpreterState = mainThreadState->interp;
More information about the Freeswitch-trunk
mailing list