added generic interrupt support

git-svn-id: http://svn.openzap.org/svn/openzap/branches/sangoma_boost@1057 a93c3328-9c30-0410-af19-c9cd2b2d52af
This commit is contained in:
Moises Silva 2010-03-12 18:27:24 +00:00
parent 617020ea0c
commit 5305611be3
11 changed files with 372 additions and 233 deletions

View File

@ -5,3 +5,5 @@
then ftdm_event_t would be renamed to ftdm_oob_event_t and the enum_id renamed to type, then ftdm_span_next_event() then ftdm_event_t would be renamed to ftdm_oob_event_t and the enum_id renamed to type, then ftdm_span_next_event()
will only return OOB events will only return OOB events
- query span hw status (connected/disconnected) on startup

View File

@ -49,6 +49,8 @@
#include "ftdm_pika.h" #include "ftdm_pika.h"
#endif #endif
#define SPAN_PENDING_CHANS_QUEUE_SIZE 1000
static int time_is_init = 0; static int time_is_init = 0;
static void time_init(void) static void time_init(void)
@ -410,6 +412,7 @@ static ftdm_status_t ftdm_span_destroy(ftdm_span_t *span)
} }
/* destroy final basic resources of the span data structure */ /* destroy final basic resources of the span data structure */
ftdm_queue_destroy(&span->pendingchans);
ftdm_mutex_unlock(span->mutex); ftdm_mutex_unlock(span->mutex);
ftdm_mutex_destroy(&span->mutex); ftdm_mutex_destroy(&span->mutex);
ftdm_safe_free(span->signal_data); ftdm_safe_free(span->signal_data);
@ -504,16 +507,19 @@ FT_DECLARE(ftdm_status_t) ftdm_span_create(ftdm_io_interface_t *fio, ftdm_span_t
ftdm_span_t *new_span = NULL; ftdm_span_t *new_span = NULL;
ftdm_status_t status = FTDM_FAIL; ftdm_status_t status = FTDM_FAIL;
assert(fio != NULL); ftdm_assert(fio != NULL, "No IO provided\n");
ftdm_mutex_lock(globals.mutex); ftdm_mutex_lock(globals.mutex);
if (globals.span_index < FTDM_MAX_SPANS_INTERFACE) { if (globals.span_index < FTDM_MAX_SPANS_INTERFACE) {
new_span = ftdm_malloc(sizeof(*new_span)); new_span = ftdm_calloc(sizeof(*new_span), 1);
assert(new_span); ftdm_assert(new_span, "allocating span failed\n");
memset(new_span, 0, sizeof(*new_span));
status = ftdm_mutex_create(&new_span->mutex); status = ftdm_mutex_create(&new_span->mutex);
assert(status == FTDM_SUCCESS); ftdm_assert(status == FTDM_SUCCESS, "mutex creation failed\n");
status = ftdm_queue_create(&new_span->pendingchans, SPAN_PENDING_CHANS_QUEUE_SIZE);
ftdm_assert(status == FTDM_SUCCESS, "span chans queue creation failed\n");
ftdm_set_flag(new_span, FTDM_SPAN_CONFIGURED); ftdm_set_flag(new_span, FTDM_SPAN_CONFIGURED);
new_span->span_id = ++globals.span_index; new_span->span_id = ++globals.span_index;
@ -1154,7 +1160,12 @@ FT_DECLARE(ftdm_status_t) ftdm_channel_set_state(ftdm_channel_t *ftdmchan, ftdm_
if (ok) { if (ok) {
ftdm_set_flag(ftdmchan, FTDM_CHANNEL_STATE_CHANGE); ftdm_set_flag(ftdmchan, FTDM_CHANNEL_STATE_CHANGE);
ftdm_set_flag_locked(ftdmchan->span, FTDM_SPAN_STATE_CHANGE);
ftdm_mutex_lock(ftdmchan->span->mutex);
ftdm_set_flag(ftdmchan->span, FTDM_SPAN_STATE_CHANGE);
ftdm_queue_enqueue(ftdmchan->span->pendingchans, ftdmchan);
ftdm_mutex_unlock(ftdmchan->span->mutex);
ftdmchan->last_state = ftdmchan->state; ftdmchan->last_state = ftdmchan->state;
ftdmchan->state = state; ftdmchan->state = state;
} }
@ -3155,44 +3166,85 @@ FT_DECLARE(int) ftdm_load_modules(void)
FT_DECLARE(ftdm_status_t) ftdm_unload_modules(void) FT_DECLARE(ftdm_status_t) ftdm_unload_modules(void)
{ {
ftdm_hash_iterator_t *i; ftdm_hash_iterator_t *i = NULL;
ftdm_dso_lib_t lib; ftdm_dso_lib_t lib = NULL;
char modpath[255] = { 0 };
/* stop signaling interfaces first as signaling depends on I/O and not the other way around */
for (i = hashtable_first(globals.module_hash); i; i = hashtable_next(i)) { for (i = hashtable_first(globals.module_hash); i; i = hashtable_next(i)) {
const void *key; const void *key = NULL;
void *val; void *val = NULL;
ftdm_module_t *mod = NULL;
hashtable_this(i, &key, NULL, &val); hashtable_this(i, &key, NULL, &val);
if (key && val) { if (!key || !val) {
ftdm_module_t *mod = (ftdm_module_t *) val; continue;
if (!mod) {
continue;
}
if (mod->io_unload) {
if (mod->io_unload() == FTDM_SUCCESS) {
ftdm_log(FTDM_LOG_INFO, "Unloading IO %s\n", mod->name);
} else {
ftdm_log(FTDM_LOG_ERROR, "Error unloading IO %s\n", mod->name);
}
}
if (mod->sig_unload) {
if (mod->sig_unload() == FTDM_SUCCESS) {
ftdm_log(FTDM_LOG_INFO, "Unloading SIG %s\n", mod->name);
} else {
ftdm_log(FTDM_LOG_ERROR, "Error unloading SIG %s\n", mod->name);
}
}
ftdm_log(FTDM_LOG_INFO, "Unloading %s\n", mod->path);
lib = mod->lib;
ftdm_dso_destroy(&lib);
} }
mod = (ftdm_module_t *) val;
if (!mod->sig_unload) {
continue;
}
ftdm_log(FTDM_LOG_INFO, "Unloading signaling interface %s\n", mod->name);
if (mod->sig_unload() != FTDM_SUCCESS) {
ftdm_log(FTDM_LOG_ERROR, "Error unloading signaling interface %s\n", mod->name);
continue;
}
ftdm_log(FTDM_LOG_INFO, "Unloaded signaling interface %s\n", mod->name);
}
/* Now go ahead with I/O interfaces */
for (i = hashtable_first(globals.module_hash); i; i = hashtable_next(i)) {
const void *key = NULL;
void *val = NULL;
ftdm_module_t *mod = NULL;
hashtable_this(i, &key, NULL, &val);
if (!key || !val) {
continue;
}
mod = (ftdm_module_t *) val;
if (!mod->io_unload) {
continue;
}
ftdm_log(FTDM_LOG_INFO, "Unloading I/O interface %s\n", mod->name);
if (mod->io_unload() != FTDM_SUCCESS) {
ftdm_log(FTDM_LOG_ERROR, "Error unloading I/O interface %s\n", mod->name);
continue;
}
ftdm_log(FTDM_LOG_INFO, "Unloaded I/O interface %s\n", mod->name);
}
/* Now unload the actual shared object/dll */
for (i = hashtable_first(globals.module_hash); i; i = hashtable_next(i)) {
ftdm_module_t *mod = NULL;
const void *key = NULL;
void *val = NULL;
hashtable_this(i, &key, NULL, &val);
if (!key || !val) {
continue;
}
mod = (ftdm_module_t *) val;
lib = mod->lib;
snprintf(modpath, sizeof(modpath), "%s", mod->path);
ftdm_log(FTDM_LOG_INFO, "Unloading module %s\n", modpath);
ftdm_dso_destroy(&lib);
ftdm_log(FTDM_LOG_INFO, "Unloaded module %s\n", modpath);
} }
return FTDM_SUCCESS; return FTDM_SUCCESS;
@ -3506,8 +3558,12 @@ FT_DECLARE(ftdm_status_t) ftdm_global_destroy(void)
time_end(); time_end();
globals.running = 0; globals.running = 0;
globals.span_index = 0;
ftdm_span_close_all(); ftdm_span_close_all();
ftdm_sleep(1000);
ftdm_unload_modules();
ftdm_mutex_lock(globals.span_mutex); ftdm_mutex_lock(globals.span_mutex);
for (sp = globals.spans; sp;) { for (sp = globals.spans; sp;) {
@ -3529,10 +3585,6 @@ FT_DECLARE(ftdm_status_t) ftdm_global_destroy(void)
globals.spans = NULL; globals.spans = NULL;
ftdm_mutex_unlock(globals.span_mutex); ftdm_mutex_unlock(globals.span_mutex);
globals.span_index = 0;
ftdm_unload_modules();
ftdm_mutex_lock(globals.mutex); ftdm_mutex_lock(globals.mutex);
hashtable_destroy(globals.interface_hash); hashtable_destroy(globals.interface_hash);
hashtable_destroy(globals.module_hash); hashtable_destroy(globals.module_hash);

View File

@ -38,11 +38,12 @@ static ftdm_status_t ftdm_std_queue_create(ftdm_queue_t **outqueue, ftdm_size_t
static ftdm_status_t ftdm_std_queue_enqueue(ftdm_queue_t *queue, void *obj); static ftdm_status_t ftdm_std_queue_enqueue(ftdm_queue_t *queue, void *obj);
static void *ftdm_std_queue_dequeue(ftdm_queue_t *queue); static void *ftdm_std_queue_dequeue(ftdm_queue_t *queue);
static ftdm_status_t ftdm_std_queue_wait(ftdm_queue_t *queue, int ms); static ftdm_status_t ftdm_std_queue_wait(ftdm_queue_t *queue, int ms);
static ftdm_status_t ftdm_std_queue_get_interrupt(ftdm_queue_t *queue, ftdm_interrupt_t **interrupt);
static ftdm_status_t ftdm_std_queue_destroy(ftdm_queue_t **inqueue); static ftdm_status_t ftdm_std_queue_destroy(ftdm_queue_t **inqueue);
struct ftdm_queue { struct ftdm_queue {
ftdm_mutex_t *mutex; ftdm_mutex_t *mutex;
ftdm_condition_t *condition; ftdm_interrupt_t *interrupt;
ftdm_size_t capacity; ftdm_size_t capacity;
ftdm_size_t size; ftdm_size_t size;
unsigned rindex; unsigned rindex;
@ -56,6 +57,7 @@ FT_DECLARE_DATA ftdm_queue_handler_t g_ftdm_queue_handler =
/*.enqueue = */ ftdm_std_queue_enqueue, /*.enqueue = */ ftdm_std_queue_enqueue,
/*.dequeue = */ ftdm_std_queue_dequeue, /*.dequeue = */ ftdm_std_queue_dequeue,
/*.wait = */ ftdm_std_queue_wait, /*.wait = */ ftdm_std_queue_wait,
/*.get_interrupt = */ ftdm_std_queue_get_interrupt,
/*.destroy = */ ftdm_std_queue_destroy /*.destroy = */ ftdm_std_queue_destroy
}; };
@ -66,6 +68,7 @@ FT_DECLARE(ftdm_status_t) ftdm_global_set_queue_handler(ftdm_queue_handler_t *ha
!handler->enqueue || !handler->enqueue ||
!handler->dequeue || !handler->dequeue ||
!handler->wait || !handler->wait ||
!handler->get_interrupt ||
!handler->destroy) { !handler->destroy) {
return FTDM_FAIL; return FTDM_FAIL;
} }
@ -95,7 +98,7 @@ static ftdm_status_t ftdm_std_queue_create(ftdm_queue_t **outqueue, ftdm_size_t
goto failed; goto failed;
} }
if (ftdm_condition_create(&queue->condition, queue->mutex) != FTDM_SUCCESS) { if (ftdm_interrupt_create(&queue->interrupt, FTDM_INVALID_SOCKET) != FTDM_SUCCESS) {
goto failed; goto failed;
} }
@ -104,8 +107,8 @@ static ftdm_status_t ftdm_std_queue_create(ftdm_queue_t **outqueue, ftdm_size_t
failed: failed:
if (queue) { if (queue) {
if (queue->condition) { if (queue->interrupt) {
ftdm_condition_destroy(&queue->condition); ftdm_interrupt_destroy(&queue->interrupt);
} }
if (queue->mutex) { if (queue->mutex) {
ftdm_mutex_destroy(&queue->mutex); ftdm_mutex_destroy(&queue->mutex);
@ -139,7 +142,7 @@ static ftdm_status_t ftdm_std_queue_enqueue(ftdm_queue_t *queue, void *obj)
status = FTDM_SUCCESS; status = FTDM_SUCCESS;
/* wake up queue reader */ /* wake up queue reader */
ftdm_condition_signal(queue->condition); ftdm_interrupt_signal(queue->interrupt);
done: done:
@ -188,7 +191,7 @@ static ftdm_status_t ftdm_std_queue_wait(ftdm_queue_t *queue, int ms)
} }
/* no elements on the queue, wait for someone to write an element */ /* no elements on the queue, wait for someone to write an element */
ret = ftdm_condition_wait(queue->condition, ms); ret = ftdm_interrupt_wait(queue->interrupt, ms);
/* got an element or timeout, bail out */ /* got an element or timeout, bail out */
ftdm_mutex_unlock(queue->mutex); ftdm_mutex_unlock(queue->mutex);
@ -196,14 +199,22 @@ static ftdm_status_t ftdm_std_queue_wait(ftdm_queue_t *queue, int ms)
return ret; return ret;
} }
static ftdm_status_t ftdm_std_queue_get_interrupt(ftdm_queue_t *queue, ftdm_interrupt_t **interrupt)
{
ftdm_assert_return(queue != NULL, FTDM_FAIL, "Queue is null!\n");
ftdm_assert_return(interrupt != NULL, FTDM_FAIL, "Queue is null!\n");
*interrupt = queue->interrupt;
return FTDM_SUCCESS;
}
static ftdm_status_t ftdm_std_queue_destroy(ftdm_queue_t **inqueue) static ftdm_status_t ftdm_std_queue_destroy(ftdm_queue_t **inqueue)
{ {
ftdm_queue_t *queue = NULL; ftdm_queue_t *queue = NULL;
ftdm_assert_return(inqueue != NULL, FTDM_FAIL, "Queue is null!"); ftdm_assert_return(inqueue != NULL, FTDM_FAIL, "Queue is null!\n");
ftdm_assert_return(*inqueue != NULL, FTDM_FAIL, "Queue is null!"); ftdm_assert_return(*inqueue != NULL, FTDM_FAIL, "Queue is null!\n");
queue = *inqueue; queue = *inqueue;
ftdm_condition_destroy(&queue->condition); ftdm_interrupt_destroy(&queue->interrupt);
ftdm_mutex_destroy(&queue->mutex); ftdm_mutex_destroy(&queue->mutex);
ftdm_safe_free(queue->elements); ftdm_safe_free(queue->elements);
ftdm_safe_free(queue); ftdm_safe_free(queue);

View File

@ -40,6 +40,7 @@ struct ftdm_mutex {
#else #else
#include <pthread.h> #include <pthread.h>
#include <poll.h>
#define FTDM_THREAD_CALLING_CONVENTION #define FTDM_THREAD_CALLING_CONVENTION
@ -49,16 +50,18 @@ struct ftdm_mutex {
#endif #endif
struct ftdm_condition { struct ftdm_interrupt {
ftdm_socket_t device;
#ifdef WIN32 #ifdef WIN32
HANDLE condition; /* for generic interruption */
HANDLE event;
#else #else
pthread_cond_t condition; /* for generic interruption */
int readfd;
int writefd;
#endif #endif
ftdm_mutex_t *mutex;
}; };
struct ftdm_thread { struct ftdm_thread {
#ifdef WIN32 #ifdef WIN32
void *handle; void *handle;
@ -238,123 +241,207 @@ FT_DECLARE(ftdm_status_t) _ftdm_mutex_unlock(ftdm_mutex_t *mutex)
} }
FT_DECLARE(ftdm_status_t) ftdm_condition_create(ftdm_condition_t **incondition, ftdm_mutex_t *mutex) FT_DECLARE(ftdm_status_t) ftdm_interrupt_create(ftdm_interrupt_t **ininterrupt, ftdm_socket_t device)
{ {
ftdm_condition_t *condition = NULL; ftdm_interrupt_t *interrupt = NULL;
#ifndef WIN32
int fds[2];
#endif
ftdm_assert_return(incondition != NULL, FTDM_FAIL, "Condition double pointer is null!\n"); ftdm_assert_return(ininterrupt != NULL, FTDM_FAIL, "interrupt double pointer is null!\n");
ftdm_assert_return(mutex != NULL, FTDM_FAIL, "Mutex for condition must not be null!\n");
condition = ftdm_calloc(1, sizeof(*condition)); interrupt = ftdm_calloc(1, sizeof(*interrupt));
if (!condition) { if (!interrupt) {
ftdm_log(FTDM_LOG_ERROR, "Failed to allocate interrupt memory\n");
return FTDM_FAIL; return FTDM_FAIL;
} }
condition->mutex = mutex; interrupt->device = device;
#ifdef WIN32 #ifdef WIN32
condition->condition = CreateEvent(NULL, FALSE, FALSE, NULL); interrupt->interrupt = CreateEvent(NULL, FALSE, FALSE, NULL);
if (!condition->condition) { if (!interrupt->interrupt) {
ftdm_log(FTDM_LOG_ERROR, "Failed to allocate interrupt event\n");
goto failed; goto failed;
} }
#else #else
if (pthread_cond_init(&condition->condition, NULL)) { if (pipe(fds)) {
ftdm_log(FTDM_LOG_ERROR, "Failed to allocate interrupt pipe: %s\n", strerror(errno));
goto failed; goto failed;
} }
interrupt->readfd = fds[0];
interrupt->writefd = fds[1];
#endif #endif
*incondition = condition; *ininterrupt = interrupt;
return FTDM_SUCCESS; return FTDM_SUCCESS;
failed: failed:
if (condition) { if (interrupt) {
ftdm_safe_free(condition); #ifndef WIN32
if (interrupt->readfd) {
close(interrupt->readfd);
close(interrupt->writefd);
interrupt->readfd = -1;
interrupt->writefd = -1;
}
#endif
ftdm_safe_free(interrupt);
} }
return FTDM_FAIL; return FTDM_FAIL;
} }
#define ONE_BILLION 1000000000 #define ONE_BILLION 1000000000
FT_DECLARE(ftdm_status_t) ftdm_condition_wait(ftdm_condition_t *condition, int ms) FT_DECLARE(ftdm_status_t) ftdm_interrupt_wait(ftdm_interrupt_t *interrupt, int ms)
{ {
int num = 1;
#ifdef WIN32 #ifdef WIN32
DWORD res = 0; DWORD res = 0;
HANDLE ints[2];
#else
int res = 0;
struct pollfd ints[2];
char pipebuf[255];
#endif #endif
ftdm_assert_return(condition != NULL, FTDM_FAIL, "Condition is null!\n");
ftdm_assert_return(interrupt != NULL, FTDM_FAIL, "Condition is null!\n");
/* start implementation */
#ifdef WIN32 #ifdef WIN32
ftdm_mutex_unlock(condition->mutex); ints[0] = interrupt->event;
res = WaitForSingleObject(condition->condition, ms > 0 ? ms : INFINITE); if (interrupt->device != FTDM_INVALID_SOCKET) {
ftdm_mutex_lock(condition->mutex); num++;
ints[1] = interrupt->device;
}
res = WaitForMultipleObjects(num, &ints, FALSE, ms >= 0 ? ms : INFINITE);
switch (res) { switch (res) {
case WAIT_ABANDONED:
case WAIT_TIMEOUT: case WAIT_TIMEOUT:
return FTDM_TIMEOUT; return FTDM_TIMEOUT;
case WAIT_FAILED: case WAIT_FAILED:
case WAIT_ABANDONED: /* is it right to fail with abandoned? */
return FTDM_FAIL; return FTDM_FAIL;
case WAIT_OBJECT_0:
return FTDM_SUCCESS;
default: default:
ftdm_log(FTDM_LOG_ERROR, "Error waiting for freetdm condition event (WaitForSingleObject returned %d)\n", res); if (res >= (sizeof(ints)/sizeof(ints[0]))) {
return FTDM_FAIL; ftdm_log(FTDM_LOG_ERROR, "Error waiting for freetdm interrupt event (WaitForSingleObject returned %d)\n", res);
return FTDM_FAIL;
}
return FTDM_SUCCESS;
} }
#else #else
int res = 0; ints[0].fd = interrupt->readfd;
if (ms > 0) { ints[0].events = POLLIN;
struct timeval t; ints[0].revents = 0;
struct timespec waitms;
gettimeofday(&t, NULL);
waitms.tv_sec = t.tv_sec + ( ms / 1000 );
waitms.tv_nsec = 1000*(t.tv_usec + (1000 * ( ms % 1000 )));
if (waitms.tv_nsec >= ONE_BILLION) {
waitms.tv_sec++;
waitms.tv_nsec -= ONE_BILLION;
}
res = pthread_cond_timedwait(&condition->condition, &condition->mutex->mutex, &waitms);
} else {
res = pthread_cond_wait(&condition->condition, &condition->mutex->mutex);
}
if (res != 0) {
if (res == ETIMEDOUT) {
return FTDM_TIMEOUT;
}
ftdm_log(FTDM_LOG_CRIT,"pthread_cond_timedwait failed (%d)\n", res); if (interrupt->device != FTDM_INVALID_SOCKET) {
num++;
ints[1].fd = interrupt->device;
ints[1].events = POLLIN;
ints[1].revents = 0;
}
res = poll(ints, num, ms);
if (res == -1) {
ftdm_log(FTDM_LOG_CRIT, "interrupt poll failed (%s)\n", strerror(errno));
return FTDM_FAIL; return FTDM_FAIL;
} }
if (res == 0) {
return FTDM_TIMEOUT;
}
if (ints[0].revents & POLLIN) {
res = read(ints[0].fd, pipebuf, sizeof(pipebuf));
if (res == -1) {
ftdm_log(FTDM_LOG_CRIT, "reading interrupt descriptor failed (%s)\n", strerror(errno));
}
}
return FTDM_SUCCESS; return FTDM_SUCCESS;
#endif #endif
} }
FT_DECLARE(ftdm_status_t) ftdm_condition_signal(ftdm_condition_t *condition) FT_DECLARE(ftdm_status_t) ftdm_interrupt_signal(ftdm_interrupt_t *interrupt)
{ {
ftdm_assert_return(condition != NULL, FTDM_FAIL, "Condition is null!\n"); ftdm_assert_return(interrupt != NULL, FTDM_FAIL, "Interrupt is null!\n");
#ifdef WIN32 #ifdef WIN32
if (!SetEvent(condition->condition)) { if (!SetEvent(interrupt->interrupt)) {
ftdm_log(FTDM_LOG_ERROR, "Failed to signal interrupt\n");
return FTDM_FAIL; return FTDM_FAIL;
} }
#else #else
int err; int err;
if ((err = pthread_cond_signal(&condition->condition))) { if ((err = write(interrupt->writefd, "w", 1)) != 1) {
ftdm_log(FTDM_LOG_ERROR, "Failed to signal condition %d:%s\n", err, strerror(err)); ftdm_log(FTDM_LOG_ERROR, "Failed to signal interrupt: %s\n", errno, strerror(errno));
return FTDM_FAIL; return FTDM_FAIL;
} }
#endif #endif
return FTDM_SUCCESS; return FTDM_SUCCESS;
} }
FT_DECLARE(ftdm_status_t) ftdm_condition_destroy(ftdm_condition_t **incondition) FT_DECLARE(ftdm_status_t) ftdm_interrupt_destroy(ftdm_interrupt_t **ininterrupt)
{ {
ftdm_condition_t *condition = NULL; ftdm_interrupt_t *interrupt = NULL;
ftdm_assert_return(incondition != NULL, FTDM_FAIL, "Condition null when destroying!\n"); ftdm_assert_return(ininterrupt != NULL, FTDM_FAIL, "Interrupt null when destroying!\n");
condition = *incondition; interrupt = *ininterrupt;
#ifdef WIN32 #ifdef WIN32
CloseHandle(condition->condition); CloseHandle(interrupt->interrupt);
#else #else
if (pthread_cond_destroy(&condition->condition)) { close(interrupt->readfd);
close(interrupt->writefd);
interrupt->readfd = -1;
interrupt->writefd = -1;
#endif
ftdm_safe_free(interrupt);
*ininterrupt = NULL;
return FTDM_SUCCESS;
}
FT_DECLARE(ftdm_status_t) ftdm_interrupt_multiple_wait(ftdm_interrupt_t *interrupts[], ftdm_size_t size, int ms)
{
#ifndef WIN32
int i;
int res = 0;
int numdevices = 0;
char pipebuf[255];
struct pollfd ints[size*2];
memset(&ints, 0, sizeof(ints));
for (i = 0; i < size; i++) {
ints[i].events = POLLIN;
ints[i].revents = 0;
ints[i].fd = interrupts[i]->readfd;
if (interrupts[i]->device != FTDM_INVALID_SOCKET) {
ints[i+numdevices].events = POLLIN;
ints[i+numdevices].revents = 0;
ints[i+numdevices].fd = interrupts[i]->device;
numdevices++;
}
}
res = poll(ints, size + numdevices, ms);
if (res == -1) {
ftdm_log(FTDM_LOG_CRIT, "interrupt poll failed (%s)\n", strerror(errno));
return FTDM_FAIL; return FTDM_FAIL;
} }
if (res == 0) {
return FTDM_TIMEOUT;
}
for (i = size; i < ftdm_array_len(ints); i++) {
if (ints[i].revents & POLLIN) {
res = read(ints[0].fd, pipebuf, sizeof(pipebuf));
if (res == -1) {
ftdm_log(FTDM_LOG_CRIT, "reading interrupt descriptor failed (%s)\n", strerror(errno));
}
}
}
#endif #endif
ftdm_safe_free(condition);
*incondition = NULL;
return FTDM_SUCCESS; return FTDM_SUCCESS;
} }

View File

@ -46,8 +46,6 @@ typedef enum {
typedef struct ftdm_sangoma_boost_data { typedef struct ftdm_sangoma_boost_data {
sangomabc_connection_t mcon; sangomabc_connection_t mcon;
sangomabc_connection_t pcon; sangomabc_connection_t pcon;
fd_set rfds;
fd_set efds;
int iteration; int iteration;
uint32_t flags; uint32_t flags;
boost_sigmod_interface_t *sigmod; boost_sigmod_interface_t *sigmod;

View File

@ -39,7 +39,7 @@
*/ */
/* NOTE: /* NOTE:
On WIN32 platform this code works with sigmod ONLY, don't try to make sense of any socket code for win32 On __WINDOWS__ platform this code works with sigmod ONLY, don't try to make sense of any socket code for win
I basically ifdef out everything that the compiler complained about I basically ifdef out everything that the compiler complained about
*/ */
@ -1016,11 +1016,8 @@ static void handle_heartbeat(sangomabc_connection_t *mcon, sangomabc_short_event
err = sangomabc_connection_writep(mcon, (sangomabc_event_t*)event); err = sangomabc_connection_writep(mcon, (sangomabc_event_t*)event);
if (err <= 0) { if (err <= 0) {
ftdm_log(FTDM_LOG_CRIT, "Failed to tx on ISUP socket [%s]: %s\n", strerror(errno)); ftdm_log(FTDM_LOG_CRIT, "Failed to tx on boost connection [%s]: %s\n", strerror(errno));
} }
mcon->hb_elapsed = 0;
return; return;
} }
@ -1050,7 +1047,6 @@ static void handle_restart(sangomabc_connection_t *mcon, ftdm_span_t *span, sang
ftdm_set_flag_locked(span, FTDM_SPAN_SUSPENDED); ftdm_set_flag_locked(span, FTDM_SPAN_SUSPENDED);
ftdm_set_flag(sangoma_boost_data, FTDM_SANGOMA_BOOST_RESTARTING); ftdm_set_flag(sangoma_boost_data, FTDM_SANGOMA_BOOST_RESTARTING);
mcon->hb_elapsed = 0;
} }
/** /**
@ -1452,6 +1448,7 @@ static __inline__ void init_outgoing_array(void)
*/ */
static __inline__ void check_state(ftdm_span_t *span) static __inline__ void check_state(ftdm_span_t *span)
{ {
ftdm_channel_t *ftdmchan = NULL;
ftdm_sangoma_boost_data_t *sangoma_boost_data = span->signal_data; ftdm_sangoma_boost_data_t *sangoma_boost_data = span->signal_data;
int susp = ftdm_test_flag(span, FTDM_SPAN_SUSPENDED); int susp = ftdm_test_flag(span, FTDM_SPAN_SUSPENDED);
@ -1462,17 +1459,23 @@ static __inline__ void check_state(ftdm_span_t *span)
if (ftdm_test_flag(span, FTDM_SPAN_STATE_CHANGE) || susp) { if (ftdm_test_flag(span, FTDM_SPAN_STATE_CHANGE) || susp) {
uint32_t j; uint32_t j;
ftdm_clear_flag_locked(span, FTDM_SPAN_STATE_CHANGE); ftdm_clear_flag_locked(span, FTDM_SPAN_STATE_CHANGE);
for(j = 1; j <= span->chan_count; j++) { if (susp) {
if (ftdm_test_flag((span->channels[j]), FTDM_CHANNEL_STATE_CHANGE) || susp) { for (j = 0; j <= span->chan_count; j++) {
ftdm_mutex_lock(span->channels[j]->mutex); ftdm_mutex_lock(span->channels[j]->mutex);
ftdm_clear_flag((span->channels[j]), FTDM_CHANNEL_STATE_CHANGE); ftdm_clear_flag((span->channels[j]), FTDM_CHANNEL_STATE_CHANGE);
if (susp && span->channels[j]->state != FTDM_CHANNEL_STATE_DOWN) { ftdm_channel_set_state(span->channels[j], FTDM_CHANNEL_STATE_RESTART, 0);
ftdm_channel_set_state(span->channels[j], FTDM_CHANNEL_STATE_RESTART, 0);
}
state_advance(span->channels[j]); state_advance(span->channels[j]);
ftdm_channel_complete_state(span->channels[j]); ftdm_channel_complete_state(span->channels[j]);
ftdm_mutex_unlock(span->channels[j]->mutex); ftdm_mutex_unlock(span->channels[j]->mutex);
} }
} else {
while ((ftdmchan = ftdm_queue_dequeue(span->pendingchans))) {
ftdm_mutex_lock(ftdmchan->mutex);
ftdm_clear_flag(ftdmchan, FTDM_CHANNEL_STATE_CHANGE);
state_advance(ftdmchan);
ftdm_channel_complete_state(ftdmchan);
ftdm_mutex_unlock(ftdmchan->mutex);
}
} }
} }
@ -1487,7 +1490,6 @@ static __inline__ void check_state(ftdm_span_t *span)
ftdm_clear_flag(sangoma_boost_data, FTDM_SANGOMA_BOOST_RESTARTING); ftdm_clear_flag(sangoma_boost_data, FTDM_SANGOMA_BOOST_RESTARTING);
ftdm_clear_flag_locked(span, FTDM_SPAN_SUSPENDED); ftdm_clear_flag_locked(span, FTDM_SPAN_SUSPENDED);
ftdm_clear_flag((&sangoma_boost_data->mcon), MSU_FLAG_DOWN); ftdm_clear_flag((&sangoma_boost_data->mcon), MSU_FLAG_DOWN);
sangoma_boost_data->mcon.hb_elapsed = 0;
init_outgoing_array(); init_outgoing_array();
} }
} }
@ -1596,6 +1598,18 @@ static ftdm_status_t ftdm_boost_connection_open(ftdm_span_t *span)
ftdm_log(FTDM_LOG_ERROR, "Error: Opening PCON Socket [%d] %s\n", sangoma_boost_data->pcon.socket, strerror(errno)); ftdm_log(FTDM_LOG_ERROR, "Error: Opening PCON Socket [%d] %s\n", sangoma_boost_data->pcon.socket, strerror(errno));
return FTDM_FAIL; return FTDM_FAIL;
} }
/* try to create the boost sockets interrupt objects */
if (ftdm_interrupt_create(&sangoma_boost_data->pcon.sock_interrupt, sangoma_boost_data->pcon.socket) != FTDM_SUCCESS) {
ftdm_log(FTDM_LOG_ERROR, "Span %s could not create its boost msock interrupt!\n", span->name);
return FTDM_FAIL;
}
if (ftdm_interrupt_create(&sangoma_boost_data->mcon.sock_interrupt, sangoma_boost_data->mcon.socket) != FTDM_SUCCESS) {
ftdm_log(FTDM_LOG_ERROR, "Span %s could not create its boost psock interrupt!\n", span->name);
return FTDM_FAIL;
}
return FTDM_SUCCESS; return FTDM_SUCCESS;
} }
@ -1603,49 +1617,34 @@ static ftdm_status_t ftdm_boost_connection_open(ftdm_span_t *span)
\brief wait for a boost event \brief wait for a boost event
\return -1 on error, 0 on timeout, 1 when there are events \return -1 on error, 0 on timeout, 1 when there are events
*/ */
static int ftdm_boost_wait_event(ftdm_span_t *span, int ms) static int ftdm_boost_wait_event(ftdm_span_t *span)
{ {
#ifndef WIN32 ftdm_status_t res;
struct timeval tv = { 0, ms * 1000 }; ftdm_interrupt_t *ints[3];
sangomabc_connection_t *mcon, *pcon; int numints;
int max, activity;
#endif
ftdm_sangoma_boost_data_t *sangoma_boost_data = span->signal_data; ftdm_sangoma_boost_data_t *sangoma_boost_data = span->signal_data;
ftdm_queue_get_interrupt(span->pendingchans, &ints[0]);
numints = 1;
/* if in queue mode wait for both the pendingchans queue and the boost msg queue */
if (sangoma_boost_data->sigmod) { if (sangoma_boost_data->sigmod) {
ftdm_status_t res; ftdm_queue_get_interrupt(sangoma_boost_data->boost_queue, &ints[1]);
res = ftdm_queue_wait(sangoma_boost_data->boost_queue, ms); numints = 2;
if (FTDM_TIMEOUT == res) { }
return 0; #ifndef __WINDOWS__
} else {
if (FTDM_SUCCESS != res) { /* socket mode ... */
return -1; ints[1] = sangoma_boost_data->mcon.sock_interrupt;
} ints[2] = sangoma_boost_data->pcon.sock_interrupt;
return 1; numints = 3;
sangoma_boost_data->iteration = 0;
} }
#ifndef WIN32
mcon = &sangoma_boost_data->mcon;
pcon = &sangoma_boost_data->pcon;
FD_ZERO(&sangoma_boost_data->rfds);
FD_ZERO(&sangoma_boost_data->efds);
FD_SET(mcon->socket, &sangoma_boost_data->rfds);
FD_SET(mcon->socket, &sangoma_boost_data->efds);
FD_SET(pcon->socket, &sangoma_boost_data->rfds);
FD_SET(pcon->socket, &sangoma_boost_data->efds);
sangoma_boost_data->iteration = 0;
max = ((pcon->socket > mcon->socket) ? pcon->socket : mcon->socket) + 1;
if ((activity = select(max, &sangoma_boost_data->rfds, NULL, &sangoma_boost_data->efds, &tv)) < 0) {
return -1;
}
if (FD_ISSET(pcon->socket, &sangoma_boost_data->efds) || FD_ISSET(mcon->socket, &sangoma_boost_data->efds)) {
return -1;
}
return 1;
#endif #endif
res = ftdm_interrupt_multiple_wait(ints, numints, -1);
if (FTDM_SUCCESS != res) {
ftdm_log(FTDM_LOG_CRIT, "Unexpected return value from interrupt waiting: %d\n", res);
return -1;
}
return 0; return 0;
} }
@ -1659,19 +1658,13 @@ static sangomabc_event_t *ftdm_boost_read_event(ftdm_span_t *span)
mcon = &sangoma_boost_data->mcon; mcon = &sangoma_boost_data->mcon;
pcon = &sangoma_boost_data->pcon; pcon = &sangoma_boost_data->pcon;
if (sangoma_boost_data->sigmod event = sangomabc_connection_readp(pcon, sangoma_boost_data->iteration);
#ifndef WIN32
|| FD_ISSET(pcon->socket, &sangoma_boost_data->rfds)
#endif
) {
event = sangomabc_connection_readp(pcon, sangoma_boost_data->iteration);
}
#ifndef WIN32
/* if there is no event and this is not a sigmod-driven span it's time to try the other connection for events */ /* if there is no event and this is not a sigmod-driven span it's time to try the other connection for events */
if (!event && !sangoma_boost_data->sigmod && FD_ISSET(mcon->socket, &sangoma_boost_data->rfds)) { if (!event && !sangoma_boost_data->sigmod) {
event = sangomabc_connection_readp(mcon, sangoma_boost_data->iteration); event = sangomabc_connection_read(mcon, sangoma_boost_data->iteration);
} }
#endif
return event; return event;
} }
@ -1684,7 +1677,6 @@ static void *ftdm_sangoma_boost_run(ftdm_thread_t *me, void *obj)
{ {
ftdm_span_t *span = (ftdm_span_t *) obj; ftdm_span_t *span = (ftdm_span_t *) obj;
sangomabc_connection_t *mcon, *pcon; sangomabc_connection_t *mcon, *pcon;
uint32_t ms = 10;
ftdm_sangoma_boost_data_t *sangoma_boost_data = span->signal_data; ftdm_sangoma_boost_data_t *sangoma_boost_data = span->signal_data;
mcon = &sangoma_boost_data->mcon; mcon = &sangoma_boost_data->mcon;
@ -1719,7 +1711,6 @@ static void *ftdm_sangoma_boost_run(ftdm_thread_t *me, void *obj)
while (ftdm_test_flag(sangoma_boost_data, FTDM_SANGOMA_BOOST_RUNNING)) { while (ftdm_test_flag(sangoma_boost_data, FTDM_SANGOMA_BOOST_RUNNING)) {
sangomabc_event_t *event = NULL; sangomabc_event_t *event = NULL;
int activity = 0;
if (!ftdm_running()) { if (!ftdm_running()) {
if (!sangoma_boost_data->sigmod) { if (!sangoma_boost_data->sigmod) {
@ -1735,27 +1726,17 @@ static void *ftdm_sangoma_boost_run(ftdm_thread_t *me, void *obj)
break; break;
} }
if ((activity = ftdm_boost_wait_event(span, ms)) < 0) { if (ftdm_boost_wait_event(span) < 0) {
ftdm_log(FTDM_LOG_ERROR, "ftdm_boost_wait_event failed\n"); ftdm_log(FTDM_LOG_ERROR, "ftdm_boost_wait_event failed\n");
goto error; goto error;
} }
if (activity) { while ((event = ftdm_boost_read_event(span))) {
while ((event = ftdm_boost_read_event(span))) { parse_sangoma_event(span, pcon, (sangomabc_short_event_t*)event);
parse_sangoma_event(span, pcon, (sangomabc_short_event_t*)event); sangoma_boost_data->iteration++;
sangoma_boost_data->iteration++;
}
} }
pcon->hb_elapsed += ms; check_state(span);
if (ftdm_test_flag(span, FTDM_SPAN_SUSPENDED) || ftdm_test_flag(mcon, MSU_FLAG_DOWN)) {
pcon->hb_elapsed = 0;
}
if (ftdm_running()) {
check_state(span);
}
} }
goto end; goto end;
@ -2235,6 +2216,7 @@ static FIO_CONFIGURE_SPAN_SIGNALING_FUNCTION(ftdm_sangoma_boost_configure_span)
sangoma_boost_data->sigmod = sigmod_iface; sangoma_boost_data->sigmod = sigmod_iface;
sigmod_iface->configure_span(span, ftdm_parameters); sigmod_iface->configure_span(span, ftdm_parameters);
} else { } else {
ftdm_log(FTDM_LOG_NOTICE, "Span %s will use boost socket mode\n", span->name);
ftdm_set_string(sangoma_boost_data->mcon.cfg.local_ip, local_ip); ftdm_set_string(sangoma_boost_data->mcon.cfg.local_ip, local_ip);
sangoma_boost_data->mcon.cfg.local_port = local_port; sangoma_boost_data->mcon.cfg.local_port = local_port;
ftdm_set_string(sangoma_boost_data->mcon.cfg.remote_ip, remote_ip); ftdm_set_string(sangoma_boost_data->mcon.cfg.remote_ip, remote_ip);

View File

@ -311,11 +311,7 @@ sangomabc_event_t *__sangomabc_connection_read(sangomabc_connection_t *mcon, int
ftdm_log(FTDM_LOG_CRIT, "Invalid Boost Version %i Expecting %i\n",mcon->event.version, SIGBOOST_VERSION); ftdm_log(FTDM_LOG_CRIT, "Invalid Boost Version %i Expecting %i\n",mcon->event.version, SIGBOOST_VERSION);
} }
/* Must check for < 0 cannot rely on bytes > MIN_SIZE_... compiler issue */ if ((bytes >= MIN_SIZE_CALLSTART_MSG) && boost_full_event(mcon->event.event_id)) {
if (bytes < 0) {
msg_ok=0;
} else if ((bytes >= MIN_SIZE_CALLSTART_MSG) && boost_full_event(mcon->event.event_id)) {
msg_ok=1; msg_ok=1;
} else if (bytes == sizeof(sangomabc_short_event_t)) { } else if (bytes == sizeof(sangomabc_short_event_t)) {

View File

@ -105,10 +105,10 @@ struct sangomabc_connection {
unsigned int txwindow; unsigned int txwindow;
unsigned int rxseq_reset; unsigned int rxseq_reset;
sangomabc_ip_cfg_t cfg; sangomabc_ip_cfg_t cfg;
uint32_t hb_elapsed;
/* boost signaling mod interface pointer (if not working in TCP mode) */ /* boost signaling mod interface pointer (if not working in TCP mode) */
boost_sigmod_interface_t *sigmod; boost_sigmod_interface_t *sigmod;
ftdm_queue_t *boost_queue; ftdm_queue_t *boost_queue;
ftdm_interrupt_t *sock_interrupt;
ftdm_span_t *span; ftdm_span_t *span;
}; };

View File

@ -381,6 +381,42 @@ struct ftdm_event {
void *data; void *data;
}; };
typedef struct ftdm_queue ftdm_queue_t;
typedef ftdm_status_t (*ftdm_queue_create_func_t)(ftdm_queue_t **queue, ftdm_size_t capacity);
typedef ftdm_status_t (*ftdm_queue_enqueue_func_t)(ftdm_queue_t *queue, void *obj);
typedef void *(*ftdm_queue_dequeue_func_t)(ftdm_queue_t *queue);
typedef ftdm_status_t (*ftdm_queue_wait_func_t)(ftdm_queue_t *queue, int ms);
typedef ftdm_status_t (*ftdm_queue_get_interrupt_func_t)(ftdm_queue_t *queue, ftdm_interrupt_t **interrupt);
typedef ftdm_status_t (*ftdm_queue_destroy_func_t)(ftdm_queue_t **queue);
typedef struct ftdm_queue_handler {
ftdm_queue_create_func_t create;
ftdm_queue_enqueue_func_t enqueue;
ftdm_queue_dequeue_func_t dequeue;
ftdm_queue_wait_func_t wait;
ftdm_queue_get_interrupt_func_t get_interrupt;
ftdm_queue_destroy_func_t destroy;
} ftdm_queue_handler_t;
FT_DECLARE_DATA extern ftdm_queue_handler_t g_ftdm_queue_handler;
/*! brief create a new queue */
#define ftdm_queue_create(queue, capacity) g_ftdm_queue_handler.create(queue, capacity)
/*! Enqueue an object */
#define ftdm_queue_enqueue(queue, obj) g_ftdm_queue_handler.enqueue(queue, obj)
/*! dequeue an object from the queue */
#define ftdm_queue_dequeue(queue) g_ftdm_queue_handler.dequeue(queue)
/*! wait ms milliseconds for a queue to have available objects, -1 to wait forever */
#define ftdm_queue_wait(queue, ms) g_ftdm_queue_handler.wait(queue, ms)
/*! get the internal interrupt object (to wait for elements to be added from the outside bypassing ftdm_queue_wait) */
#define ftdm_queue_get_interrupt(queue, ms) g_ftdm_queue_handler.get_interrupt(queue, ms)
/*! destroy the queue */
#define ftdm_queue_destroy(queue) g_ftdm_queue_handler.destroy(queue)
#define FTDM_TOKEN_STRLEN 128 #define FTDM_TOKEN_STRLEN 128
#define FTDM_MAX_TOKENS 10 #define FTDM_MAX_TOKENS 10
@ -621,6 +657,7 @@ struct ftdm_span {
int suggest_chan_id; int suggest_chan_id;
ftdm_state_map_t *state_map; ftdm_state_map_t *state_map;
ftdm_caller_data_t default_caller_data; ftdm_caller_data_t default_caller_data;
ftdm_queue_t *pendingchans;
struct ftdm_span *next; struct ftdm_span *next;
}; };
@ -673,36 +710,6 @@ struct ftdm_io_interface {
fio_api_t api; fio_api_t api;
}; };
typedef struct ftdm_queue ftdm_queue_t;
typedef ftdm_status_t (*ftdm_queue_create_func_t)(ftdm_queue_t **queue, ftdm_size_t capacity);
typedef ftdm_status_t (*ftdm_queue_enqueue_func_t)(ftdm_queue_t *queue, void *obj);
typedef void *(*ftdm_queue_dequeue_func_t)(ftdm_queue_t *queue);
typedef ftdm_status_t (*ftdm_queue_wait_func_t)(ftdm_queue_t *queue, int ms);
typedef ftdm_status_t (*ftdm_queue_destroy_func_t)(ftdm_queue_t **queue);
typedef struct ftdm_queue_handler {
ftdm_queue_create_func_t create;
ftdm_queue_enqueue_func_t enqueue;
ftdm_queue_dequeue_func_t dequeue;
ftdm_queue_wait_func_t wait;
ftdm_queue_destroy_func_t destroy;
} ftdm_queue_handler_t;
FT_DECLARE_DATA extern ftdm_queue_handler_t g_ftdm_queue_handler;
/*! brief create a new queue */
#define ftdm_queue_create(queue, capacity) g_ftdm_queue_handler.create(queue, capacity)
/*! Enqueue an object */
#define ftdm_queue_enqueue(queue, obj) g_ftdm_queue_handler.enqueue(queue, obj)
/*! dequeue an object from the queue */
#define ftdm_queue_dequeue(queue) g_ftdm_queue_handler.dequeue(queue)
/*! wait ms milliseconds for a queue to have available objects, -1 to wait forever */
#define ftdm_queue_wait(queue, ms) g_ftdm_queue_handler.wait(queue, ms)
/*! destroy the queue */
#define ftdm_queue_destroy(queue) g_ftdm_queue_handler.destroy(queue)
/*! \brief Override the default queue handler */ /*! \brief Override the default queue handler */
FT_DECLARE(ftdm_status_t) ftdm_global_set_queue_handler(ftdm_queue_handler_t *handler); FT_DECLARE(ftdm_status_t) ftdm_global_set_queue_handler(ftdm_queue_handler_t *handler);
@ -890,6 +897,8 @@ FIO_CODEC_FUNCTION(fio_alaw2ulaw);
*/ */
#define ftdm_socket_close(it) if (it > -1) { close(it); it = -1;} #define ftdm_socket_close(it) if (it > -1) { close(it); it = -1;}
#define ftdm_array_len(array) sizeof(array)/sizeof(array[0])
static __inline__ void ftdm_abort(void) static __inline__ void ftdm_abort(void)
{ {
#ifdef __cplusplus #ifdef __cplusplus

View File

@ -32,7 +32,7 @@ extern "C" {
#endif #endif
typedef struct ftdm_mutex ftdm_mutex_t; typedef struct ftdm_mutex ftdm_mutex_t;
typedef struct ftdm_thread ftdm_thread_t; typedef struct ftdm_thread ftdm_thread_t;
typedef struct ftdm_condition ftdm_condition_t; typedef struct ftdm_interrupt ftdm_interrupt_t;
typedef void *(*ftdm_thread_function_t) (ftdm_thread_t *, void *); typedef void *(*ftdm_thread_function_t) (ftdm_thread_t *, void *);
FT_DECLARE(ftdm_status_t) ftdm_thread_create_detached(ftdm_thread_function_t func, void *data); FT_DECLARE(ftdm_status_t) ftdm_thread_create_detached(ftdm_thread_function_t func, void *data);
@ -43,10 +43,11 @@ FT_DECLARE(ftdm_status_t) ftdm_mutex_destroy(ftdm_mutex_t **mutex);
FT_DECLARE(ftdm_status_t) _ftdm_mutex_lock(ftdm_mutex_t *mutex); FT_DECLARE(ftdm_status_t) _ftdm_mutex_lock(ftdm_mutex_t *mutex);
FT_DECLARE(ftdm_status_t) _ftdm_mutex_trylock(ftdm_mutex_t *mutex); FT_DECLARE(ftdm_status_t) _ftdm_mutex_trylock(ftdm_mutex_t *mutex);
FT_DECLARE(ftdm_status_t) _ftdm_mutex_unlock(ftdm_mutex_t *mutex); FT_DECLARE(ftdm_status_t) _ftdm_mutex_unlock(ftdm_mutex_t *mutex);
FT_DECLARE(ftdm_status_t) ftdm_condition_create(ftdm_condition_t **cond, ftdm_mutex_t *mutex); FT_DECLARE(ftdm_status_t) ftdm_interrupt_create(ftdm_interrupt_t **cond, ftdm_socket_t device);
FT_DECLARE(ftdm_status_t) ftdm_condition_destroy(ftdm_condition_t **cond); FT_DECLARE(ftdm_status_t) ftdm_interrupt_destroy(ftdm_interrupt_t **cond);
FT_DECLARE(ftdm_status_t) ftdm_condition_signal(ftdm_condition_t *cond); FT_DECLARE(ftdm_status_t) ftdm_interrupt_signal(ftdm_interrupt_t *cond);
FT_DECLARE(ftdm_status_t) ftdm_condition_wait(ftdm_condition_t *cond, int ms); FT_DECLARE(ftdm_status_t) ftdm_interrupt_wait(ftdm_interrupt_t *cond, int ms);
FT_DECLARE(ftdm_status_t) ftdm_interrupt_multiple_wait(ftdm_interrupt_t *interrupts[], ftdm_size_t size, int ms);
#ifdef __cplusplus #ifdef __cplusplus
} }

View File

@ -40,6 +40,7 @@
#define FTDM_TYPES_H #define FTDM_TYPES_H
#include "fsk.h" #include "fsk.h"
#define FTDM_INVALID_SOCKET -1
#ifdef WIN32 #ifdef WIN32
#include <windows.h> #include <windows.h>
typedef HANDLE ftdm_socket_t; typedef HANDLE ftdm_socket_t;