]> git.ipfire.org Git - thirdparty/freeswitch.git/commitdiff
added cpu monitor
authorMoises Silva <moy@sangoma.com>
Mon, 5 Apr 2010 21:49:43 +0000 (17:49 -0400)
committerMoises Silva <moy@sangoma.com>
Mon, 5 Apr 2010 21:49:43 +0000 (17:49 -0400)
libs/freetdm/Makefile.am
libs/freetdm/mod_freetdm/mod_freetdm.c
libs/freetdm/src/ftdm_cpu_monitor.c [new file with mode: 0644]
libs/freetdm/src/ftdm_io.c
libs/freetdm/src/ftmod/ftmod_sangoma_boost/ftmod_sangoma_boost.c
libs/freetdm/src/include/freetdm.h
libs/freetdm/src/include/ftdm_cpu_monitor.h [new file with mode: 0644]

index a90da6659e78ffa7e5874537dcdca60abfe8d00b..b322d65138621846091fdbc55db274692fc2c88b 100644 (file)
@@ -72,7 +72,8 @@ $(SRC)/libteletone_detect.c \
 $(SRC)/libteletone_generate.c \
 $(SRC)/ftdm_buffer.c \
 $(SRC)/ftdm_threadmutex.c \
-$(SRC)/ftdm_dso.c
+$(SRC)/ftdm_dso.c \
+$(SRC)/ftdm_cpu_monitor.c
 
 library_include_HEADERS = \
 $(SRC)/include/fsk.h \
@@ -90,7 +91,8 @@ $(SRC)/include/ftdm_buffer.h \
 $(SRC)/include/ftdm_config.h \
 $(SRC)/include/ftdm_threadmutex.h \
 $(SRC)/include/ftdm_dso.h \
-$(SRC)/include/ftdm_types.h 
+$(SRC)/include/ftdm_types.h \
+$(SRC)/include/ftdm_cpu_monitor.h 
 
 lib_LTLIBRARIES               = libfreetdm.la
 libfreetdm_la_CFLAGS   = $(AM_CFLAGS) $(MY_CFLAGS)
index 468bcf10de7bfa0208a1062e3102194c34278d8c..cf7ddad007fd5804af5bb2c6d1e41e533adb04da 100644 (file)
@@ -3142,6 +3142,8 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_freetdm_load)
        module_pool = pool;
 
        ftdm_global_set_logger(ftdm_logger);
