Mon Mar 19 11:30:36 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 50 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 302 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().

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

void ast_autoservice_init ( void   ) 

Provided by autoservice.c

Definition at line 319 of file autoservice.c.

References as_cond, and ast_cond_init.

Referenced by main().

00320 {
00321    ast_cond_init(&as_cond, NULL);
00322 }

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 174 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(), post_join_marked(), realtimefield_read(), senddtmf_exec(), shell_helper(), sla_station_exec(), smdi_msg_retrieve_read(), srv_datastore_setup(), system_exec_helper(), and trylock_read().

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

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 233 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(), post_join_marked(), realtimefield_read(), senddtmf_exec(), shell_helper(), sla_station_exec(), smdi_msg_retrieve_read(), srv_datastore_setup(), system_exec_helper(), and trylock_read().

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

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

Definition at line 74 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().

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


Variable Documentation

int as_chan_list_state [static]

Definition at line 72 of file autoservice.c.

Referenced by ast_autoservice_stop().

ast_cond_t as_cond [static]

Definition at line 68 of file autoservice.c.

Referenced by ast_autoservice_init(), and ast_autoservice_start().

pthread_t asthread = AST_PTHREADT_NULL [static]

Definition at line 70 of file autoservice.c.

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


Generated on Mon Mar 19 11:30:36 2012 for Asterisk - The Open Source Telephony Project by  doxygen 1.4.7