Mon Oct 8 12:39:11 2012

Asterisk developer's documentation


autoservice.c File Reference

Automatic channel service routines. More...

#include "asterisk.h"
#include <sys/time.h>
#include <signal.h>
#include "asterisk/_private.h"
#include "asterisk/pbx.h"
#include "asterisk/frame.h"
#include "asterisk/sched.h"
#include "asterisk/channel.h"
#include "asterisk/file.h"
#include "asterisk/translate.h"
#include "asterisk/manager.h"
#include "asterisk/chanvars.h"
#include "asterisk/linkedlists.h"
#include "asterisk/indications.h"
#include "asterisk/lock.h"
#include "asterisk/utils.h"

Go to the source code of this file.

Data Structures

struct  asent
struct  aslist

Defines

#define MAX_AUTOMONS   1500

Functions

int ast_autoservice_ignore (struct ast_channel *chan, enum ast_frame_type ftype)
 Ignore certain frame types.
void ast_autoservice_init (void)
int ast_autoservice_start (struct ast_channel *chan)
 Automatically service a channel for us...
int ast_autoservice_stop (struct ast_channel *chan)
 Stop servicing a channel for us...
static void * autoservice_run (void *ign)

Variables

static int as_chan_list_state
static ast_cond_t as_cond
static pthread_t asthread = AST_PTHREADT_NULL


Detailed Description

Automatic channel service routines.

Author:
Mark Spencer <markster@digium.com>

Russell Bryant <russell@digium.com>

Definition in file autoservice.c.


Define Documentation

#define MAX_AUTOMONS   1500

Definition at line 54 of file autoservice.c.

Referenced by autoservice_run().


Function Documentation

int ast_autoservice_ignore ( struct ast_channel chan,
enum ast_frame_type  ftype 
)

Ignore certain frame types.

Note:
Normally, we cache DTMF, IMAGE, HTML, TEXT, and CONTROL frames while a channel is in autoservice and queue them up when taken out of autoservice. When this is not desireable, this API may be used to cause the channel to ignore those frametypes after the channel is put into autoservice, but before autoservice is stopped.
Return values:
0 success
-1 channel is not in autoservice

Definition at line 306 of file autoservice.c.

References AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, asent::chan, asent::ignore_frame_types, and asent::list.

Referenced by builtin_automixmonitor(), feature_exec_app(), and play_message_on_chan().

00307 {
00308    struct asent *as;
00309    int res = -1;
00310 
00311    AST_LIST_LOCK(&aslist);
00312    AST_LIST_TRAVERSE(&aslist, as, list) {
00313       if (as->chan == chan) {
00314          res = 0;
00315          as->ignore_frame_types |= (1 << ftype);
00316          break;
00317       }
00318    }
00319    AST_LIST_UNLOCK(&aslist);
00320    return res;
00321 }

void ast_autoservice_init ( void   ) 

Provided by autoservice.c

Definition at line 323 of file autoservice.c.

References as_cond, and ast_cond_init.

Referenced by main().

00324 {
00325    ast_cond_init(&as_cond, NULL);
00326 }

int ast_autoservice_start ( struct ast_channel chan  ) 

Automatically service a channel for us...

Return values:
0 success
-1 failure, or the channel is already being autoserviced

Definition at line 178 of file autoservice.c.

References as_cond, ast_calloc, ast_channel_lock, ast_channel_unlock, ast_cond_signal, AST_FLAG_END_DTMF_ONLY, AST_LIST_EMPTY, AST_LIST_INSERT_HEAD, AST_LIST_LOCK, AST_LIST_REMOVE, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_log(), ast_pthread_create_background, AST_PTHREADT_NULL, ast_set_flag, ast_test_flag, asthread, autoservice_run(), asent::chan, free, asent::list, LOG_WARNING, and asent::use_count.