+
+       ftdm_cpu_monitor_disable();
        
        if (ftdm_global_init() != FTDM_SUCCESS) {
                ftdm_log(FTDM_LOG_ERROR, "Error loading FreeTDM\n");
diff --git a/libs/freetdm/src/ftdm_cpu_monitor.c b/libs/freetdm/src/ftdm_cpu_monitor.c
new file mode 100644 (file)
index 0000000..eebf922
--- /dev/null
@@ -0,0 +1,271 @@
+/*
+ * Copyright (c) 2010, Sangoma Technologies
+ * Moises Silva <moy@sangoma.com>
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 
+ * * Neither the name of the original author; nor the names of any contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ * 
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER
+ * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Contributors:
+ * David Yat Sin <dyatsin@sangoma.com>
+ * 
+ */
+
+#ifdef WIN32
+#define _WIN32_WINNT 0x0501 // To make GetSystemTimes visible in windows.h
+#include <windows.h>
+#else /* LINUX */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <fcntl.h>
+#include <errno.h>
+#endif
+
+#include "freetdm.h"
+#include "ftdm_cpu_monitor.h"
+struct ftdm_cpu_monitor_stats
+{
+       /* bool, just used to retrieve the values for the first time and not calculate the percentage of idle time */
+       int valid_last_times;
+
+       /* last calculated percentage of idle time */
+       double last_percentage_of_idle_time;
+
+#ifdef __linux__
+       /* all of these are the Linux jiffies last retrieved count */
+       unsigned long long last_user_time;
+       unsigned long long last_system_time;
+       unsigned long long last_idle_time;
+
+       unsigned long long last_nice_time;
+       unsigned long long last_irq_time;
+       unsigned long long last_soft_irq_time;
+       unsigned long long last_io_wait_time;
+       unsigned long long last_steal_time;
+
+       /* /proc/stat file descriptor used to retrieve the counters */
+       int procfd;
+       int initd;
+#elif defined (WIN32)  || defined (WIN64)
+       __int64 i64LastUserTime;
+       __int64 i64LastKernelTime;
+       __int64 i64LastIdleTime;
+#else
+/* Unsupported */
+#endif
+};
+
+#ifdef __linux__
+static ftdm_status_t ftdm_cpu_read_stats(struct ftdm_cpu_monitor_stats *p,
+                                                                                       unsigned long long *user,
+                                                                                       unsigned long long *nice,
+                                                                                       unsigned long long *system,
+                                                                                       unsigned long long *idle,
+                                                                                       unsigned long long *iowait,
+                                                                                       unsigned long long *irq,
+                                                                                       unsigned long long *softirq,
+                                                                                       unsigned long long *steal)
+{
+// the output of proc should not change that often from one kernel to other
+// see fs/proc/proc_misc.c or fs/proc/stat.c in the Linux kernel for more details
+// also man 5 proc is useful
+#define CPU_ELEMENTS 8 // change this if you change the format string
+#define CPU_INFO_FORMAT "cpu  %Lu %Lu %Lu %Lu %Lu %Lu %Lu %Lu"
+       static const char procfile[] = "/proc/stat";
+       int rc = 0;
+       int myerrno = 0;
+       int elements = 0;
+       const char *cpustr = NULL;
+       char statbuff[1024];
+
+       if (!p->initd) {
+               p->procfd = open(procfile, O_RDONLY, 0);
+               if(p->procfd == -1) {
+                       ftdm_log(FTDM_LOG_ERROR, "Failed to open CPU statistics file %s: %s\n", procfile, strerror(myerrno));
+                       return FTDM_FAIL;
+               }
+               p->initd = 1;
+       } else {
+               lseek(p->procfd, 0L, SEEK_SET);
+       }
+
+       rc = read(p->procfd, statbuff, sizeof(statbuff) - 1);
+       if (rc <= 0) {
+               myerrno = errno;
+               ftdm_log(FTDM_LOG_ERROR, "Failed to read CPU statistics file %s: %s\n", procfile, strerror(myerrno));
+               return FTDM_FAIL;
+       }
+
+       cpustr = strstr(statbuff, "cpu ");
+       if (!cpustr) {
+               ftdm_log(FTDM_LOG_ERROR, "wrong format for Linux proc cpu statistics: missing cpu string\n");
+               return FTDM_FAIL;
+       }
+
+       elements = sscanf(cpustr, CPU_INFO_FORMAT, user, nice, system, idle, iowait, irq, softirq, steal);
+       if (elements != CPU_ELEMENTS) {
+               ftdm_log(FTDM_LOG_ERROR, "wrong format for Linux proc cpu statistics: expected %d elements, but just found %d\n", CPU_ELEMENTS, elements);
+               return FTDM_FAIL;
+       }
+       return FTDM_SUCCESS;
+}
+#endif
+
+#ifdef __linux__
+FT_DECLARE(ftdm_status_t) ftdm_cpu_get_system_idle_time (struct ftdm_cpu_monitor_stats *p, double *idle_percentage)
+{
+       unsigned long long user, nice, system, idle, iowait, irq, softirq, steal;
+       unsigned long long usertime, kerneltime, idletime, totaltime, halftime;
+
+       if (ftdm_cpu_read_stats(p, &user, &nice, &system, &idle, &iowait, &irq, &softirq, &steal)) {
+               ftdm_log(FTDM_LOG_ERROR, "Failed to retrieve Linux CPU statistics\n");
+               return FTDM_FAIL;
+       }
+
+       if (!p->valid_last_times) {
+               // we dont strictly need to save all of them but I feel code is more clear if we do
+               p->valid_last_times = 1;
+               p->last_user_time = user;
+               p->last_nice_time = nice;
+               p->last_system_time = system;
+               p->last_irq_time = irq;
+               p->last_soft_irq_time = softirq;
+               p->last_io_wait_time = iowait;
+               p->last_steal_time = steal;
+               p->last_idle_time = idle;
+               p->last_percentage_of_idle_time = 100.0;
+               *idle_percentage = p->last_percentage_of_idle_time;
+               return FTDM_SUCCESS;
+       }
+
+       usertime = (user - p->last_user_time) + (nice - p->last_nice_time);
+       kerneltime = (system - p->last_system_time) + (irq - p->last_irq_time) + (softirq - p->last_soft_irq_time);
+       kerneltime += (iowait - p->last_io_wait_time);
+       kerneltime += (steal - p->last_steal_time);
+       idletime = (idle - p->last_idle_time);
+
+       totaltime = usertime + kerneltime + idletime;
+       
+       if (totaltime <= 0) {
+               // this may happen if not enough time has elapsed and the jiffies counters are the same than the last time we checked
+               // jiffies depend on timer interrupts which depend on the number of HZ compile time setting of the kernel
+               // typical configs set HZ to 100 (that means, 100 jiffies updates per second, that is one each 10ms)
+               // avoid an arithmetic exception and return the same values
+               *idle_percentage = p->last_percentage_of_idle_time;
+               return FTDM_SUCCESS;
+       }
+
+       halftime = totaltime / 2UL;
+
+       p->last_percentage_of_idle_time = ((100 * idletime + halftime) / totaltime);
+       *idle_percentage = p->last_percentage_of_idle_time;
+
+       p->last_user_time = user;
+       p->last_nice_time = nice;
+       p->last_system_time = system;
+       p->last_irq_time = irq;
+       p->last_soft_irq_time = softirq;
+       p->last_io_wait_time = iowait;
+       p->last_steal_time = steal;
+       p->last_idle_time = idle;
+
+       return FTDM_SUCCESS;
+}
+
+#elif defined (WIN32) || defined (WIN64)
+FT_DECLARE(ftdm_status_t) ftdm_cpu_get_system_idle_time(struct ftdm_cpu_monitor_stats *p, double *idle_percentage)
+{
+       FILETIME idleTime;
+       FILETIME kernelTime;
+       FILETIME userTime;
+  
+       if (!::GetSystemTimes(&idleTime, &kernelTime, &userTime)) {
+               return false;
+       }
+  
+       __int64 i64UserTime = (__int64)userTime.dwLowDateTime | ((__int64)userTime.dwHighDateTime << 32);
+
+       __int64 i64KernelTime = (__int64)kernelTime.dwLowDateTime | ((__int64)kernelTime.dwHighDateTime << 32);
+
+       __int64 i64IdleTime = (__int64)idleTime.dwLowDateTime | ((__int64)idleTime.dwHighDateTime << 32);
+
+       if (p->valid_last_times) {
+               __int64 i64User = i64UserTime - p->i64LastUserTime;
+               __int64 i64Kernel = i64KernelTime - p->i64LastKernelTime;
+               __int64 i64Idle = i64IdleTime - p->i64LastIdleTime;
+               __int64 i64System = i64User + i64Kernel;
+               *idle_percentage = 100.0 * i64Idle / i64System;
+       } else {
+               *idle_percentage = 100.0;
+               p->valid_last_times = 1;
+       }
+
+       /* Remember current value for the next call */
+       p->i64LastUserTime = i64UserTime;
+       p->i64LastKernelTime = i64KernelTime;
+       p->i64LastIdleTime = i64IdleTime;
+
+       /* Success */
+       return FTDM_SUCCESS;
+}
+#else
+/* Unsupported */
+FT_DECLARE(ftdm_status_t) ftdm_cpu_get_system_idle_time(struct ftdm_cpu_monitor_stats *p, double *idle_percentage)
+{
+       return FTDM_FAIL;
+}
+#endif
+
+FT_DECLARE(struct ftdm_cpu_monitor_stats*) ftdm_new_cpu_monitor(void)
+{
+       return calloc(1, sizeof(struct ftdm_cpu_monitor_stats));
+}
+
+FT_DECLARE(void) ftdm_delete_cpu_monitor(struct ftdm_cpu_monitor_stats *p)
+{
+#ifdef __linux__
+       close(p->procfd);
+#endif
+       free(p);
+}
+
+
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4:
+ */
index 1b27f91130308c89a9e1eca3666041f63a6bd48d..65f5e7b706dd8ba0755202715524955b8e4cea61 100644 (file)
@@ -48,6 +48,7 @@
 #ifdef FTDM_PIKA_SUPPORT
 #include "ftdm_pika.h"
 #endif
+#include "ftdm_cpu_monitor.h"
 
 #define SPAN_PENDING_CHANS_QUEUE_SIZE 1000
 
@@ -80,6 +81,16 @@ FT_DECLARE(ftdm_time_t) ftdm_current_time_in_ms(void)
 #endif
 }
 
