From: Jaroslav Kysela Date: Mon, 19 Jun 2017 18:40:21 +0000 (+0200) Subject: descrambler/cwc: try to avoid dead-lock (descrambler_table_callback) X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=f4a01aec3c7261519fae079060d54d5fe8ada086;p=thirdparty%2Ftvheadend.git descrambler/cwc: try to avoid dead-lock (descrambler_table_callback) --- diff --git a/src/descrambler.h b/src/descrambler.h index e45d7f268..61de6007c 100644 --- a/src/descrambler.h +++ b/src/descrambler.h @@ -115,9 +115,15 @@ typedef void (*descrambler_section_callback_t) */ typedef struct descrambler_ecmsec { LIST_ENTRY(descrambler_ecmsec) link; + LIST_ENTRY(descrambler_ecmsec) active_link; + int refcnt; + uint8_t changed; uint8_t number; + uint8_t quick_ecm_called; uint8_t *last_data; int last_data_len; + descrambler_section_callback_t callback; + void *opaque; } descrambler_ecmsec_t; typedef struct descrambler_section { @@ -125,7 +131,6 @@ typedef struct descrambler_section { descrambler_section_callback_t callback; void *opaque; LIST_HEAD(, descrambler_ecmsec) ecmsecs; - uint8_t quick_ecm_called; } descrambler_section_t; typedef struct descrambler_table { diff --git a/src/descrambler/descrambler.c b/src/descrambler/descrambler.c index 8345c06f2..72d58766a 100644 --- a/src/descrambler/descrambler.c +++ b/src/descrambler/descrambler.c @@ -709,8 +709,11 @@ cont: td->td_nicename, dr->dr_key_const ? " (const)" : ""); descrambler_change_keystate(td, DS_IDLE, 0); - if (td->td_ecm_idle) + if (td->td_ecm_idle) { + pthread_mutex_unlock(&t->s_stream_mutex); td->td_ecm_idle(td); + pthread_mutex_lock(&t->s_stream_mutex); + } goto fin; } @@ -858,7 +861,8 @@ descrambler_flush_table_data( service_t *t ) while ((des = LIST_FIRST(&ds->ecmsecs)) != NULL) { LIST_REMOVE(des, link); free(des->last_data); - free(des); + if (atomic_dec(&des->refcnt, 1) == 0) + free(des); } } pthread_mutex_unlock(&mux->mm_descrambler_lock); @@ -1212,6 +1216,7 @@ descrambler_table_callback descrambler_ecmsec_t *des; th_descrambler_runtime_t *dr; th_descrambler_key_t *tk; + LIST_HEAD(,descrambler_ecmsec) sections; int emm = (mt->mt_flags & MT_FAST) == 0; mpegts_service_t *t; int64_t clk; @@ -1220,6 +1225,7 @@ descrambler_table_callback if (len < 6) return 0; + LIST_INIT(§ions); pthread_mutex_lock(&mt->mt_mux->mm_descrambler_lock); TAILQ_FOREACH(ds, &dt->sections, link) { if (!emm) { @@ -1244,14 +1250,28 @@ descrambler_table_callback } else { des->last_data_len = 0; } - ds->callback(ds->opaque, mt->mt_pid, ptr, len, emm); + des->changed = 2; + } else { + des->changed = des->last_data != NULL ? 1 : 0; + } + atomic_add(&des->refcnt, 1); + des->callback = ds->callback; + des->opaque = ds->opaque; + LIST_INSERT_HEAD(§ions, des, active_link); + } + pthread_mutex_unlock(&mt->mt_mux->mm_descrambler_lock); + + LIST_FOREACH(des, §ions, active_link) { + if (des->changed == 2) { + des->callback(des->opaque, mt->mt_pid, ptr, len, emm); if (!emm) { /* ECM */ if ((t = mt->mt_service) != NULL) { + pthread_mutex_lock(&t->s_stream_mutex); /* The keys are requested from this moment */ dr = t->s_descramble; if (dr) { - if (!dr->dr_quick_ecm && !ds->quick_ecm_called) { - ds->quick_ecm_called = 1; + if (!dr->dr_quick_ecm && !des->quick_ecm_called) { + des->quick_ecm_called = 1; dr->dr_quick_ecm = descrambler_quick_ecm(mt->mt_service, mt->mt_pid); if (dr->dr_quick_ecm) tvhdebug(LS_DESCRAMBLER, "quick ECM enabled for service '%s'", @@ -1271,6 +1291,7 @@ descrambler_table_callback tvhtrace(LS_DESCRAMBLER, "ECM message %02x (section %d, len %d, pid %d) for service \"%s\"", ptr[0], des->number, len, mt->mt_pid, t->s_dvb_svcname); } + pthread_mutex_unlock(&t->s_stream_mutex); } else tvhtrace(LS_DESCRAMBLER, "Unknown fast table message %02x (section %d, len %d, pid %d)", ptr[0], des->number, len, mt->mt_pid); @@ -1291,8 +1312,9 @@ descrambler_table_callback tvhtrace(LS_DESCRAMBLER_EMM, "%s message %02x:{%02x:%02x}:%02x (len %d, pid %d)", s, ptr[0], ptr[1], ptr[2], ptr[3], len, mt->mt_pid); } - } else if (des->last_data && !emm) { + } else if (des->changed == 1 && !emm) { if ((t = mt->mt_service) != NULL) { + pthread_mutex_lock(&t->s_stream_mutex); if ((dr = t->s_descramble) != NULL) { clk = mclk(); for (i = 0; i < DESCRAMBLER_MAX_KEYS; i++) { @@ -1308,10 +1330,16 @@ descrambler_table_callback } } } + pthread_mutex_unlock(&t->s_stream_mutex); } } } - pthread_mutex_unlock(&mt->mt_mux->mm_descrambler_lock); + + while ((des = LIST_FIRST(§ions)) != NULL) { + LIST_REMOVE(des, active_link); + if (atomic_dec(&des->refcnt, 1) == 0) + free(des); + } return 0; } @@ -1394,7 +1422,8 @@ descrambler_close_pid_( mpegts_mux_t *mux, void *opaque, int pid ) while ((des = LIST_FIRST(&ds->ecmsecs)) != NULL) { LIST_REMOVE(des, link); free(des->last_data); - free(des); + if (atomic_dec(&des->refcnt, 1) == 0) + free(des); } if (TAILQ_FIRST(&dt->sections) == NULL) { TAILQ_REMOVE(&mux->mm_descrambler_tables, dt, link); @@ -1442,7 +1471,8 @@ descrambler_flush_tables( mpegts_mux_t *mux ) while ((des = LIST_FIRST(&ds->ecmsecs)) != NULL) { LIST_REMOVE(des, link); free(des->last_data); - free(des); + if (atomic_dec(&des->refcnt, 1) == 0) + free(des); } free(ds); }