chan_console: Fix deadlock caused by unclean thread exit.
To terminate a console channel, stop_stream causes pthread_cancel
to make stream_monitor exit. However, commit 5b8fea93d1
added locking to this function which results in deadlock due to
the stream_monitor thread being killed while it's holding the pvt lock.
To resolve this, a flag is now set and read to indicate abort, so
the use of pthread_cancel and pthread_kill can be avoided altogether.
Resolves: #308
This commit is contained in:
parent
67fd66e2fe
commit
0ab5dea46b
|
@ -152,6 +152,8 @@ static struct console_pvt {
|
||||||
struct ast_frame fr;
|
struct ast_frame fr;
|
||||||
/*! Running = 1, Not running = 0 */
|
/*! Running = 1, Not running = 0 */
|
||||||
unsigned int streamstate:1;
|
unsigned int streamstate:1;
|
||||||
|
/*! Abort stream processing? */
|
||||||
|
unsigned int abort:1;
|
||||||
/*! On-hook = 0, Off-hook = 1 */
|
/*! On-hook = 0, Off-hook = 1 */
|
||||||
unsigned int hookstate:1;
|
unsigned int hookstate:1;
|
||||||
/*! Unmuted = 0, Muted = 1 */
|
/*! Unmuted = 0, Muted = 1 */
|
||||||
|
@ -275,18 +277,19 @@ static void *stream_monitor(void *data)
|
||||||
};
|
};
|
||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
pthread_testcancel();
|
|
||||||
console_pvt_lock(pvt);
|
console_pvt_lock(pvt);
|
||||||
res = Pa_ReadStream(pvt->stream, buf, sizeof(buf) / sizeof(int16_t));
|
res = Pa_ReadStream(pvt->stream, buf, sizeof(buf) / sizeof(int16_t));
|
||||||
console_pvt_unlock(pvt);
|
console_pvt_unlock(pvt);
|
||||||
pthread_testcancel();
|
|
||||||
|
|
||||||
if (!pvt->owner) {
|
if (!pvt->owner || pvt->abort) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (res == paNoError)
|
if (res == paNoError) {
|
||||||
ast_queue_frame(pvt->owner, &f);
|
ast_queue_frame(pvt->owner, &f);
|
||||||
|
} else {
|
||||||
|
ast_log(LOG_WARNING, "Console ReadStream failed: %s\n", Pa_GetErrorText(res));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -401,8 +404,9 @@ static int stop_stream(struct console_pvt *pvt)
|
||||||
if (!pvt->streamstate || pvt->thread == AST_PTHREADT_NULL)
|
if (!pvt->streamstate || pvt->thread == AST_PTHREADT_NULL)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
pthread_cancel(pvt->thread);
|
pvt->abort = 1;
|
||||||
pthread_kill(pvt->thread, SIGURG);
|
/* Wait for pvt->thread to exit cleanly, to avoid killing it while it's holding a lock. */
|
||||||
|
pthread_kill(pvt->thread, SIGURG); /* Wake it up if needed, but don't cancel it */
|
||||||
pthread_join(pvt->thread, NULL);
|
pthread_join(pvt->thread, NULL);
|
||||||
|
|
||||||
console_pvt_lock(pvt);
|
console_pvt_lock(pvt);
|
||||||
|
|
Loading…
Reference in New Issue