+typedef struct {
+       uint8_t         running;
+       uint8_t         alarm;
+       uint32_t        interval;
+       uint8_t         alarm_action_flags;
+       uint8_t         set_alarm_threshold;
+       uint8_t         reset_alarm_threshold;
+       ftdm_interrupt_t *interrupt;
+} cpu_monitor_t;
+
 static struct {
        ftdm_hash_t *interface_hash;
        ftdm_hash_t *module_hash;
@@ -93,8 +104,16 @@ static struct {
        uint32_t running;
        ftdm_span_t *spans;
        ftdm_group_t *groups;
+       cpu_monitor_t cpu_monitor;
 } globals;
 
+static uint8_t ftdm_cpu_monitor_disabled = 0;
+
+enum ftdm_enum_cpu_alarm_action_flags
+{
+       FTDM_CPU_ALARM_ACTION_WARN   = (1 << 0),
+       FTDM_CPU_ALARM_ACTION_REJECT = (1 << 1)
+};
 
 /* enum lookup funcs */
 FTDM_ENUM_NAMES(TONEMAP_NAMES, TONEMAP_STRINGS)
@@ -1470,6 +1489,14 @@ FT_DECLARE(ftdm_status_t) ftdm_channel_open_chan(ftdm_channel_t *ftdmchan)
                snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "%s", "Channel is alarmed\n");
                return FTDM_FAIL;
        }
