@ -734,11 +734,12 @@ struct eventqent {
int usecount ; /*!< # of clients who still need the event */
int category ;
unsigned int seq ; /*!< sequence number */
AST_LIST_ENTRY ( eventqent ) eq_next ;
struct timeval tv ; /*!< When event was allocated */
AST_RWLIST_ENTRY ( eventqent ) eq_next ;
char eventdata [ 1 ] ; /*!< really variable size, allocated by append_event() */
} ;
static AST_ LIST_HEAD_STATIC( all_events , eventqent ) ;
static AST_ RW LIST_HEAD_STATIC( all_events , eventqent ) ;
static int displayconnects = 1 ;
static int allowmultiplelogin = 1 ;
@ -863,8 +864,6 @@ struct manager_channel_variable {
static AST_RWLIST_HEAD_STATIC ( channelvars , manager_channel_variable ) ;
# define NEW_EVENT(m) (AST_LIST_NEXT(m->session->last_ev, eq_next))
/*! \brief user descriptor, as read from the config file.
*
* \ note It is still missing some fields - - e . g . we can have multiple permit and deny
@ -893,8 +892,6 @@ static AST_RWLIST_HEAD_STATIC(actions, manager_action);
/*! \brief list of hooks registered */
static AST_RWLIST_HEAD_STATIC ( manager_hooks , manager_custom_hook ) ;
static struct eventqent * unref_event ( struct eventqent * e ) ;
static void ref_event ( struct eventqent * e ) ;
static void free_channelvars ( void ) ;
/*! \brief Add a custom hook to be called when an event is fired */
@ -931,15 +928,15 @@ static struct eventqent *grab_last(void)
{
struct eventqent * ret ;
AST_ LIST_LOCK( & all_events ) ;
ret = AST_ LIST_LAST( & all_events ) ;
AST_ RW LIST_WR LOCK( & all_events ) ;
ret = AST_ RW LIST_LAST( & all_events ) ;
/* the list is never empty now, but may become so when
* we optimize it in the future , so be prepared .
*/
if ( ret ) {
ast_atomic_fetchadd_int ( & ret - > usecount , 1 ) ;
}
AST_ LIST_UNLOCK( & all_events ) ;
AST_ RW LIST_UNLOCK( & all_events ) ;
return ret ;
}
@ -950,14 +947,24 @@ static struct eventqent *grab_last(void)
static void purge_events ( void )
{
struct eventqent * ev ;
struct timeval now = ast_tvnow ( ) ;
AST_ LIST_LOCK( & all_events ) ;
while ( ( ev = AST_ LIST_FIRST( & all_events ) ) & &
ev - > usecount = = 0 & & AST_ LIST_NEXT( ev , eq_next ) ) {
AST_ LIST_REMOVE_HEAD( & all_events , eq_next ) ;
AST_ RW LIST_WR LOCK( & all_events ) ;
while ( ( ev = AST_ RW LIST_FIRST( & all_events ) ) & &
ev - > usecount = = 0 & & AST_ RW LIST_NEXT( ev , eq_next ) ) {
AST_ RW LIST_REMOVE_HEAD( & all_events , eq_next ) ;
ast_free ( ev ) ;
}
AST_LIST_UNLOCK ( & all_events ) ;
AST_RWLIST_TRAVERSE_SAFE_BEGIN ( & all_events , ev , eq_next ) {
/* 2.5 times whatever the HTTP timeout is (maximum 2.5 hours) is the maximum time that we will definitely cache an event */
if ( ev - > usecount = = 0 & & ast_tvdiff_sec ( now , ev - > tv ) > ( httptimeout > 3600 ? 3600 : httptimeout ) * 2.5 ) {
AST_RWLIST_REMOVE_CURRENT ( eq_next ) ;
ast_free ( ev ) ;
}
}
AST_RWLIST_TRAVERSE_SAFE_END ;
AST_RWLIST_UNLOCK ( & all_events ) ;
}
/*!
@ -1107,7 +1114,7 @@ static void session_destructor(void *obj)
if ( session - > f ! = NULL ) {
fclose ( session - > f ) ;
}
unref_event( eqe ) ;
ast_atomic_fetchadd_int( & eqe - > usecount , - 1 ) ;
}
/*! \brief Allocate manager session structure and add it to the list of sessions */
@ -1482,13 +1489,13 @@ static char *handle_showmaneventq(struct ast_cli_entry *e, int cmd, struct ast_c
case CLI_GENERATE :
return NULL ;
}
AST_ LIST_LOCK( & all_events ) ;
AST_ LIST_TRAVERSE( & all_events , s , eq_next ) {
AST_ RW LIST_RD LOCK( & all_events ) ;
AST_ RW LIST_TRAVERSE( & all_events , s , eq_next ) {
ast_cli ( a - > fd , " Usecount: %d \n " , s - > usecount ) ;
ast_cli ( a - > fd , " Category: %d \n " , s - > category ) ;
ast_cli ( a - > fd , " Event: \n %s " , s - > eventdata ) ;
}
AST_ LIST_UNLOCK( & all_events ) ;
AST_ RW LIST_UNLOCK( & all_events ) ;
return CLI_SUCCESS ;
}
@ -1513,15 +1520,17 @@ static char *handle_manager_reload(struct ast_cli_entry *e, int cmd, struct ast_
return CLI_SUCCESS ;
}
static struct eventqent * unref _event( struct eventqent * e )
static struct eventqent * advance _event( struct eventqent * e )
{
ast_atomic_fetchadd_int ( & e - > usecount , - 1 ) ;
return AST_LIST_NEXT ( e , eq_next ) ;
}
struct eventqent * next ;
static void ref_event ( struct eventqent * e )
{
ast_atomic_fetchadd_int ( & e - > usecount , 1 ) ;
AST_RWLIST_RDLOCK ( & all_events ) ;
if ( ( next = AST_RWLIST_NEXT ( e , eq_next ) ) ) {
ast_atomic_fetchadd_int ( & next - > usecount , 1 ) ;
ast_atomic_fetchadd_int ( & e - > usecount , - 1 ) ;
}
AST_RWLIST_UNLOCK ( & all_events ) ;
return next ;
}
/*
@ -2610,7 +2619,7 @@ static int action_waitevent(struct mansession *s, const struct message *m)
for ( x = 0 ; x < timeout | | timeout < 0 ; x + + ) {
mansession_lock ( s ) ;
if ( NEW_EVENT( s ) ) {
if ( AST_RWLIST_NEXT( s - > session - > last_ev , eq_next ) ) {
needexit = 1 ;
}
/* We can have multiple HTTP session point to the same mansession entry.
@ -2639,16 +2648,17 @@ static int action_waitevent(struct mansession *s, const struct message *m)
mansession_lock ( s ) ;
if ( s - > session - > waiting_thread = = pthread_self ( ) ) {
struct eventqent * eqe ;
struct eventqent * eqe = s - > session - > last_ev ;
astman_send_response ( s , m , " Success " , " Waiting for Event completed. " ) ;
while ( ( eqe = NEW_EVENT ( s ) ) ) {
ref_event ( eqe ) ;
AST_RWLIST_RDLOCK ( & all_events ) ;
while ( ( eqe = advance_event ( eqe ) ) ) {
if ( ( ( s - > session - > readperm & eqe - > category ) = = eqe - > category ) & &
( ( s - > session - > send_events & eqe - > category ) = = eqe - > category ) ) {
astman_append ( s , " %s " , eqe - > eventdata ) ;
}
s - > session - > last_ev = unref_event ( s - > session - > last_ev ) ;
s - > session - > last_ev = eqe ;
}
AST_RWLIST_UNLOCK ( & all_events ) ;
astman_append ( s ,
" Event: WaitEventComplete \r \n "
" %s "
@ -3622,18 +3632,19 @@ static int process_events(struct mansession *s)
ao2_lock ( s - > session ) ;
if ( s - > session - > f ! = NULL ) {
struct eventqent * eqe ;
while ( ( eqe = NEW_EVENT ( s ) ) ) {
ref_event ( eqe ) ;
struct eventqent * eqe = s - > session - > last_ev ;
AST_RWLIST_RDLOCK ( & all_events ) ;
while ( ( eqe = advance_event ( eqe ) ) ) {
if ( ! ret & & s - > session - > authenticated & &
( s - > session - > readperm & eqe - > category ) = = eqe - > category & &
( s - > session - > send_events & eqe - > category ) = = eqe - > category ) {
if ( send_string ( s , eqe - > eventdata ) < 0 )
if ( send_string ( s , eqe - > eventdata ) < 0 ) {
ret = - 1 ; /* don't send more */
}
}
s - > session - > last_ev = unref_event ( s - > session - > last_ev ) ;
s - > session - > last_ev = eqe ;
}
AST_RWLIST_UNLOCK ( & all_events ) ;
}
ao2_unlock ( s - > session ) ;
return ret ;
@ -4251,12 +4262,13 @@ static int append_event(const char *str, int category)
tmp - > usecount = 0 ;
tmp - > category = category ;
tmp - > seq = ast_atomic_fetchadd_int ( & seq , 1 ) ;
AST_LIST_NEXT ( tmp , eq_next ) = NULL ;
tmp - > tv = ast_tvnow ( ) ;
AST_RWLIST_NEXT ( tmp , eq_next ) = NULL ;
strcpy ( tmp - > eventdata , str ) ;
AST_ LIST_LOCK( & all_events ) ;
AST_ LIST_INSERT_TAIL( & all_events , tmp , eq_next ) ;
AST_ LIST_UNLOCK( & all_events ) ;
AST_ RW LIST_WR LOCK( & all_events ) ;
AST_ RW LIST_INSERT_TAIL( & all_events , tmp , eq_next ) ;
AST_ RW LIST_UNLOCK( & all_events ) ;
return 0 ;
}