2014-02-28 02:15:24 -08:00
/** \file event.c
2005-10-06 08:37:08 +10:00
2012-11-18 11:23:22 +01:00
Functions for handling event triggers
2005-10-06 08:37:08 +10:00
*/
2006-08-11 11:18:35 +10:00
# include "config.h"
2005-10-06 08:37:08 +10:00
# include <stdlib.h>
# include <stdio.h>
# include <wchar.h>
# include <unistd.h>
# include <termios.h>
# include <signal.h>
# include <string.h>
2011-12-26 22:18:16 -08:00
# include <algorithm>
2005-10-06 08:37:08 +10:00
2006-02-28 23:17:16 +10:00
# include "fallback.h"
2005-10-06 08:37:08 +10:00
# include "util.h"
2006-02-28 23:17:16 +10:00
2006-01-21 00:27:21 +10:00
# include "wutil.h"
2005-10-06 08:37:08 +10:00
# include "function.h"
2013-04-03 17:26:02 -07:00
# include "input_common.h"
2005-10-06 08:37:08 +10:00
# include "proc.h"
# include "parser.h"
# include "common.h"
# include "event.h"
# include "signal.h"
2006-07-20 08:55:49 +10:00
2012-12-19 00:32:03 +01:00
2005-10-06 08:37:08 +10:00
/**
Number of signals that can be queued before an overflow occurs
*/
# define SIG_UNHANDLED_MAX 64
/**
This struct contains a list of generated signals waiting to be
dispatched
*/
typedef struct
{
2012-11-18 16:30:30 -08:00
/**
Number of delivered signals
*/
2012-12-23 16:37:43 +01:00
volatile int count ;
2012-11-18 16:30:30 -08:00
/**
Whether signals have been skipped
*/
2012-12-23 16:37:43 +01:00
volatile int overflow ;
2012-11-18 16:30:30 -08:00
/**
Array of signal events
*/
2012-12-23 16:37:43 +01:00
volatile int signal [ SIG_UNHANDLED_MAX ] ;
2005-10-06 08:37:08 +10:00
}
2012-11-18 16:30:30 -08:00
signal_list_t ;
2005-10-06 08:37:08 +10:00
2005-10-25 01:26:25 +10:00
/**
2005-10-06 08:37:08 +10:00
The signal event list . Actually two separate lists . One which is
active , which is the one that new events is written to . The inactive
one contains the events that are currently beeing performed .
*/
2014-03-07 18:20:42 +01:00
static signal_list_t sig_list [ ] = { { } , { } } ;
2005-10-06 08:37:08 +10:00
/**
The index of sig_list that is the list of signals currently written to
*/
2012-12-23 16:37:43 +01:00
static volatile int active_list = 0 ;
2005-10-06 08:37:08 +10:00
2012-11-18 11:23:22 +01:00
typedef std : : vector < event_t * > event_list_t ;
2011-12-26 22:27:58 -08:00
2005-10-06 08:37:08 +10:00
/**
2012-06-04 14:20:01 -07:00
List of event handlers .
Note this is inspected by our signal handler , so we must block signals around manipulating it .
2005-10-06 08:37:08 +10:00
*/
2011-12-26 22:27:58 -08:00
static event_list_t events ;
2005-10-06 08:37:08 +10:00
/**
List of event handlers that should be removed
*/
2011-12-26 22:27:58 -08:00
static event_list_t killme ;
2005-10-06 08:37:08 +10:00
2005-12-12 08:21:01 +10:00
/**
List of events that have been sent but have not yet been delivered because they are blocked .
*/
2011-12-26 22:27:58 -08:00
static event_list_t blocked ;
2005-12-12 08:21:01 +10:00
2005-10-06 08:37:08 +10:00
/**
Tests if one event instance matches the definition of a event
2006-02-03 01:33:30 +10:00
class . If both the class and the instance name a function ,
they must name the same function .
2005-10-06 08:37:08 +10:00
*/
2012-12-20 11:48:36 +01:00
static int event_match ( const event_t & classv , const event_t & instance )
2005-10-06 08:37:08 +10:00
{
2007-08-20 02:42:30 +10:00
2012-03-05 14:18:16 -08:00
/* If the function names are both non-empty and different, then it's not a match */
2012-12-20 11:48:36 +01:00
if ( ! classv . function_name . empty ( ) & &
! instance . function_name . empty ( ) & &
classv . function_name ! = instance . function_name )
2012-11-18 16:30:30 -08:00
{
2012-03-05 14:18:16 -08:00
return 0 ;
2012-11-18 16:30:30 -08:00
}
2012-11-18 11:23:22 +01:00
2012-12-20 11:48:36 +01:00
if ( classv . type = = EVENT_ANY )
2012-11-18 16:30:30 -08:00
return 1 ;
2012-11-18 11:23:22 +01:00
2012-12-20 11:48:36 +01:00
if ( classv . type ! = instance . type )
2012-11-18 16:30:30 -08:00
return 0 ;
2012-11-18 11:23:22 +01:00
2012-12-20 11:48:36 +01:00
switch ( classv . type )
2012-11-18 16:30:30 -08:00
{
2012-11-18 11:23:22 +01:00
2012-11-19 00:31:03 -08:00
case EVENT_SIGNAL :
2012-12-20 11:48:36 +01:00
if ( classv . param1 . signal = = EVENT_ANY_SIGNAL )
2012-11-19 00:31:03 -08:00
return 1 ;
2012-12-20 11:48:36 +01:00
return classv . param1 . signal = = instance . param1 . signal ;
2012-11-18 11:23:22 +01:00
2012-11-19 00:31:03 -08:00
case EVENT_VARIABLE :
2012-12-20 11:48:36 +01:00
return instance . str_param1 = = classv . str_param1 ;
2012-11-18 11:23:22 +01:00
2012-11-19 00:31:03 -08:00
case EVENT_EXIT :
2012-12-20 11:48:36 +01:00
if ( classv . param1 . pid = = EVENT_ANY_PID )
2012-11-19 00:31:03 -08:00
return 1 ;
2012-12-20 11:48:36 +01:00
return classv . param1 . pid = = instance . param1 . pid ;
2012-11-18 11:23:22 +01:00
2012-11-19 00:31:03 -08:00
case EVENT_JOB_ID :
2012-12-20 11:48:36 +01:00
return classv . param1 . job_id = = instance . param1 . job_id ;
2012-11-18 11:23:22 +01:00
2012-11-19 00:31:03 -08:00
case EVENT_GENERIC :
2012-12-20 11:48:36 +01:00
return instance . str_param1 = = classv . str_param1 ;
2012-11-18 11:23:22 +01:00
2012-11-18 16:30:30 -08:00
}
2012-11-18 11:23:22 +01:00
2012-11-18 16:30:30 -08:00
/**
This should never be reached
*/
2012-12-19 15:56:19 +01:00
debug ( 0 , " Warning: Unreachable code reached in event_match in event.cpp \n " ) ;
2012-11-18 16:30:30 -08:00
return 0 ;
2005-10-06 08:37:08 +10:00
}
2006-01-24 06:40:14 +10:00
/**
Test if specified event is blocked
*/
2012-12-20 11:48:36 +01:00
static int event_is_blocked ( const event_t & e )
2005-12-12 08:21:01 +10:00
{
2013-12-20 17:41:21 -08:00
const block_t * block ;
2012-11-18 16:30:30 -08:00
parser_t & parser = parser_t : : principal_parser ( ) ;
2014-01-15 01:40:40 -08:00
2013-12-20 17:41:21 -08:00
size_t idx = 0 ;
while ( ( block = parser . block_at_index ( idx + + ) ) )
2012-11-18 16:30:30 -08:00
{
2012-12-20 11:48:36 +01:00
if ( event_block_list_blocks_type ( block - > event_blocks , e . type ) )
2012-02-07 21:04:51 -08:00
return true ;
2014-01-15 01:40:40 -08:00
2012-11-18 16:30:30 -08:00
}
2012-12-20 11:48:36 +01:00
return event_block_list_blocks_type ( parser . global_event_blocks , e . type ) ;
2005-12-12 08:21:01 +10:00
}
2012-12-20 11:48:36 +01:00
wcstring event_get_desc ( const event_t & e )
2006-02-02 01:49:11 +10:00
{
2006-06-21 20:07:46 +10:00
2012-11-18 16:30:30 -08:00
wcstring result ;
2012-12-20 11:48:36 +01:00
switch ( e . type )
2012-11-18 16:30:30 -08:00
{
2006-06-21 20:07:46 +10:00
2012-11-19 00:31:03 -08:00
case EVENT_SIGNAL :
2012-12-20 11:48:36 +01:00
result = format_string ( _ ( L " signal handler for %ls (%ls) " ) , sig2wcs ( e . param1 . signal ) , signal_get_desc ( e . param1 . signal ) ) ;
2012-11-19 00:31:03 -08:00
break ;
2012-11-18 11:23:22 +01:00
2012-11-19 00:31:03 -08:00
case EVENT_VARIABLE :
2012-12-20 11:48:36 +01:00
result = format_string ( _ ( L " handler for variable '%ls' " ) , e . str_param1 . c_str ( ) ) ;
2012-11-19 00:31:03 -08:00
break ;
2012-11-18 11:23:22 +01:00
2012-11-19 00:31:03 -08:00
case EVENT_EXIT :
2012-12-20 11:48:36 +01:00
if ( e . param1 . pid > 0 )
2012-11-19 00:31:03 -08:00
{
2012-12-20 11:48:36 +01:00
result = format_string ( _ ( L " exit handler for process %d " ) , e . param1 . pid ) ;
2012-11-19 00:31:03 -08:00
}
else
{
2012-12-20 11:48:36 +01:00
job_t * j = job_get_from_pid ( - e . param1 . pid ) ;
2012-11-19 00:31:03 -08:00
if ( j )
result = format_string ( _ ( L " exit handler for job %d, '%ls' " ) , j - > job_id , j - > command_wcstr ( ) ) ;
else
2012-12-20 11:48:36 +01:00
result = format_string ( _ ( L " exit handler for job with process group %d " ) , - e . param1 . pid ) ;
2012-11-19 00:31:03 -08:00
}
break ;
case EVENT_JOB_ID :
2012-11-18 16:30:30 -08:00
{
2012-12-20 11:48:36 +01:00
job_t * j = job_get ( e . param1 . job_id ) ;
2012-11-18 16:30:30 -08:00
if ( j )
result = format_string ( _ ( L " exit handler for job %d, '%ls' " ) , j - > job_id , j - > command_wcstr ( ) ) ;
else
2012-12-20 11:48:36 +01:00
result = format_string ( _ ( L " exit handler for job with job id %d " ) , e . param1 . job_id ) ;
2012-11-18 11:23:22 +01:00
2012-11-19 00:31:03 -08:00
break ;
}
2012-11-18 11:23:22 +01:00
2012-11-19 00:31:03 -08:00
case EVENT_GENERIC :
2012-12-20 11:48:36 +01:00
result = format_string ( _ ( L " handler for generic event '%ls' " ) , e . str_param1 . c_str ( ) ) ;
2012-11-19 00:31:03 -08:00
break ;
2012-11-18 11:23:22 +01:00
2012-11-19 00:31:03 -08:00
default :
2012-12-22 12:21:31 -08:00
result = format_string ( _ ( L " Unknown event type '0x%x' " ) , e . type ) ;
2012-11-19 00:31:03 -08:00
break ;
2012-11-18 11:23:22 +01:00
2012-11-18 16:30:30 -08:00
}
2012-11-18 11:23:22 +01:00
2012-11-18 16:30:30 -08:00
return result ;
2006-02-02 01:49:11 +10:00
}
2012-02-17 15:58:02 -08:00
#if 0
2012-11-18 16:30:30 -08:00
static void show_all_handlers ( void )
{
2012-02-17 11:36:49 -08:00
puts ( " event handlers: " ) ;
2012-11-18 16:30:30 -08:00
for ( event_list_t : : const_iterator iter = events . begin ( ) ; iter ! = events . end ( ) ; + + iter )
{
2012-02-17 11:36:49 -08:00
const event_t * foo = * iter ;
wcstring tmp = event_get_desc ( foo ) ;
printf ( " handler now %ls \n " , tmp . c_str ( ) ) ;
}
}
2012-02-17 15:58:02 -08:00
# endif
2005-12-12 08:21:01 +10:00
2012-12-22 18:38:28 +01:00
/*
2012-12-22 12:21:31 -08:00
Give a more condensed description of \ c event compared to \ c event_get_desc .
It includes what function will fire if the \ c event is an event handler .
2012-12-22 18:38:28 +01:00
*/
2012-12-22 12:21:31 -08:00
static wcstring event_desc_compact ( const event_t & event )
{
wcstring res ;
wchar_t const * temp ;
int sig ;
switch ( event . type )
{
case EVENT_ANY :
res = L " EVENT_ANY " ;
break ;
case EVENT_VARIABLE :
if ( event . str_param1 . c_str ( ) )
{
res = format_string ( L " EVENT_VARIABLE($%ls) " , event . str_param1 . c_str ( ) ) ;
}
else
{
res = L " EVENT_VARIABLE([any]) " ;
}
break ;
case EVENT_SIGNAL :
sig = event . param1 . signal ;
if ( sig = = EVENT_ANY_SIGNAL )
{
temp = L " [all signals] " ;
}
else if ( sig = = 0 )
{
temp = L " not set " ;
}
else
{
temp = sig2wcs ( sig ) ;
}
res = format_string ( L " EVENT_SIGNAL(%ls) " , temp ) ;
break ;
case EVENT_EXIT :
if ( event . param1 . pid = = EVENT_ANY_PID )
{
res = wcstring ( L " EVENT_EXIT([all child processes]) " ) ;
}
else if ( event . param1 . pid > 0 )
{
res = format_string ( L " EVENT_EXIT(pid %d) " , event . param1 . pid ) ;
}
else
{
job_t * j = job_get_from_pid ( - event . param1 . pid ) ;
if ( j )
res = format_string ( L " EVENT_EXIT(jobid %d: \" %ls \" ) " , j - > job_id , j - > command_wcstr ( ) ) ;
else
res = format_string ( L " EVENT_EXIT(pgid %d) " , - event . param1 . pid ) ;
}
break ;
case EVENT_JOB_ID :
{
job_t * j = job_get ( event . param1 . job_id ) ;
if ( j )
res = format_string ( L " EVENT_JOB_ID(job %d: \" %ls \" ) " , j - > job_id , j - > command_wcstr ( ) ) ;
else
res = format_string ( L " EVENT_JOB_ID(jobid %d) " , event . param1 . job_id ) ;
break ;
}
case EVENT_GENERIC :
res = format_string ( L " EVENT_GENERIC(%ls) " , event . str_param1 . c_str ( ) ) ;
break ;
default :
res = format_string ( L " unknown/illegal event(%x) " , event . type ) ;
}
if ( event . function_name . size ( ) )
{
return format_string ( L " %ls: \" %ls \" " , res . c_str ( ) , event . function_name . c_str ( ) ) ;
}
else
{
return res ;
}
2012-12-19 00:32:03 +01:00
}
2012-12-20 11:48:36 +01:00
void event_add_handler ( const event_t & event )
2005-10-06 08:37:08 +10:00
{
2012-11-18 16:30:30 -08:00
event_t * e ;
2005-12-12 08:21:01 +10:00
2012-12-22 12:21:31 -08:00
if ( debug_level > = 3 )
{
2012-12-22 18:38:28 +01:00
wcstring desc = event_desc_compact ( event ) ;
debug ( 3 , " register: %ls \n " , desc . c_str ( ) ) ;
}
2012-12-20 10:52:44 +01:00
2012-12-20 11:48:36 +01:00
e = new event_t ( event ) ;
2012-11-18 11:23:22 +01:00
2012-11-18 16:30:30 -08:00
if ( e - > type = = EVENT_SIGNAL )
{
signal_handle ( e - > param1 . signal , 1 ) ;
}
2005-10-06 08:37:08 +10:00
2012-06-04 14:20:01 -07:00
// Block around updating the events vector
signal_block ( ) ;
events . push_back ( e ) ;
signal_unblock ( ) ;
2005-10-06 08:37:08 +10:00
}
2012-12-22 18:38:28 +01:00
void event_remove ( const event_t & criterion )
2005-10-06 08:37:08 +10:00
{
2012-11-18 16:30:30 -08:00
event_list_t new_list ;
2012-11-18 11:23:22 +01:00
2012-12-22 12:21:31 -08:00
if ( debug_level > = 3 )
{
2012-12-22 18:38:28 +01:00
wcstring desc = event_desc_compact ( criterion ) ;
debug ( 3 , " unregister: %ls \n " , desc . c_str ( ) ) ;
}
2012-11-18 11:23:22 +01:00
2012-11-18 16:30:30 -08:00
/*
Because of concurrency issues ( env_remove could remove an event
that is currently being executed ) , env_remove does not actually
free any events - instead it simply moves all events that should
be removed from the event list to the killme list , and the ones
that shouldn ' t be killed to new_list , and then drops the empty
events - list .
*/
2012-11-18 11:23:22 +01:00
2012-11-18 16:30:30 -08:00
if ( events . empty ( ) )
return ;
2012-11-18 11:23:22 +01:00
2012-12-22 12:40:34 -08:00
for ( size_t i = 0 ; i < events . size ( ) ; i + + )
2012-11-18 11:23:22 +01:00
{
2012-11-18 16:30:30 -08:00
event_t * n = events . at ( i ) ;
2012-12-20 11:48:36 +01:00
if ( event_match ( criterion , * n ) )
2012-11-18 16:30:30 -08:00
{
2011-12-26 22:22:55 -08:00
killme . push_back ( n ) ;
2005-10-06 21:54:16 +10:00
2012-11-18 16:30:30 -08:00
/*
If this event was a signal handler and no other handler handles
the specified signal type , do not handle that type of signal any
more .
*/
if ( n - > type = = EVENT_SIGNAL )
{
2012-02-08 19:02:25 -08:00
event_t e = event_t : : signal_event ( n - > param1 . signal ) ;
2012-12-20 11:48:36 +01:00
if ( event_get ( e , 0 ) = = 1 )
2012-11-18 16:30:30 -08:00
{
signal_handle ( e . param1 . signal , 0 ) ;
}
}
2012-11-18 11:23:22 +01:00
}
2012-11-18 16:30:30 -08:00
else
{
2011-12-26 22:18:16 -08:00
new_list . push_back ( n ) ;
2012-11-18 16:30:30 -08:00
}
2012-11-18 11:23:22 +01:00
}
2012-06-04 14:20:01 -07:00
signal_block ( ) ;
2012-11-18 16:30:30 -08:00
events . swap ( new_list ) ;
2012-06-04 14:20:01 -07:00
signal_unblock ( ) ;
2005-10-06 08:37:08 +10:00
}
2012-12-20 11:48:36 +01:00
int event_get ( const event_t & criterion , std : : vector < event_t * > * out )
2005-10-06 08:37:08 +10:00
{
2012-11-18 16:30:30 -08:00
size_t i ;
int found = 0 ;
2012-11-18 11:23:22 +01:00
2012-11-18 16:30:30 -08:00
if ( events . empty ( ) )
return 0 ;
2012-11-18 11:23:22 +01:00
2012-11-18 16:30:30 -08:00
for ( i = 0 ; i < events . size ( ) ; i + + )
2012-11-18 11:23:22 +01:00
{
2012-11-18 16:30:30 -08:00
event_t * n = events . at ( i ) ;
2012-12-20 11:48:36 +01:00
if ( event_match ( criterion , * n ) )
2012-11-18 16:30:30 -08:00
{
found + + ;
if ( out )
2012-02-07 17:06:45 -08:00
out - > push_back ( n ) ;
2012-11-18 16:30:30 -08:00
}
2012-11-18 11:23:22 +01:00
}
2012-11-18 16:30:30 -08:00
return found ;
2005-10-06 08:37:08 +10:00
}
2012-06-04 14:20:01 -07:00
bool event_is_signal_observed ( int sig )
{
/* We are in a signal handler! Don't allocate memory, etc.
This does what event_match does , except it doesn ' t require passing in an event_t .
*/
size_t i , max = events . size ( ) ;
for ( i = 0 ; i < max ; i + + )
{
const event_t * event = events [ i ] ;
if ( event - > type = = EVENT_ANY )
{
return true ;
}
else if ( event - > type = = EVENT_SIGNAL )
{
2012-11-18 16:30:30 -08:00
if ( event - > param1 . signal = = EVENT_ANY_SIGNAL | | event - > param1 . signal = = sig )
2012-06-04 14:20:01 -07:00
return true ;
}
}
return false ;
}
2005-10-06 08:37:08 +10:00
/**
Free all events in the kill list
*/
static void event_free_kills ( )
{
2011-12-26 22:22:55 -08:00
for_each ( killme . begin ( ) , killme . end ( ) , event_free ) ;
killme . resize ( 0 ) ;
2005-10-06 08:37:08 +10:00
}
/**
Test if the specified event is waiting to be killed
*/
2012-12-20 11:48:36 +01:00
static int event_is_killed ( const event_t & e )
2005-10-06 08:37:08 +10:00
{
2012-12-20 11:48:36 +01:00
return std : : find ( killme . begin ( ) , killme . end ( ) , & e ) ! = killme . end ( ) ;
2012-11-18 11:23:22 +01:00
}
2005-10-06 08:37:08 +10:00
2013-04-03 17:26:02 -07:00
/* Callback for firing (and then deleting) an event */
static void fire_event_callback ( void * arg )
{
ASSERT_IS_MAIN_THREAD ( ) ;
assert ( arg ! = NULL ) ;
event_t * event = static_cast < event_t * > ( arg ) ;
event_fire ( event ) ;
delete event ;
}
2005-10-06 08:37:08 +10:00
/**
Perform the specified event . Since almost all event firings will
2006-07-30 03:31:59 +10:00
not be matched by even a single event handler , we make sure to
optimize the ' no matches ' path . This means that nothing is
allocated / initialized unless needed .
2005-10-06 08:37:08 +10:00
*/
2012-12-20 11:48:36 +01:00
static void event_fire_internal ( const event_t & event )
2005-10-06 08:37:08 +10:00
{
2012-02-17 11:36:49 -08:00
2012-11-18 16:30:30 -08:00
event_list_t fire ;
2012-11-18 11:23:22 +01:00
2012-11-18 16:30:30 -08:00
/*
2012-12-22 12:21:31 -08:00
First we free all events that have been removed , but only if this
invocation of event_fire_internal is not a recursive call .
2012-11-18 16:30:30 -08:00
*/
2012-12-22 12:21:31 -08:00
if ( is_event < = 1 )
event_free_kills ( ) ;
2012-11-18 11:23:22 +01:00
2012-11-18 16:30:30 -08:00
if ( events . empty ( ) )
return ;
2012-11-18 11:23:22 +01:00
/*
2012-11-18 16:30:30 -08:00
Then we iterate over all events , adding events that should be
fired to a second list . We need to do this in a separate step
since an event handler might call event_remove or
event_add_handler , which will change the contents of the \ c
events list .
2012-11-18 11:23:22 +01:00
*/
2012-12-22 12:40:34 -08:00
for ( size_t i = 0 ; i < events . size ( ) ; i + + )
2012-11-18 11:23:22 +01:00
{
2012-11-18 16:30:30 -08:00
event_t * criterion = events . at ( i ) ;
/*
Check if this event is a match
*/
2012-12-20 11:48:36 +01:00
if ( event_match ( * criterion , event ) )
2012-11-18 16:30:30 -08:00
{
2011-12-26 22:51:34 -08:00
fire . push_back ( criterion ) ;
2012-11-18 16:30:30 -08:00
}
2012-11-18 11:23:22 +01:00
}
/*
2012-11-18 16:30:30 -08:00
No matches . Time to return .
2012-11-18 11:23:22 +01:00
*/
2012-11-18 16:30:30 -08:00
if ( fire . empty ( ) )
return ;
2012-11-18 11:23:22 +01:00
2013-04-03 17:26:02 -07:00
if ( signal_is_blocked ( ) )
{
/* Fix for https://github.com/fish-shell/fish-shell/issues/608. Don't run event handlers while signals are blocked. */
event_t * heap_event = new event_t ( event ) ;
input_common_add_callback ( fire_event_callback , heap_event ) ;
return ;
}
2012-11-18 11:23:22 +01:00
/*
2012-11-18 16:30:30 -08:00
Iterate over our list of matching events
2012-11-18 11:23:22 +01:00
*/
2012-11-18 16:30:30 -08:00
2012-12-22 12:40:34 -08:00
for ( size_t i = 0 ; i < fire . size ( ) ; i + + )
2012-11-18 16:30:30 -08:00
{
event_t * criterion = fire . at ( i ) ;
int prev_status ;
/*
Check if this event has been removed , if so , dont fire it
*/
2012-12-20 11:48:36 +01:00
if ( event_is_killed ( * criterion ) )
2012-11-18 16:30:30 -08:00
continue ;
/*
Fire event
*/
wcstring buffer = criterion - > function_name ;
2012-11-18 11:23:22 +01:00
2012-12-22 12:40:34 -08:00
for ( size_t j = 0 ; j < event . arguments . size ( ) ; j + + )
2011-12-27 00:06:07 -08:00
{
2012-12-22 12:40:34 -08:00
wcstring arg_esc = escape_string ( event . arguments . at ( j ) , 1 ) ;
buffer + = L " " ;
buffer + = arg_esc ;
2011-12-27 00:06:07 -08:00
}
2005-10-12 05:23:43 +10:00
2012-12-22 12:21:31 -08:00
// debug( 1, L"Event handler fires command '%ls'", buffer.c_str() );
2012-11-18 11:23:22 +01:00
2012-11-18 16:30:30 -08:00
/*
Event handlers are not part of the main flow of code , so
they are marked as non - interactive
*/
proc_push_interactive ( 0 ) ;
prev_status = proc_get_last_status ( ) ;
2012-01-22 21:40:08 -08:00
parser_t & parser = parser_t : : principal_parser ( ) ;
2012-11-18 11:23:22 +01:00
2012-12-22 18:38:28 +01:00
block_t * block = new event_block_t ( event ) ;
2012-11-18 16:30:30 -08:00
parser . push_block ( block ) ;
parser . eval ( buffer , io_chain_t ( ) , TOP ) ;
parser . pop_block ( ) ;
proc_pop_interactive ( ) ;
proc_set_last_status ( prev_status ) ;
}
/*
Free killed events
*/
2012-12-22 12:21:31 -08:00
if ( is_event < = 1 )
event_free_kills ( ) ;
2012-11-18 11:23:22 +01:00
2005-10-06 08:37:08 +10:00
}
/**
2005-10-15 10:51:26 +10:00
Handle all pending signal events
2005-10-06 08:37:08 +10:00
*/
2005-12-12 08:21:01 +10:00
static void event_fire_delayed ( )
2005-10-06 08:37:08 +10:00
{
2012-11-18 16:30:30 -08:00
/*
If is_event is one , we are running the event - handler non - recursively .
2012-11-18 11:23:22 +01:00
2012-11-18 16:30:30 -08:00
When the event handler has called a piece of code that triggers
another event , we do not want to fire delayed events because of
concurrency problems .
*/
if ( ! blocked . empty ( ) & & is_event = = 1 )
2012-11-18 11:23:22 +01:00
{
2012-11-18 16:30:30 -08:00
event_list_t new_blocked ;
2014-01-12 13:53:59 -08:00
for ( size_t i = 0 ; i < blocked . size ( ) ; i + + )
2012-11-18 16:30:30 -08:00
{
event_t * e = blocked . at ( i ) ;
2012-12-20 11:48:36 +01:00
if ( event_is_blocked ( * e ) )
2012-11-18 16:30:30 -08:00
{
2012-12-20 10:52:44 +01:00
new_blocked . push_back ( new event_t ( * e ) ) ;
2012-11-18 16:30:30 -08:00
}
else
{
2012-12-20 11:48:36 +01:00
event_fire_internal ( * e ) ;
2012-11-18 16:30:30 -08:00
event_free ( e ) ;
}
}
2011-12-26 22:27:58 -08:00
blocked . swap ( new_blocked ) ;
2012-11-18 16:30:30 -08:00
}
2012-11-18 11:23:22 +01:00
2012-12-23 16:37:43 +01:00
int al = active_list ;
while ( sig_list [ al ] . count > 0 )
2012-11-18 16:30:30 -08:00
{
signal_list_t * lst ;
/*
Switch signal lists
*/
2012-12-23 16:37:43 +01:00
sig_list [ 1 - al ] . count = 0 ;
sig_list [ 1 - al ] . overflow = 0 ;
al = 1 - al ;
active_list = al ;
2012-11-18 16:30:30 -08:00
/*
Set up
*/
2012-12-23 16:37:43 +01:00
lst = & sig_list [ 1 - al ] ;
2012-02-08 19:02:25 -08:00
event_t e = event_t : : signal_event ( 0 ) ;
2012-12-22 18:38:28 +01:00
e . arguments . resize ( 1 ) ;
2012-11-18 11:23:22 +01:00
2012-11-18 16:30:30 -08:00
if ( lst - > overflow )
{
debug ( 0 , _ ( L " Signal list overflow. Signals have been ignored. " ) ) ;
}
2012-11-18 11:23:22 +01:00
2012-11-18 16:30:30 -08:00
/*
Send all signals in our private list
*/
for ( int i = 0 ; i < lst - > count ; i + + )
{
e . param1 . signal = lst - > signal [ i ] ;
2012-12-20 10:52:44 +01:00
e . arguments . at ( 0 ) = sig2wcs ( e . param1 . signal ) ;
2012-12-20 11:48:36 +01:00
if ( event_is_blocked ( e ) )
2012-11-18 16:30:30 -08:00
{
2012-12-20 10:52:44 +01:00
blocked . push_back ( new event_t ( e ) ) ;
2012-11-18 16:30:30 -08:00
}
else
{
2012-12-20 11:48:36 +01:00
event_fire_internal ( e ) ;
2012-11-18 16:30:30 -08:00
}
}
2012-11-18 11:23:22 +01:00
2012-11-18 16:30:30 -08:00
}
2005-10-06 08:37:08 +10:00
}
2012-06-04 14:20:01 -07:00
void event_fire_signal ( int signal )
{
/*
This means we are in a signal handler . We must be very
careful not do do anything that could cause a memory
allocation or something else that might be bad when in a
signal handler .
*/
2012-11-18 16:30:30 -08:00
if ( sig_list [ active_list ] . count < SIG_UNHANDLED_MAX )
2012-06-04 14:20:01 -07:00
sig_list [ active_list ] . signal [ sig_list [ active_list ] . count + + ] = signal ;
else
sig_list [ active_list ] . overflow = 1 ;
}
2005-10-06 08:37:08 +10:00
2013-04-03 17:26:02 -07:00
void event_fire ( const event_t * event )
2005-10-06 08:37:08 +10:00
{
2012-11-18 11:23:22 +01:00
2013-04-03 17:26:02 -07:00
if ( event & & event - > type = = EVENT_SIGNAL )
2012-11-18 16:30:30 -08:00
{
2012-06-04 14:20:01 -07:00
event_fire_signal ( event - > param1 . signal ) ;
2012-11-18 16:30:30 -08:00
}
else
{
2012-06-04 14:20:01 -07:00
is_event + + ;
2012-11-18 16:30:30 -08:00
/*
Fire events triggered by signals
*/
event_fire_delayed ( ) ;
2012-11-18 11:23:22 +01:00
2012-11-18 16:30:30 -08:00
if ( event )
{
2012-12-20 11:48:36 +01:00
if ( event_is_blocked ( * event ) )
2012-11-18 16:30:30 -08:00
{
2012-12-20 10:52:44 +01:00
blocked . push_back ( new event_t ( * event ) ) ;
2012-11-18 16:30:30 -08:00
}
else
{
2012-12-20 11:48:36 +01:00
event_fire_internal ( * event ) ;
2012-11-18 16:30:30 -08:00
}
}
2012-06-04 14:20:01 -07:00
is_event - - ;
2012-11-18 16:30:30 -08:00
}
2005-10-06 08:37:08 +10:00
}
void event_init ( )
{
}
void event_destroy ( )
{
2006-02-06 23:45:32 +10:00
2011-12-26 22:18:16 -08:00
for_each ( events . begin ( ) , events . end ( ) , event_free ) ;
2012-06-04 14:20:01 -07:00
events . clear ( ) ;
2012-11-18 11:23:22 +01:00
2011-12-26 22:22:55 -08:00
for_each ( killme . begin ( ) , killme . end ( ) , event_free ) ;
2012-06-04 14:20:01 -07:00
killme . clear ( ) ;
2005-10-06 08:37:08 +10:00
}
2012-11-18 16:30:30 -08:00
void event_free ( event_t * e )
2005-10-06 08:37:08 +10:00
{
2012-11-18 16:30:30 -08:00
CHECK ( e , ) ;
2012-02-08 19:02:25 -08:00
delete e ;
2005-10-06 08:37:08 +10:00
}
2006-05-14 20:16:23 +10:00
2012-12-20 01:11:55 +01:00
void event_fire_generic ( const wchar_t * name , wcstring_list_t * args )
2007-08-20 02:42:30 +10:00
{
2012-11-18 16:30:30 -08:00
CHECK ( name , ) ;
2012-02-08 19:02:25 -08:00
2012-11-18 16:30:30 -08:00
event_t ev ( EVENT_GENERIC ) ;
ev . str_param1 = name ;
2012-12-20 01:11:55 +01:00
if ( args )
2012-12-20 10:52:44 +01:00
ev . arguments = * args ;
2012-11-18 16:30:30 -08:00
event_fire ( & ev ) ;
2007-08-20 02:42:30 +10:00
}
2013-04-13 01:32:07 -07:00
event_t : : event_t ( int t ) : type ( t ) , param1 ( ) , str_param1 ( ) , function_name ( ) , arguments ( )
{
}
event_t : : ~ event_t ( )
{
}
2012-11-18 16:30:30 -08:00
event_t event_t : : signal_event ( int sig )
{
2012-02-08 19:02:25 -08:00
event_t event ( EVENT_SIGNAL ) ;
event . param1 . signal = sig ;
return event ;
}
2007-08-20 02:42:30 +10:00
2012-11-18 16:30:30 -08:00
event_t event_t : : variable_event ( const wcstring & str )
{
2012-02-08 19:02:25 -08:00
event_t event ( EVENT_VARIABLE ) ;
event . str_param1 = str ;
return event ;
}
2012-11-18 16:30:30 -08:00
event_t event_t : : generic_event ( const wcstring & str )
{
2012-02-08 19:02:25 -08:00
event_t event ( EVENT_GENERIC ) ;
event . str_param1 = str ;
return event ;
}
2012-12-22 12:21:31 -08:00