<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head><meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>[Freeswitch-trunk][17216] </title>
</head>
<body>
<style type="text/css"><!--
#msg dl.meta { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; }
#msg dl.meta dt { float: left; width: 6em; font-weight: bold; }
#msg dt:after { content:':';}
#msg dl, #msg dt, #msg ul, #msg li, #header, #footer, #logmsg { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; }
#msg dl a { font-weight: bold}
#msg dl a:link { color:#fc3; }
#msg dl a:active { color:#ff0; }
#msg dl a:visited { color:#cc6; }
h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: bold; }
#msg pre { overflow: auto; background: #ffc; border: 1px #fa0 solid; padding: 6px; }
#logmsg { background: #ffc; border: 1px #fa0 solid; padding: 1em 1em 0 1em; }
#logmsg p, #logmsg pre, #logmsg blockquote { margin: 0 0 1em 0; }
#logmsg p, #logmsg li, #logmsg dt, #logmsg dd { line-height: 14pt; }
#logmsg h1, #logmsg h2, #logmsg h3, #logmsg h4, #logmsg h5, #logmsg h6 { margin: .5em 0; }
#logmsg h1:first-child, #logmsg h2:first-child, #logmsg h3:first-child, #logmsg h4:first-child, #logmsg h5:first-child, #logmsg h6:first-child { margin-top: 0; }
#logmsg ul, #logmsg ol { padding: 0; list-style-position: inside; margin: 0 0 0 1em; }
#logmsg ul { text-indent: -1em; padding-left: 1em; }#logmsg ol { text-indent: -1.5em; padding-left: 1.5em; }
#logmsg > ul, #logmsg > ol { margin: 0 0 1em 0; }
#logmsg pre { background: #eee; padding: 1em; }
#logmsg blockquote { border: 1px solid #fa0; border-left-width: 10px; padding: 1em 1em 0 1em; background: white;}
#logmsg dl { margin: 0; }
#logmsg dt { font-weight: bold; }
#logmsg dd { margin: 0; padding: 0 0 0.5em 0; }
#logmsg dd:before { content:'\00bb';}
#logmsg table { border-spacing: 0px; border-collapse: collapse; border-top: 4px solid #fa0; border-bottom: 1px solid #fa0; background: #fff; }
#logmsg table th { text-align: left; font-weight: normal; padding: 0.2em 0.5em; border-top: 1px dotted #fa0; }
#logmsg table td { text-align: right; border-top: 1px dotted #fa0; padding: 0.2em 0.5em; }
#logmsg table thead th { text-align: center; border-bottom: 1px solid #fa0; }
#logmsg table th.Corner { text-align: left; }
#logmsg hr { border: none 0; border-top: 2px dashed #fa0; height: 1px; }
#header, #footer { color: #fff; background: #636; border: 1px #300 solid; padding: 6px; }
#patch { width: 100%; }
#patch h4 {font-family: verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;}
#patch .propset h4, #patch .binary h4 {margin:0;}
#patch pre {padding:0;line-height:1.2em;margin:0;}
#patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;}
#patch .propset .diff, #patch .binary .diff {padding:10px 0;}
#patch span {display:block;padding:0 10px;}
#patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;}
#patch ins {background:#dfd;text-decoration:none;display:block;padding:0 10px;}
#patch del {background:#fdd;text-decoration:none;display:block;padding:0 10px;}
#patch .lines, .info {color:#888;background:#fff;}
--></style>
<div id="msg">
<div id="header">FreeSWITCH Subversion</div>
<dl class="meta">
<dt>Revision</dt> <dd><a href="http://fisheye.freeswitch.org/changelog/FreeSWITCH?cs=17216">17216</a></dd>
<dt>Author</dt> <dd>moy</dd>
<dt>Date</dt> <dd>2010-04-05 16:49:43 -0500 (Mon, 05 Apr 2010)</dd>
</dl>
<h3>Log Message</h3>
<pre>added cpu monitor</pre>
<h3>Modified Paths</h3>
<ul>
<li><a href="#freeswitchtrunklibsfreetdmMakefileam">freeswitch/trunk/libs/freetdm/Makefile.am</a></li>
<li><a href="#freeswitchtrunklibsfreetdmmod_freetdmmod_freetdmc">freeswitch/trunk/libs/freetdm/mod_freetdm/mod_freetdm.c</a></li>
<li><a href="#freeswitchtrunklibsfreetdmsrcftdm_ioc">freeswitch/trunk/libs/freetdm/src/ftdm_io.c</a></li>
<li><a href="#freeswitchtrunklibsfreetdmsrcftmodftmod_sangoma_boostftmod_sangoma_boostc">freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_sangoma_boost/ftmod_sangoma_boost.c</a></li>
<li><a href="#freeswitchtrunklibsfreetdmsrcincludefreetdmh">freeswitch/trunk/libs/freetdm/src/include/freetdm.h</a></li>
</ul>
<h3>Added Paths</h3>
<ul>
<li><a href="#freeswitchtrunklibsfreetdmsrcftdm_cpu_monitorc">freeswitch/trunk/libs/freetdm/src/ftdm_cpu_monitor.c</a></li>
<li><a href="#freeswitchtrunklibsfreetdmsrcincludeftdm_cpu_monitorh">freeswitch/trunk/libs/freetdm/src/include/ftdm_cpu_monitor.h</a></li>
</ul>
</div>
<div id="patch">
<h3>Diff</h3>
<a id="freeswitchtrunklibsfreetdmMakefileam"></a>
<div class="modfile"><h4>Modified: freeswitch/trunk/libs/freetdm/Makefile.am (17215 => 17216)</h4>
<pre class="diff"><span>
<span class="info">--- freeswitch/trunk/libs/freetdm/Makefile.am        2010-04-05 20:01:08 UTC (rev 17215)
+++ freeswitch/trunk/libs/freetdm/Makefile.am        2010-04-05 21:49:43 UTC (rev 17216)
</span><span class="lines">@@ -72,7 +72,8 @@
</span><span class="cx"> $(SRC)/libteletone_generate.c \
</span><span class="cx"> $(SRC)/ftdm_buffer.c \
</span><span class="cx"> $(SRC)/ftdm_threadmutex.c \
</span><del>-$(SRC)/ftdm_dso.c
</del><ins>+$(SRC)/ftdm_dso.c \
+$(SRC)/ftdm_cpu_monitor.c
</ins><span class="cx">
</span><span class="cx"> library_include_HEADERS = \
</span><span class="cx"> $(SRC)/include/fsk.h \
</span><span class="lines">@@ -90,7 +91,8 @@
</span><span class="cx"> $(SRC)/include/ftdm_config.h \
</span><span class="cx"> $(SRC)/include/ftdm_threadmutex.h \
</span><span class="cx"> $(SRC)/include/ftdm_dso.h \
</span><del>-$(SRC)/include/ftdm_types.h
</del><ins>+$(SRC)/include/ftdm_types.h \
+$(SRC)/include/ftdm_cpu_monitor.h
</ins><span class="cx">
</span><span class="cx"> lib_LTLIBRARIES         = libfreetdm.la
</span><span class="cx"> libfreetdm_la_CFLAGS = $(AM_CFLAGS) $(MY_CFLAGS)
</span></span></pre></div>
<a id="freeswitchtrunklibsfreetdmmod_freetdmmod_freetdmc"></a>
<div class="modfile"><h4>Modified: freeswitch/trunk/libs/freetdm/mod_freetdm/mod_freetdm.c (17215 => 17216)</h4>
<pre class="diff"><span>
<span class="info">--- freeswitch/trunk/libs/freetdm/mod_freetdm/mod_freetdm.c        2010-04-05 20:01:08 UTC (rev 17215)
+++ freeswitch/trunk/libs/freetdm/mod_freetdm/mod_freetdm.c        2010-04-05 21:49:43 UTC (rev 17216)
</span><span class="lines">@@ -3142,6 +3142,8 @@
</span><span class="cx">         module_pool = pool;
</span><span class="cx">
</span><span class="cx">         ftdm_global_set_logger(ftdm_logger);
</span><ins>+
+        ftdm_cpu_monitor_disable();
</ins><span class="cx">         
</span><span class="cx">         if (ftdm_global_init() != FTDM_SUCCESS) {
</span><span class="cx">                 ftdm_log(FTDM_LOG_ERROR, "Error loading FreeTDM\n");
</span></span></pre></div>
<a id="freeswitchtrunklibsfreetdmsrcftdm_cpu_monitorc"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/freetdm/src/ftdm_cpu_monitor.c (0 => 17216)</h4>
<pre class="diff"><span>
<span class="info">--- freeswitch/trunk/libs/freetdm/src/ftdm_cpu_monitor.c         (rev 0)
+++ freeswitch/trunk/libs/freetdm/src/ftdm_cpu_monitor.c        2010-04-05 21:49:43 UTC (rev 17216)
</span><span class="lines">@@ -0,0 +1,271 @@
</span><ins>+/*
+ * 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:
+ */
</ins></span></pre></div>
<a id="freeswitchtrunklibsfreetdmsrcftdm_ioc"></a>
<div class="modfile"><h4>Modified: freeswitch/trunk/libs/freetdm/src/ftdm_io.c (17215 => 17216)</h4>
<pre class="diff"><span>
<span class="info">--- freeswitch/trunk/libs/freetdm/src/ftdm_io.c        2010-04-05 20:01:08 UTC (rev 17215)
+++ freeswitch/trunk/libs/freetdm/src/ftdm_io.c        2010-04-05 21:49:43 UTC (rev 17216)
</span><span class="lines">@@ -48,6 +48,7 @@
</span><span class="cx"> #ifdef FTDM_PIKA_SUPPORT
</span><span class="cx"> #include "ftdm_pika.h"
</span><span class="cx"> #endif
</span><ins>+#include "ftdm_cpu_monitor.h"
</ins><span class="cx">
</span><span class="cx"> #define SPAN_PENDING_CHANS_QUEUE_SIZE 1000
</span><span class="cx">
</span><span class="lines">@@ -80,6 +81,16 @@
</span><span class="cx"> #endif
</span><span class="cx"> }
</span><span class="cx">
</span><ins>+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;
+
</ins><span class="cx"> static struct {
</span><span class="cx">         ftdm_hash_t *interface_hash;
</span><span class="cx">         ftdm_hash_t *module_hash;
</span><span class="lines">@@ -93,9 +104,17 @@
</span><span class="cx">         uint32_t running;
</span><span class="cx">         ftdm_span_t *spans;
</span><span class="cx">         ftdm_group_t *groups;
</span><ins>+        cpu_monitor_t cpu_monitor;
</ins><span class="cx"> } globals;
</span><span class="cx">
</span><ins>+static uint8_t ftdm_cpu_monitor_disabled = 0;
</ins><span class="cx">
</span><ins>+enum ftdm_enum_cpu_alarm_action_flags
+{
+        FTDM_CPU_ALARM_ACTION_WARN = (1 << 0),
+        FTDM_CPU_ALARM_ACTION_REJECT = (1 << 1)
+};
+
</ins><span class="cx"> /* enum lookup funcs */
</span><span class="cx"> FTDM_ENUM_NAMES(TONEMAP_NAMES, TONEMAP_STRINGS)
</span><span class="cx"> FTDM_STR2ENUM(ftdm_str2ftdm_tonemap, ftdm_tonemap2str, ftdm_tonemap_t, TONEMAP_NAMES, FTDM_TONEMAP_INVALID)
</span><span class="lines">@@ -1470,6 +1489,14 @@
</span><span class="cx">                 snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "%s", "Channel is alarmed\n");
</span><span class="cx">                 return FTDM_FAIL;
</span><span class="cx">         }
</span><ins>+
+        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;
+        }
</ins><span class="cx">         
</span><span class="cx">         if (!ftdm_test_flag(ftdmchan, FTDM_CHANNEL_READY) || (status = ftdm_mutex_trylock(ftdmchan->mutex)) != FTDM_SUCCESS) {
</span><span class="cx">                 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);
</span><span class="lines">@@ -2988,6 +3015,44 @@
</span><span class="cx">                         } else {
</span><span class="cx">                                 ftdm_log(FTDM_LOG_ERROR, "unknown span variable '%s'\n", var);
</span><span class="cx">                         }
</span><ins>+                } 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);
+                        }
</ins><span class="cx">                 } else {
</span><span class="cx">                         ftdm_log(FTDM_LOG_ERROR, "unknown param [%s] '%s' / '%s'\n", cfg.category, var, val);
</span><span class="cx">                 }
</span><span class="lines">@@ -3516,6 +3581,71 @@
</span><span class="cx">         return status;
</span><span class="cx"> }
</span><span class="cx">
</span><ins>+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;
+}
+
+
</ins><span class="cx"> FT_DECLARE(ftdm_status_t) ftdm_global_init(void)
</span><span class="cx"> {
</span><span class="cx">         memset(&globals, 0, sizeof(globals));
</span><span class="lines">@@ -3538,14 +3668,34 @@
</span><span class="cx">
</span><span class="cx"> FT_DECLARE(ftdm_status_t) ftdm_global_configuration(void)
</span><span class="cx"> {
</span><del>-        int modcount = ftdm_load_modules();
</del><ins>+        int modcount = 0;
+
+        if (!globals.running) {
+                return FTDM_FAIL;
+        }
+        
+        modcount = ftdm_load_modules();
+
</ins><span class="cx">         ftdm_log(FTDM_LOG_NOTICE, "Modules configured: %d \n", modcount);
</span><span class="cx">
</span><ins>+        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;
+
</ins><span class="cx">         if (load_config() != FTDM_SUCCESS) {
</span><span class="cx">                 globals.running = 0;
</span><span class="cx">                 ftdm_log(FTDM_LOG_ERROR, "FreeTDM global configuration failed!\n");
</span><span class="cx">                 return FTDM_FAIL;
</span><span class="cx">         }
</span><ins>+
+        if (!ftdm_cpu_monitor_disabled) {
+                if (ftdm_cpu_monitor_start(&globals.cpu_monitor) != FTDM_SUCCESS) {
+                        return FTDM_FAIL;
+                }
+        }
+
+
</ins><span class="cx">         return FTDM_SUCCESS;
</span><span class="cx"> }
</span><span class="cx">
</span><span class="lines">@@ -3563,6 +3713,8 @@
</span><span class="cx">
</span><span class="cx">         globals.running = 0;        
</span><span class="cx">
</span><ins>+        ftdm_cpu_monitor_stop(&globals.cpu_monitor);
+
</ins><span class="cx">         globals.span_index = 0;
</span><span class="cx">
</span><span class="cx">         ftdm_span_close_all();
</span><span class="lines">@@ -3596,6 +3748,7 @@
</span><span class="cx">         ftdm_mutex_unlock(globals.mutex);
</span><span class="cx">         ftdm_mutex_destroy(&globals.mutex);
</span><span class="cx">         ftdm_mutex_destroy(&globals.span_mutex);
</span><ins>+        ftdm_interrupt_destroy(&globals.cpu_monitor.interrupt);
</ins><span class="cx">
</span><span class="cx">         memset(&globals, 0, sizeof(globals));
</span><span class="cx">         return FTDM_SUCCESS;
</span></span></pre></div>
<a id="freeswitchtrunklibsfreetdmsrcftmodftmod_sangoma_boostftmod_sangoma_boostc"></a>
<div class="modfile"><h4>Modified: freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_sangoma_boost/ftmod_sangoma_boost.c (17215 => 17216)</h4>
<pre class="diff"><span>
<span class="info">--- freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_sangoma_boost/ftmod_sangoma_boost.c        2010-04-05 20:01:08 UTC (rev 17215)
+++ freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_sangoma_boost/ftmod_sangoma_boost.c        2010-04-05 21:49:43 UTC (rev 17216)
</span><span class="lines">@@ -880,8 +880,8 @@
</span><span class="cx"> */
</span><span class="cx"> static void handle_call_start(ftdm_span_t *span, sangomabc_connection_t *mcon, sangomabc_event_t *event)
</span><span class="cx"> {
</span><del>-        ftdm_channel_t *ftdmchan;
-
</del><ins>+        ftdm_channel_t *ftdmchan = NULL;
+        int hangup_cause = FTDM_CAUSE_CALL_REJECTED;
</ins><span class="cx">         if (!(ftdmchan = find_ftdmchan(span, (sangomabc_short_event_t*)event, 0))) {
</span><span class="cx">                 if ((ftdmchan = find_ftdmchan(span, (sangomabc_short_event_t*)event, 1))) {
</span><span class="cx">                         int r;
</span><span class="lines">@@ -896,7 +896,7 @@
</span><span class="cx">
</span><span class="cx">                         }
</span><span class="cx">                         ftdm_set_sflag(ftdmchan, SFLAG_SENT_FINAL_MSG);
</span><del>-                        ftdmchan=NULL;
</del><ins>+                        ftdmchan = NULL;
</ins><span class="cx">                 }
</span><span class="cx">                 ftdm_log(FTDM_LOG_CRIT, "START CANT FIND CHAN %d:%d\n", event->span+1,event->chan+1);
</span><span class="cx">                 goto error;
</span><span class="lines">@@ -953,12 +953,13 @@
</span><span class="cx">         return;
</span><span class="cx">
</span><span class="cx"> error:
</span><ins>+        hangup_cause = ftdmchan ? ftdmchan->caller_data.hangup_cause : FTDM_CAUSE_REQUESTED_CHAN_UNAVAIL;
</ins><span class="cx">         sangomabc_exec_command(mcon,
</span><span class="cx">                                                  event->span,
</span><span class="cx">                                                  event->chan,
</span><span class="cx">                                                  0,
</span><span class="cx">                                                  SIGBOOST_EVENT_CALL_START_NACK,
</span><del>-                                                 0, 0);
</del><ins>+                                                 hangup_cause, 0);
</ins><span class="cx">                 
</span><span class="cx"> }
</span><span class="cx">
</span></span></pre></div>
<a id="freeswitchtrunklibsfreetdmsrcincludefreetdmh"></a>
<div class="modfile"><h4>Modified: freeswitch/trunk/libs/freetdm/src/include/freetdm.h (17215 => 17216)</h4>
<pre class="diff"><span>
<span class="info">--- freeswitch/trunk/libs/freetdm/src/include/freetdm.h        2010-04-05 20:01:08 UTC (rev 17215)
+++ freeswitch/trunk/libs/freetdm/src/include/freetdm.h        2010-04-05 21:49:43 UTC (rev 17216)
</span><span class="lines">@@ -824,6 +824,7 @@
</span><span class="cx"> FT_DECLARE(char *) ftdm_api_execute(const char *type, const char *cmd);
</span><span class="cx"> FT_DECLARE(int) ftdm_vasprintf(char **ret, const char *fmt, va_list ap);
</span><span class="cx"> FT_DECLARE(ftdm_status_t) ftdm_channel_set_caller_data(ftdm_channel_t *ftdmchan, ftdm_caller_data_t *caller_data);
</span><ins>+FT_DECLARE(void) ftdm_cpu_monitor_disable(void);
</ins><span class="cx">
</span><span class="cx"> FIO_CODEC_FUNCTION(fio_slin2ulaw);
</span><span class="cx"> FIO_CODEC_FUNCTION(fio_ulaw2slin);
</span></span></pre></div>
<a id="freeswitchtrunklibsfreetdmsrcincludeftdm_cpu_monitorh"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/freetdm/src/include/ftdm_cpu_monitor.h (0 => 17216)</h4>
<pre class="diff"><span>
<span class="info">--- freeswitch/trunk/libs/freetdm/src/include/ftdm_cpu_monitor.h         (rev 0)
+++ freeswitch/trunk/libs/freetdm/src/include/ftdm_cpu_monitor.h        2010-04-05 21:49:43 UTC (rev 17216)
</span><span class="lines">@@ -0,0 +1,75 @@
</span><ins>+/*
+ * 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:
+ */
</ins></span></pre>
</div>
</div>
<div id="footer">See you at ClueCon</div>
</body>
</html>