Referenced by _macro_exec(), acf_curl_helper(), acf_jabberreceive_read(), acf_odbc_read(), acf_odbc_write(), ast_app_run_macro(), ast_dtmf_stream(), ast_get_enum(), ast_get_srv(), ast_get_txt(), ast_masq_park_call_exten(), ast_park_call_exten(), bridge_playfile(), builtin_atxfer(), builtin_automixmonitor(), builtin_blindtransfer(), conf_play(), confbridge_exec(), dial_exec_full(), exec(), feature_exec_app(), feature_request_and_dial(), function_realtime_read(), function_realtime_readdestroy(), function_realtime_store(), function_realtime_write(), leave_conference_bridge(), lock_read(), lua_autoservice_start(), lua_get_variable_value(), lua_pbx_exec(), lua_set_variable(), lua_set_variable_value(), originate_exec(), osplookup_exec(), pbx_find_extension(), play_message_on_chan(), realtimefield_read(), senddtmf_exec(), shell_helper(), sla_station_exec(), smdi_msg_retrieve_read(), srv_datastore_setup(), system_exec_helper(), and trylock_read().

00179 {
00180    int res = 0;
00181    struct asent *as;
00182 
00183    AST_LIST_LOCK(&aslist);
00184    AST_LIST_TRAVERSE(&aslist, as, list) {
00185       if (as->chan == chan) {
00186          as->use_count++;
00187          break;
00188       }
00189    }
00190    AST_LIST_UNLOCK(&aslist);
00191 
00192    if (as) {
00193       /* Entry exists, autoservice is already handling this channel */
00194       return 0;
00195    }
00196 
00197    if (!(as = ast_calloc(1, sizeof(*as))))
00198       return -1;
00199    
00200    /* New entry created */
00201    as->chan = chan;
00202    as->use_count = 1;
00203 
00204    ast_channel_lock(chan);
00205    as->orig_end_dtmf_flag = ast_test_flag(chan, AST_FLAG_END_DTMF_ONLY) ? 1 : 0;
00206    if (!as->orig_end_dtmf_flag)
00207       ast_set_flag(chan, AST_FLAG_END_DTMF_ONLY);
00208    ast_channel_unlock(chan);
00209 
00210    AST_LIST_LOCK(&aslist);
00211 
00212    if (AST_LIST_EMPTY(&aslist) && asthread != AST_PTHREADT_NULL) {
00213       ast_cond_signal(&as_cond);
00214    }
00215 
00216    AST_LIST_INSERT_HEAD(&aslist, as, list);
00217 
00218    if (asthread == AST_PTHREADT_NULL) { /* need start the thread */
00219       if (ast_pthread_create_background(&asthread, NULL, autoservice_run, NULL)) {
00220          ast_log(LOG_WARNING, "Unable to create autoservice thread :(\n");
00221          /* There will only be a single member in the list at this point,
00222             the one we just added. */
00223          AST_LIST_REMOVE(&aslist, as, list);
00224          free(as);
00225          asthread = AST_PTHREADT_NULL;
00226          res = -1;
00227       } else {
00228          pthread_kill(asthread, SIGURG);
00229       }
00230    }
00231 
00232    AST_LIST_UNLOCK(&aslist);
00233 
00234    return res;
00235 }

int ast_autoservice_stop ( struct ast_channel chan  ) 

Stop servicing a channel for us...

Note:
if chan is locked prior to calling ast_autoservice_stop, it is likely that there will be a deadlock between the thread that calls ast_autoservice_stop and the autoservice thread. It is important that chan is not locked prior to this call
Parameters:
chan 
Return values:
0 success
-1 error, or the channel has been hungup

Definition at line 237 of file autoservice.c.

References ast_channel::_softhangup, as_chan_list_state, ast_channel_lock, ast_channel_unlock, ast_clear_flag, AST_FLAG_END_DTMF_ONLY, ast_frfree, AST_LIST_LOCK, AST_LIST_REMOVE_CURRENT, AST_LIST_REMOVE_HEAD, AST_LIST_TRAVERSE_SAFE_BEGIN, AST_LIST_TRAVERSE_SAFE_END, AST_LIST_UNLOCK, AST_PTHREADT_NULL, ast_queue_frame_head(), asthread, asent::chan, asent::deferred_frames, f, free, asent::ignore_frame_types, asent::list, asent::orig_end_dtmf_flag, and asent::use_count.