+
+       if (globals.cpu_monitor.alarm && 
+           globals.cpu_monitor.alarm_action_flags & FTDM_CPU_ALARM_ACTION_REJECT) {
+               snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "%s", "CPU usage alarm is on - refusing to open channel\n");
+               ftdm_log(FTDM_LOG_WARNING, "CPU usage alarm is on - refusing to open channel\n");
+               ftdmchan->caller_data.hangup_cause = FTDM_CAUSE_SWITCH_CONGESTION;
+               return FTDM_FAIL;
+       }
        
        if (!ftdm_test_flag(ftdmchan, FTDM_CHANNEL_READY) || (status = ftdm_mutex_trylock(ftdmchan->mutex)) != FTDM_SUCCESS) {
                snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "Channel is not ready or is in use %d %d", ftdm_test_flag(ftdmchan, FTDM_CHANNEL_READY), status);
@@ -2988,6 +3015,44 @@ static ftdm_status_t load_config(void)
                        } else {
                                ftdm_log(FTDM_LOG_ERROR, "unknown span variable '%s'\n", var);
                        }
+               } else if (!strncasecmp(cfg.category, "general", 7)) {
+                       if (!strncasecmp(var, "cpu_monitoring_interval", sizeof("cpu_monitoring_interval")-1)) {
+                               if (atoi(val) > 0) {
+                                       globals.cpu_monitor.interval = atoi(val);
+                               } else {
+                                       ftdm_log(FTDM_LOG_ERROR, "Invalid cpu monitoring interval %s\n", val);
+                               }
+                       } else if (!strncasecmp(var, "cpu_set_alarm_threshold", sizeof("cpu_set_alarm_threshold")-1)) {
+                               if (atoi(val) > 0 && atoi(val) < 100) {
+                                       globals.cpu_monitor.set_alarm_threshold = atoi(val);
+                               } else {
+                                       ftdm_log(FTDM_LOG_ERROR, "Invalid cpu alarm set threshold %s\n", val);
+                               }
+                       } else if (!strncasecmp(var, "cpu_reset_alarm_threshold", sizeof("cpu_reset_alarm_threshold")-1)) {
+                               if (atoi(val) > 0 && atoi(val) < 100) {
+                                       globals.cpu_monitor.reset_alarm_threshold = atoi(val);
+                                       if (globals.cpu_monitor.reset_alarm_threshold > globals.cpu_monitor.set_alarm_threshold) {
+                                               globals.cpu_monitor.reset_alarm_threshold = globals.cpu_monitor.set_alarm_threshold - 10;
+                                               ftdm_log(FTDM_LOG_ERROR, "Cpu alarm reset threshold must be lower than set threshold"
+                                                               ", setting threshold to %d\n", globals.cpu_monitor.reset_alarm_threshold);
+                                       }
+                               } else {
+                                       ftdm_log(FTDM_LOG_ERROR, "Invalid cpu alarm reset threshold %s\n", val);
+                               }
+                       } else if (!strncasecmp(var, "cpu_alarm_action", sizeof("cpu_alarm_action")-1)) {
+                               char* p = val;
+                               do {
+                                       if (!strncasecmp(p, "reject", sizeof("reject")-1)) {
+                                               globals.cpu_monitor.alarm_action_flags |= FTDM_CPU_ALARM_ACTION_REJECT;
+                                       } else if (!strncasecmp(p, "warn", sizeof("warn")-1)) {
+                                               globals.cpu_monitor.alarm_action_flags |= FTDM_CPU_ALARM_ACTION_WARN;
+                                       }
+                                       p = strchr(p, ',');
+                                       if (p) {
+                                               while(*p++) if (*p != 0x20) break;
+                                       }
+                               } while (p);
+                       }
                } else {
                        ftdm_log(FTDM_LOG_ERROR, "unknown param [%s] '%s' / '%s'\n", cfg.category, var, val);
                }
