freetdm: ftmod_pritap - Use a single thread per every pair of spans tapping a single line

This commit is contained in:
Moises Silva 2012-10-25 20:58:46 -04:00
parent aeb07172b0
commit 87a1d78e42
1 changed files with 72 additions and 32 deletions

View File

@ -42,6 +42,7 @@
typedef enum {
PRITAP_RUNNING = (1 << 0),
PRITAP_MASTER = (1 << 1),
} pritap_flags_t;
typedef struct {
@ -373,9 +374,9 @@ static __inline__ void pritap_check_state(ftdm_span_t *span)
uint32_t j;
ftdm_clear_flag_locked(span, FTDM_SPAN_STATE_CHANGE);
for(j = 1; j <= span->chan_count; j++) {
ftdm_mutex_lock(span->channels[j]->mutex);
ftdm_channel_lock(span->channels[j]);
ftdm_channel_advance_states(span->channels[j]);
ftdm_mutex_unlock(span->channels[j]->mutex);
ftdm_channel_unlock(span->channels[j]);
}
}
}
@ -685,14 +686,14 @@ static void handle_pri_passive_event(pritap_t *pritap, pri_event *e)
pritap->span->name, PRI_SPAN(e->answer.channel), PRI_CHANNEL(e->answer.channel), crv);
if (!(pcall = tap_pri_get_pcall_bycrv(pritap, crv))) {
ftdm_log(FTDM_LOG_DEBUG,
"ignoring answer in channel %s:%d:%d for callref %d since we don't know about it",
pritap->span->name, PRI_SPAN(e->proceeding.channel), PRI_CHANNEL(e->proceeding.channel), crv);
"ignoring answer in channel %s:%d:%d for callref %d since we don't know about it\n",
pritap->span->name, PRI_SPAN(e->answer.channel), PRI_CHANNEL(e->proceeding.channel), crv);
break;
}
if (!pcall->fchan) {
ftdm_log(FTDM_LOG_ERROR,
"Received answer in channel %s:%d:%d for callref %d but we never got a channel",
pritap->span->name, PRI_SPAN(e->proceeding.channel), PRI_CHANNEL(e->proceeding.channel), crv);
"Received answer in channel %s:%d:%d for callref %d but we never got a channel\n",
pritap->span->name, PRI_SPAN(e->answer.channel), PRI_CHANNEL(e->answer.channel), crv);
break;
}
ftdm_channel_lock(pcall->fchan);
@ -747,12 +748,14 @@ static void handle_pri_passive_event(pritap_t *pritap, pri_event *e)
static void *ftdm_pritap_run(ftdm_thread_t *me, void *obj)
{
ftdm_span_t *span = (ftdm_span_t *) obj;
ftdm_span_t *peer = NULL;
pritap_t *pritap = span->signal_data;
pritap_t *p_pritap = NULL;
pri_event *event = NULL;
struct pollfd dpoll = { 0, 0, 0 };
struct pollfd dpoll[2];
int rc = 0;
ftdm_log(FTDM_LOG_DEBUG, "Tapping PRI thread started on span %d\n", span->span_id);
ftdm_log(FTDM_LOG_DEBUG, "Tapping PRI thread started on span %s\n", span->name);
pritap->span = span;
@ -770,48 +773,80 @@ static void *ftdm_pritap_run(ftdm_thread_t *me, void *obj)
goto done;
}
dpoll.fd = pritap->dchan->sockfd;
/* The last span starting runs the show ...
* This simplifies locking and avoid races by having multiple threads for a single tapped link
* Since both threads really handle a single tapped link there is no benefit on multi-threading, just complications ... */
peer = pritap->peerspan;
p_pritap = peer->signal_data;
if (!ftdm_test_flag(pritap, PRITAP_MASTER)) {
ftdm_log(FTDM_LOG_DEBUG, "Running dummy thread on span %s\n", span->name);
while (ftdm_running() && !ftdm_test_flag(span, FTDM_SPAN_STOP_THREAD)) {
poll(NULL, 0, 100);
}
} else {
memset(&dpoll, 0, sizeof(dpoll));
dpoll[0].fd = pritap->dchan->sockfd;
dpoll[1].fd = p_pritap->dchan->sockfd;
while (ftdm_running() && !ftdm_test_flag(span, FTDM_SPAN_STOP_THREAD)) {
ftdm_log(FTDM_LOG_DEBUG, "Master tapping thread on span %s (fd1=%d, fd2=%d)\n", span->name,
pritap->dchan->sockfd, p_pritap->dchan->sockfd);
while (ftdm_running() && !ftdm_test_flag(span, FTDM_SPAN_STOP_THREAD)) {
pritap_check_state(span);
pritap_check_state(span);
pritap_check_state(peer);
dpoll.revents = 0;
dpoll.events = POLLIN;
dpoll[0].revents = 0;
dpoll[0].events = POLLIN;
rc = poll(&dpoll, 1, 10);
dpoll[1].revents = 0;
dpoll[1].events = POLLIN;
if (rc < 0) {
if (errno == EINTR) {
ftdm_log(FTDM_LOG_DEBUG, "D-channel waiting interrupted, continuing ...\n");
rc = poll(&dpoll[0], 2, 10);
if (rc < 0) {
if (errno == EINTR) {
ftdm_log(FTDM_LOG_DEBUG, "D-channel waiting interrupted, continuing ...\n");
continue;
}
ftdm_log(FTDM_LOG_ERROR, "poll failed: %s\n", strerror(errno));
continue;
}
ftdm_log(FTDM_LOG_ERROR, "poll failed: %s\n", strerror(errno));
continue;
}
pri_schedule_run(pritap->pri);
pri_schedule_run(pritap->pri);
pri_schedule_run(p_pritap->pri);
if (rc) {
if (dpoll.revents & POLLIN) {
event = pri_read_event(pritap->pri);
if (event) {
handle_pri_passive_event(pritap, event);
pritap_check_state(span);
pritap_check_state(peer);
if (rc) {
if (dpoll[0].revents & POLLIN) {
event = pri_read_event(pritap->pri);
if (event) {
handle_pri_passive_event(pritap, event);
pritap_check_state(span);
}
}
} else {
ftdm_log(FTDM_LOG_WARNING, "nothing to read?\n");
}
}
pritap_check_state(span);
if (dpoll[1].revents & POLLIN) {
event = pri_read_event(p_pritap->pri);
if (event) {
handle_pri_passive_event(p_pritap, event);
pritap_check_state(peer);
}
}
}
}
}
done:
ftdm_log(FTDM_LOG_DEBUG, "Tapping PRI thread ended on span %d\n", span->span_id);
ftdm_log(FTDM_LOG_DEBUG, "Tapping PRI thread ended on span %s\n", span->name);
ftdm_clear_flag(span, FTDM_SPAN_IN_THREAD);
ftdm_clear_flag(pritap, PRITAP_RUNNING);
ftdm_clear_flag(pritap, PRITAP_MASTER);
return NULL;
}
@ -897,6 +932,7 @@ static ftdm_status_t ftdm_pritap_start(ftdm_span_t *span)
{
ftdm_status_t ret;
pritap_t *pritap = span->signal_data;
pritap_t *p_pritap = pritap->peerspan->signal_data;
if (ftdm_test_flag(pritap, PRITAP_RUNNING)) {
return FTDM_FAIL;
@ -908,6 +944,10 @@ static ftdm_status_t ftdm_pritap_start(ftdm_span_t *span)
ftdm_clear_flag(span, FTDM_SPAN_IN_THREAD);
ftdm_set_flag(pritap, PRITAP_RUNNING);
if (p_pritap && ftdm_test_flag(p_pritap, PRITAP_RUNNING)) {
/* our peer already started, we're the master */
ftdm_set_flag(pritap, PRITAP_MASTER);
}
ret = ftdm_thread_create_detached(ftdm_pritap_run, span);
if (ret != FTDM_SUCCESS) {