Referenced by _macro_exec(), acf_curl_helper(), acf_jabberreceive_read(), acf_odbc_read(), acf_odbc_write(), array(), ast_app_run_macro(), ast_dtmf_stream(), ast_get_srv(), ast_get_txt(), ast_hangup(), ast_masq_park_call_exten(), ast_park_call_exten(), bridge_playfile(), builtin_atxfer(), builtin_automixmonitor(), conf_play(), confbridge_exec(), dial_exec_full(), exec(), feature_exec_app(), feature_request_and_dial(), finishup(), function_realtime_read(), function_realtime_readdestroy(), function_realtime_store(), function_realtime_write(), leave_conference_bridge(), lock_read(), lua_autoservice_stop(), lua_get_variable_value(), lua_pbx_exec(), lua_set_variable(), lua_set_variable_value(), originate_exec(), osplookup_exec(), pbx_find_extension(), play_message_on_chan(), realtimefield_read(), senddtmf_exec(), shell_helper(), sla_station_exec(), smdi_msg_retrieve_read(), srv_datastore_setup(), system_exec_helper(), and trylock_read().

00238 {
00239    int res = -1;
00240    struct asent *as, *removed = NULL;
00241    struct ast_frame *f;
00242    int chan_list_state;
00243 
00244    AST_LIST_LOCK(&aslist);
00245 
00246    /* Save the autoservice channel list state.  We _must_ verify that the channel
00247     * list has been rebuilt before we return.  Because, after we return, the channel
00248     * could get destroyed and we don't want our poor autoservice thread to step on
00249     * it after its gone! */
00250    chan_list_state = as_chan_list_state;
00251 
00252    /* Find the entry, but do not free it because it still can be in the
00253       autoservice thread array */
00254    AST_LIST_TRAVERSE_SAFE_BEGIN(&aslist, as, list) {  
00255       if (as->chan == chan) {
00256          as->use_count--;
00257          if (as->use_count < 1) {
00258             AST_LIST_REMOVE_CURRENT(list);
00259             removed = as;
00260          }
00261          break;
00262       }
00263    }
00264    AST_LIST_TRAVERSE_SAFE_END;
00265 
00266    if (removed && asthread != AST_PTHREADT_NULL) {
00267       pthread_kill(asthread, SIGURG);
00268    }
00269 
00270    AST_LIST_UNLOCK(&aslist);
00271 
00272    if (!removed) {
00273       return 0;
00274    }
00275 
00276    /* Wait while autoservice thread rebuilds its list. */
00277    while (chan_list_state == as_chan_list_state) {
00278       usleep(1000);
00279    }
00280 
00281    /* Now autoservice thread should have no references to our entry
00282       and we can safely destroy it */
00283 
00284    if (!chan->_softhangup) {
00285       res = 0;
00286    }
00287 
00288    if (!as->orig_end_dtmf_flag) {
00289       ast_clear_flag(chan, AST_FLAG_END_DTMF_ONLY);
00290    }
00291 
00292    ast_channel_lock(chan);
00293    while ((f = AST_LIST_REMOVE_HEAD(&as->deferred_frames, frame_list))) {
00294       if (!((1 << f->frametype) & as->ignore_frame_types)) {
00295          ast_queue_frame_head(chan, f);
00296       }
00297       ast_frfree(f);
00298    }
00299    ast_channel_unlock(chan);
00300 
00301    free(as);
00302 
00303    return res;
00304 }

static void* autoservice_run ( void *  ign  )  [static]

Definition at line 78 of file autoservice.c.

References ast_check_hangup(), ast_cond_wait, AST_CONTROL_HANGUP, AST_FRAME_CONTROL, ast_frdup(), ast_frfree, ast_frisolate(), ast_is_deferrable_frame(), AST_LIST_EMPTY, AST_LIST_INSERT_HEAD, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_log(), ast_read(), ast_waitfor_n(), asthread, asent::chan, asent::deferred_frames, f, ast_frame::frametype, LOG_WARNING, and MAX_AUTOMONS.

Referenced by ast_autoservice_start().

