From 3a35139a3212d4d07da3c0f391b00f2e1daa2fa3 Mon Sep 17 00:00:00 2001 From: Moises Silva Date: Tue, 31 Aug 2010 18:13:56 -0400 Subject: [PATCH] freetdm: add asynchronous signal notification --- libs/freetdm/src/ftdm_io.c | 52 ++++++++++++++++--- libs/freetdm/src/include/freetdm.h | 35 +++++++------ libs/freetdm/src/include/private/ftdm_core.h | 3 ++ libs/freetdm/src/include/private/ftdm_types.h | 4 ++ 4 files changed, 70 insertions(+), 24 deletions(-) diff --git a/libs/freetdm/src/ftdm_io.c b/libs/freetdm/src/ftdm_io.c index 238a9fc060..c53e9aa1fb 100644 --- a/libs/freetdm/src/ftdm_io.c +++ b/libs/freetdm/src/ftdm_io.c @@ -51,6 +51,7 @@ #include "ftdm_cpu_monitor.h" #define SPAN_PENDING_CHANS_QUEUE_SIZE 1000 +#define SPAN_PENDING_SIGNALS_QUEUE_SIZE 1000 #define FTDM_READ_TRACE_INDEX 0 #define FTDM_WRITE_TRACE_INDEX 1 @@ -463,6 +464,9 @@ static ftdm_status_t ftdm_span_destroy(ftdm_span_t *span) if (span->pendingchans) { ftdm_queue_destroy(&span->pendingchans); } + if (span->pendingsignals) { + ftdm_queue_destroy(&span->pendingsignals); + } ftdm_mutex_unlock(span->mutex); ftdm_mutex_destroy(&span->mutex); ftdm_safe_free(span->signal_data); @@ -4097,6 +4101,9 @@ static ftdm_status_t post_configure_span_channels(ftdm_span_t *span) if (ftdm_test_flag(span, FTDM_SPAN_USE_CHAN_QUEUE)) { status = ftdm_queue_create(&span->pendingchans, SPAN_PENDING_CHANS_QUEUE_SIZE); } + if (status == FTDM_SUCCESS && ftdm_test_flag(span, FTDM_SPAN_USE_SIGNALS_QUEUE)) { + status = ftdm_queue_create(&span->pendingsignals, SPAN_PENDING_SIGNALS_QUEUE_SIZE); + } return status; } @@ -4362,10 +4369,39 @@ FT_DECLARE(ftdm_status_t) ftdm_group_create(ftdm_group_t **group, const char *na return status; } +static ftdm_status_t ftdm_span_trigger_signal(const ftdm_span_t *span, ftdm_sigmsg_t *sigmsg) +{ + return span->signal_cb(sigmsg); +} + +static ftdm_status_t ftdm_span_queue_signal(const ftdm_span_t *span, ftdm_sigmsg_t *sigmsg) +{ + ftdm_sigmsg_t *new_sigmsg = NULL; + + ftdm_assert_return((sigmsg->raw_data == NULL), FTDM_FAIL, "No raw data should be used with asynchronous notification\n"); + + new_sigmsg = ftdm_calloc(1, sizeof(*sigmsg)); + if (!new_sigmsg) { + return FTDM_FAIL; + } + memcpy(new_sigmsg, sigmsg, sizeof(*sigmsg)); + + ftdm_queue_enqueue(span->pendingsignals, new_sigmsg); + return FTDM_SUCCESS; +} + +FT_DECLARE(ftdm_status_t) ftdm_span_trigger_signals(const ftdm_span_t *span) +{ + ftdm_sigmsg_t *sigmsg = NULL; + while ((sigmsg = ftdm_queue_dequeue(span->pendingsignals))) { + ftdm_span_trigger_signal(span, sigmsg); + ftdm_safe_free(sigmsg); + } + return FTDM_SUCCESS; +} + FT_DECLARE(ftdm_status_t) ftdm_span_send_signal(ftdm_span_t *span, ftdm_sigmsg_t *sigmsg) { - ftdm_status_t status = FTDM_FAIL; - if (sigmsg->channel) { ftdm_mutex_lock(sigmsg->channel->mutex); } @@ -4400,10 +4436,12 @@ FT_DECLARE(ftdm_status_t) ftdm_span_send_signal(ftdm_span_t *span, ftdm_sigmsg_t break; } - - /* call the user callback only if set */ - if (span->signal_cb) { - status = span->signal_cb(sigmsg); + + /* if the signaling module uses a queue for signaling notifications, then enqueue it */ + if (ftdm_test_flag(span, FTDM_SPAN_USE_SIGNALS_QUEUE)) { + ftdm_span_queue_signal(span, sigmsg); + } else { + ftdm_span_trigger_signal(span, sigmsg); } done: @@ -4411,7 +4449,7 @@ done: ftdm_mutex_unlock(sigmsg->channel->mutex); } - return status; + return FTDM_SUCCESS; } static void *ftdm_cpu_monitor_run(ftdm_thread_t *me, void *obj) diff --git a/libs/freetdm/src/include/freetdm.h b/libs/freetdm/src/include/freetdm.h index af55370338..b72aeb619a 100644 --- a/libs/freetdm/src/include/freetdm.h +++ b/libs/freetdm/src/include/freetdm.h @@ -317,23 +317,6 @@ typedef struct ftdm_channel_config { float txgain; } ftdm_channel_config_t; -/*! \brief Generic signaling message */ -struct ftdm_sigmsg { - ftdm_signal_event_t event_id; /*!< The type of message */ - ftdm_channel_t *channel; /*!< Related channel */ - uint32_t chan_id; /*!< easy access to chan id */ - uint32_t span_id; /*!< easy access to span_id */ - void *raw_data; /*!< Message specific data if any */ - uint32_t raw_data_len; /*!< Data len in case is needed */ -}; - -/*! \brief Crash policy - * Useful for debugging only, default policy is never, if you wish to crash on asserts then use ftdm_global_set_crash_policy */ -typedef enum { - FTDM_CRASH_NEVER = 0, - FTDM_CRASH_ON_ASSERT -} ftdm_crash_policy_t; - /*! \brief Signaling status on a given span or specific channel on protocols that support it */ @@ -352,6 +335,24 @@ typedef enum { /*! \brief Move from string to ftdm_signaling_status_t and viceversa */ FTDM_STR2ENUM_P(ftdm_str2ftdm_signaling_status, ftdm_signaling_status2str, ftdm_signaling_status_t) +/*! \brief Generic signaling message */ +struct ftdm_sigmsg { + ftdm_signal_event_t event_id; /*!< The type of message */ + ftdm_channel_t *channel; /*!< Related channel */ + uint32_t chan_id; /*!< easy access to chan id */ + uint32_t span_id; /*!< easy access to span_id */ + ftdm_signaling_status_t sigstatus; /*!< Signaling status (valid if event_id is FTDM_SIGEVENT_SIGSTATUS_CHANGED) */ + void *raw_data; /*!< Message specific data if any */ + uint32_t raw_data_len; /*!< Data len in case is needed */ +}; + +/*! \brief Crash policy + * Useful for debugging only, default policy is never, if you wish to crash on asserts then use ftdm_global_set_crash_policy */ +typedef enum { + FTDM_CRASH_NEVER = 0, + FTDM_CRASH_ON_ASSERT +} ftdm_crash_policy_t; + /*! \brief I/O waiting flags */ typedef enum { FTDM_NO_FLAGS = 0, diff --git a/libs/freetdm/src/include/private/ftdm_core.h b/libs/freetdm/src/include/private/ftdm_core.h index 95f34b4dd2..74bea8148c 100644 --- a/libs/freetdm/src/include/private/ftdm_core.h +++ b/libs/freetdm/src/include/private/ftdm_core.h @@ -466,6 +466,7 @@ struct ftdm_span { ftdm_state_map_t *state_map; ftdm_caller_data_t default_caller_data; ftdm_queue_t *pendingchans; + ftdm_queue_t *pendingsignals; struct ftdm_span *next; }; @@ -579,6 +580,8 @@ FT_DECLARE(ftdm_status_t) ftdm_span_next_event(ftdm_span_t *span, ftdm_event_t * */ FT_DECLARE(ftdm_status_t) ftdm_channel_queue_dtmf(ftdm_channel_t *ftdmchan, const char *dtmf); +/* dequeue pending signals and notify the user via the span signal callback */ +FT_DECLARE(ftdm_status_t) ftdm_span_trigger_signals(const ftdm_span_t *span); /*! \brief Assert condition diff --git a/libs/freetdm/src/include/private/ftdm_types.h b/libs/freetdm/src/include/private/ftdm_types.h index 572e63299b..d8e8b5c2e6 100644 --- a/libs/freetdm/src/include/private/ftdm_types.h +++ b/libs/freetdm/src/include/private/ftdm_types.h @@ -176,6 +176,10 @@ typedef enum { FTDM_SPAN_USE_CHAN_QUEUE = (1 << 6), FTDM_SPAN_SUGGEST_CHAN_ID = (1 << 7), FTDM_SPAN_USE_AV_RATE = (1 << 8), + /* If you use this flag, you MUST call ftdm_span_trigger_signals to deliver the user signals + * after having called ftdm_send_span_signal(), which with this flag it will just enqueue the signal + * for later delivery */ + FTDM_SPAN_USE_SIGNALS_QUEUE = (1 << 9), } ftdm_span_flag_t; /*! \brief Channel supported features */