@@ -3516,6 +3581,71 @@ FT_DECLARE(ftdm_status_t) ftdm_span_send_signal(ftdm_span_t *span, ftdm_sigmsg_t
        return status;
 }
 
+static void *ftdm_cpu_monitor_run(ftdm_thread_t *me, void *obj)
+{
+       cpu_monitor_t *monitor = (cpu_monitor_t *)obj;
+       struct ftdm_cpu_monitor_stats *cpu_stats = ftdm_new_cpu_monitor();
+       if (!cpu_stats) {
+               return NULL;
+       }
+       monitor->running = 1;
+
+       while(ftdm_running()) {
+               double time;
+               if (ftdm_cpu_get_system_idle_time(cpu_stats, &time)) {
+                       break;
+               }
+
+               if (monitor->alarm) {
+                       if ((int)time >= (100 - monitor->set_alarm_threshold)) {
+                               ftdm_log(FTDM_LOG_DEBUG, "CPU alarm OFF (idle:%d)\n", (int) time);
+                               monitor->alarm = 0;
+                       }
+                       if (monitor->alarm_action_flags & FTDM_CPU_ALARM_ACTION_WARN) {
+                       ftdm_log(FTDM_LOG_WARNING, "CPU alarm is ON (cpu usage:%d)\n", (int) (100-time));
+                       }
+               } else {
+                       if ((int)time <= (100-monitor->reset_alarm_threshold)) {
+                               ftdm_log(FTDM_LOG_DEBUG, "CPU alarm ON (idle:%d)\n", (int) time);
+                               monitor->alarm = 1;
+                       }
+               }
+               ftdm_interrupt_wait(monitor->interrupt, monitor->interval);
+       }
+
+       ftdm_delete_cpu_monitor(cpu_stats);
+       monitor->running = 0;
+       return NULL;
+}
+
+static ftdm_status_t ftdm_cpu_monitor_start(cpu_monitor_t* monitor)
+{
+       if (ftdm_interrupt_create(&monitor->interrupt, FTDM_INVALID_SOCKET) != FTDM_SUCCESS) {
+               ftdm_log(FTDM_LOG_CRIT, "Failed to create CPU monitor interrupt\n");
+               return FTDM_FAIL;
+       }
+
+       if (ftdm_thread_create_detached(ftdm_cpu_monitor_run, monitor) != FTDM_SUCCESS) {
+               ftdm_log(FTDM_LOG_CRIT, "Failed to create cpu monitor thread!!\n");
+               return FTDM_FAIL;
+       }
+       return FTDM_SUCCESS;
+}
+
+static void ftdm_cpu_monitor_stop(cpu_monitor_t* monitor)
+{
+       ftdm_interrupt_signal(monitor->interrupt);
+       while(monitor->running) {
+               ftdm_sleep(10);
+       }
+}
+
+FT_DECLARE(void) ftdm_cpu_monitor_disable(void)
+{
+       ftdm_cpu_monitor_disabled = 1;
+}
+
+
 FT_DECLARE(ftdm_status_t) ftdm_global_init(void)
 {
        memset(&globals, 0, sizeof(globals));
@@ -3538,14 +3668,34 @@ FT_DECLARE(ftdm_status_t) ftdm_global_init(void)
 
 FT_DECLARE(ftdm_status_t) ftdm_global_configuration(void)
 {
-       int modcount = ftdm_load_modules();
+       int modcount = 0;
+
+       if (!globals.running) {
+               return FTDM_FAIL;
+       }
+       
+       modcount = ftdm_load_modules();
+
        ftdm_log(FTDM_LOG_NOTICE, "Modules configured: %d \n", modcount);
 
+       globals.cpu_monitor.interval = 1000;
+       globals.cpu_monitor.alarm_action_flags = FTDM_CPU_ALARM_ACTION_WARN | FTDM_CPU_ALARM_ACTION_REJECT;
+       globals.cpu_monitor.set_alarm_threshold = 80;
+       globals.cpu_monitor.reset_alarm_threshold = 70;
+
        if (load_config() != FTDM_SUCCESS) {
                globals.running = 0;
                ftdm_log(FTDM_LOG_ERROR, "FreeTDM global configuration failed!\n");
                return FTDM_FAIL;
        }
+
+       if (!ftdm_cpu_monitor_disabled) {
+               if (ftdm_cpu_monitor_start(&globals.cpu_monitor) != FTDM_SUCCESS) {
+                       return FTDM_FAIL;
+               }
+       }
+
+
        return FTDM_SUCCESS;
 }
 
@@ -3563,6 +3713,8 @@ FT_DECLARE(ftdm_status_t) ftdm_global_destroy(void)
 
        globals.running = 0;    
 
+       ftdm_cpu_monitor_stop(&globals.cpu_monitor);
+
        globals.span_index = 0;
 
        ftdm_span_close_all();
@@ -3596,6 +3748,7 @@ FT_DECLARE(ftdm_status_t) ftdm_global_destroy(void)
        ftdm_mutex_unlock(globals.mutex);
        ftdm_mutex_destroy(&globals.mutex);
        ftdm_mutex_destroy(&globals.span_mutex);
+       ftdm_interrupt_destroy(&globals.cpu_monitor.interrupt);
 
        memset(&globals, 0, sizeof(globals));
        return FTDM_SUCCESS;
index c2ca3db7c4e344721d3ceec790392b903068656e..baaa3018189c991bbe7ab6edd001e2c5c68b15c8 100644 (file)
@@ -880,8 +880,8 @@ static __inline__ void advance_chan_states(ftdm_channel_t *ftdmchan);
  */
 static void handle_call_start(ftdm_span_t *span, sangomabc_connection_t *mcon, sangomabc_event_t *event)
 {
-       ftdm_channel_t *ftdmchan;
-
+       ftdm_channel_t *ftdmchan = NULL;
+       int hangup_cause = FTDM_CAUSE_CALL_REJECTED;
        if (!(ftdmchan = find_ftdmchan(span, (sangomabc_short_event_t*)event, 0))) {
                if ((ftdmchan = find_ftdmchan(span, (sangomabc_short_event_t*)event, 1))) {
                        int r;
@@ -896,7 +896,7 @@ static void handle_call_start(ftdm_span_t *span, sangomabc_connection_t *mcon, s
 
                        }
                        ftdm_set_sflag(ftdmchan, SFLAG_SENT_FINAL_MSG);
-                       ftdmchan=NULL;
+                       ftdmchan = NULL;
                }
                ftdm_log(FTDM_LOG_CRIT, "START CANT FIND CHAN %d:%d\n", event->span+1,event->chan+1);
                goto error;
@@ -953,12 +953,13 @@ static void handle_call_start(ftdm_span_t *span, sangomabc_connection_t *mcon, s
        return;
 
  error:
+       hangup_cause = ftdmchan ? ftdmchan->caller_data.hangup_cause : FTDM_CAUSE_REQUESTED_CHAN_UNAVAIL;
        sangomabc_exec_command(mcon,
                                                   event->span,
                                                   event->chan,
                                                   0,
                                                   SIGBOOST_EVENT_CALL_START_NACK,
-                                                  0, 0);
+                                                  hangup_cause, 0);
                
 }
 
index 04c30abc67a28dc603606e215fff48391eec9f1d..0b8b43dbf8f7947c07d4fbdd24c950873ed3587a 100644 (file)
@@ -824,6 +824,7 @@ FT_DECLARE(ftdm_status_t) ftdm_span_find_by_name(const char *name, ftdm_span_t *
 FT_DECLARE(char *) ftdm_api_execute(const char *type, const char *cmd);
 FT_DECLARE(int) ftdm_vasprintf(char **ret, const char *fmt, va_list ap);
 FT_DECLARE(ftdm_status_t) ftdm_channel_set_caller_data(ftdm_channel_t *ftdmchan, ftdm_caller_data_t *caller_data);
+FT_DECLARE(void) ftdm_cpu_monitor_disable(void);
 
 FIO_CODEC_FUNCTION(fio_slin2ulaw);
 FIO_CODEC_FUNCTION(fio_ulaw2slin);
diff --git a/libs/freetdm/src/include/ftdm_cpu_monitor.h b/libs/freetdm/src/include/ftdm_cpu_monitor.h
new file mode 100644 (file)
index 0000000..5d6bfb7
--- /dev/null
@@ -0,0 +1,75 @@
+/* 
+ * Copyright (c) 2010, Sangoma Technologies
+ * Moises Silva <moy@sangoma.com>
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 
+ * * Neither the name of the original author; nor the names of any contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ * 
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER
+ * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ * 
+ * 
+ * Contributors:
+ * David Yat Sin <dyatsin@sangoma.com>
+ * 
+ */
+
+/*! \brief opaque cpu stats structure */
+struct ftdm_cpu_monitor_stats;
+
+/*! 
+ * \brief create a new cpu monitor
+ * \return profile timer structure previously created with new_profile_timer, NULL on error
+ */
+FT_DECLARE(struct ftdm_cpu_monitor_stats*) ftdm_new_cpu_monitor(void);
+
+/*! 
+ * \brief Deletes cpu_monitor
+ */
+FT_DECLARE(void) ftdm_delete_cpu_monitor(struct ftdm_cpu_monitor_stats *p);
+
+/*! 
+ * \brief provides the percentage of idle system time
+ * \param p cpu_stats structure previously created with ftdm_new_cpu_monitor
+ * \param pointer to store the percentage of idle time
+ * \return -1 on error 0 for success
+ */
+FT_DECLARE(ftdm_status_t) ftdm_cpu_get_system_idle_time (struct ftdm_cpu_monitor_stats *p, double *idle_percentage);
+
+
+
+
+
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4:
+ */