00079 {
00080    struct ast_frame hangup_frame = {
00081       .frametype = AST_FRAME_CONTROL,
00082       .subclass.integer = AST_CONTROL_HANGUP,
00083    };
00084 
00085    for (;;) {
00086       struct ast_channel *mons[MAX_AUTOMONS];
00087       struct asent *ents[MAX_AUTOMONS];
00088       struct ast_channel *chan;
00089       struct asent *as;
00090       int i, x = 0, ms = 50;
00091       struct ast_frame *f = NULL;
00092       struct ast_frame *defer_frame = NULL;
00093 
00094       AST_LIST_LOCK(&aslist);
00095 
00096       /* At this point, we know that no channels that have been removed are going
00097        * to get used again. */
00098       as_chan_list_state++;
00099 
00100       if (AST_LIST_EMPTY(&aslist)) {
00101          ast_cond_wait(&as_cond, &aslist.lock);
00102       }
00103 
00104       AST_LIST_TRAVERSE(&aslist, as, list) {
00105          if (!ast_check_hangup(as->chan)) {
00106             if (x < MAX_AUTOMONS) {
00107                ents[x] = as;
00108                mons[x++] = as->chan;
00109             } else {
00110                ast_log(LOG_WARNING, "Exceeded maximum number of automatic monitoring events.  Fix autoservice.c\n");
00111             }
00112          }
00113       }
00114 
00115       AST_LIST_UNLOCK(&aslist);
00116 
00117       if (!x) {
00118          /* If we don't sleep, this becomes a busy loop, which causes
00119           * problems when Asterisk runs at a different priority than other
00120           * user processes.  As long as we check for new channels at least
00121           * once every 10ms, we should be fine. */
00122          usleep(10000);
00123          continue;
00124       }
00125 
00126       chan = ast_waitfor_n(mons, x, &ms);
00127       if (!chan) {
00128          continue;
00129       }
00130 
00131       f = ast_read(chan);
00132 
00133       if (!f) {
00134          /* No frame means the channel has been hung up.
00135           * A hangup frame needs to be queued here as ast_waitfor() may
00136           * never return again for the condition to be detected outside
00137           * of autoservice.  So, we'll leave a HANGUP queued up so the
00138           * thread in charge of this channel will know. */
00139 
00140          defer_frame = &hangup_frame;
00141       } else if (ast_is_deferrable_frame(f)) {
00142          defer_frame = f;
00143       }
00144 
00145       if (defer_frame) {
00146          for (i = 0; i < x; i++) {
00147             struct ast_frame *dup_f;
00148             
00149             if (mons[i] != chan) {
00150                continue;
00151             }
00152             
00153             if (defer_frame != f) {
00154                if ((dup_f = ast_frdup(defer_frame))) {
00155                   AST_LIST_INSERT_HEAD(&ents[i]->deferred_frames, dup_f, frame_list);
00156                }
00157             } else {
00158                if ((dup_f = ast_frisolate(defer_frame))) {
00159                   if (dup_f != defer_frame) {
00160                      ast_frfree(defer_frame);
00161                   }
00162                   AST_LIST_INSERT_HEAD(&ents[i]->deferred_frames, dup_f, frame_list);
00163                }
00164             }
00165             
00166             break;
00167          }
00168       } else if (f) {
00169          ast_frfree(f);
00170       }
00171    }
00172 
00173    asthread = AST_PTHREADT_NULL;
00174 
00175    return NULL;
00176 }


Variable Documentation

int as_chan_list_state [static]

Definition at line 76 of file autoservice.c.

Referenced by ast_autoservice_stop().

ast_cond_t as_cond [static]

Definition at line 72 of file autoservice.c.

Referenced by ast_autoservice_init(), and ast_autoservice_start().

pthread_t asthread = AST_PTHREADT_NULL [static]

Definition at line 74 of file autoservice.c.

Referenced by ast_autoservice_start(), ast_autoservice_stop(), and autoservice_run().


Generated on Mon Oct 8 12:39:11 2012 for Asterisk - The Open Source Telephony Project by  doxygen 1.4.7