Event handling and job reaping updates

darcs-hash:20051011192343-ac50b-aa3f5ae5e2b34d122f10e3b59ceb6fdd447f4ae3.gz
This commit is contained in:
axel 2005-10-12 05:23:43 +10:00
parent 0a4b983afa
commit 838ba08eaa
17 changed files with 209 additions and 92 deletions

View File

@ -748,7 +748,11 @@ static int builtin_function( wchar_t **argv )
}
,
{
L"on-exit", required_argument, 0, 'x'
L"on-job-exit", required_argument, 0, 'j'
}
,
{
L"on-process-exit", required_argument, 0, 'p'
}
,
{
@ -767,7 +771,7 @@ static int builtin_function( wchar_t **argv )
int opt = wgetopt_long( argc,
argv,
L"bd:s:x:v:",
L"bd:s:j:p:v:",
long_options,
&opt_index );
if( opt == -1 )
@ -848,7 +852,8 @@ static int builtin_function( wchar_t **argv )
break;
}
case 'x':
case 'j':
case 'p':
{
pid_t pid;
wchar_t *end;
@ -864,15 +869,13 @@ static int builtin_function( wchar_t **argv )
woptarg );
res=1;
break;
}
}
e = malloc( sizeof(event_t));
if( !e )
die_mem();
e->type = EVENT_EXIT;
e->pid = pid;
e->pid = (opt=='j'?-1:1)*abs(pid);
e->function_name=0;
al_push( events, e );
break;
@ -2252,7 +2255,7 @@ static int builtin_jobs( wchar_t **argv )
/*
Ignore unconstructed jobs, i.e. ourself.
*/
if( j->constructed )
if( j->constructed /*&& j->skip_notification*/ )
{
if( !found )
{
@ -2269,12 +2272,12 @@ static int builtin_jobs( wchar_t **argv )
found = 1;
sb_printf( sb_out, L"%d\t%d\t", j->job_id, j->pgid );
#ifdef HAVE__PROC_SELF_STAT
sb_printf( sb_out, L"%d\t", cpu_use(j) );
#endif
sb_append2( sb_out, job_is_stopped(j)?L"stopped\t":L"running\t",
// job_is_completed(j)?L"completed\t":L"unfinished\t",
j->command, L"\n", (void *)0 );
}

View File

@ -27,6 +27,7 @@ are inserted into the environment variable <a href="index.html#variables-arrays"
<pre>function ll
ls -l $argv
end
</pre>
will run the \c ls command, using the \c -l option, while passing on any additional files and switches to \c ls.

View File

@ -6,7 +6,7 @@
The <tt>set</tt> builtin causes fish to assign the variable <tt>VARIABLE_NAME</tt> the values <tt>VALUES...</tt>.
\subsection set-description Description
- <tt>-e</tt> or <tt>--erase</tt> causes the specified environment variables to be erased
- <tt>-e</tt> or <tt>--erase</tt> causes the specified environment variable to be erased
- <tt>-g</tt> or <tt>--global</tt> causes the specified environment variable to be made global. If this option is not supplied, the specified variable will dissapear when the current block ends
- <tt>-l</tt> or <tt>--local</tt> forces the specified environment variable to be made local to the current block, even if the variable already exists and is non-local
- <tt>-n</tt> or <tt>--names</tt> List only the names of all defined variables
@ -23,7 +23,7 @@ with the given name will be changed as specified, but it's value will
remain the same. If the variable did not previously exist, it's value
will be an empty string.
If the \c -e or \c --erase option is specified, all the variables
If the \c -e or \c --erase option is specified, the variable
specified by the following arguments will be erased
If a variable is set to more than one value, the variable will be an

74
env.c
View File

@ -194,6 +194,43 @@ static void start_fishd()
sb_destroy( &cmd );
}
static void universal_callback( int type,
const wchar_t *name,
const wchar_t *val )
{
wchar_t *str=0;
switch( type )
{
case SET:
case SET_EXPORT:
str=L"SET";
break;
case ERASE:
str=L"ERASE";
break;
}
if( str )
{
array_list_t arg;
event_t ev;
has_changed=1;
ev.type=EVENT_VARIABLE;
ev.variable=name;
ev.function_name=0;
al_init( &arg );
al_push( &arg, L"VARIABLE" );
al_push( &arg, str );
al_push( &arg, name );
event_fire( &ev, &arg );
al_destroy( &arg );
}
}
void env_init()
{
char **p;
@ -267,7 +304,8 @@ void env_init()
env_universal_init( env_get( L"FISHD_SOKET_DIR"),
env_get( L"USER" ),
&start_fishd );
&start_fishd,
&universal_callback );
}
@ -334,6 +372,7 @@ void env_set( const wchar_t *key,
event_t ev;
array_list_t ev_list;
int is_universal = 0;
if( (var_mode & ENV_USER ) &&
hash_get( &env_read_only, key ) )
@ -367,7 +406,8 @@ void env_set( const wchar_t *key,
export = (var_mode & ENV_EXPORT );
env_universal_set( key, val, export );
is_universal = 1;
}
else
{
@ -424,7 +464,8 @@ void env_set( const wchar_t *key,
export = (var_mode & ENV_EXPORT );
env_universal_set( key, val, export );
is_universal = 1;
done = 1;
}
@ -476,16 +517,22 @@ void env_set( const wchar_t *key,
}
ev.type=EVENT_VARIABLE;
ev.variable = key;
ev.function_name = 0;
if( !is_universal )
{
ev.type=EVENT_VARIABLE;
ev.variable = key;
ev.function_name = 0;
al_init( &ev_list );
al_push( &ev_list, L"VARIABLE" );
al_push( &ev_list, key );
// debug( 1, L"env_set: fire events on variable %ls", key );
event_fire( &ev, &ev_list );
// debug( 1, L"env_set: return from event firing" );
al_destroy( &ev_list );
}
al_init( &ev_list );
al_push( &ev_list, L"VARIABLE" );
al_push( &ev_list, key );
event_fire( &ev, &ev_list );
al_destroy( &ev_list );
}
/**
@ -843,7 +890,7 @@ char **env_export_arr( int recalc)
if( recalc && !proc_had_barrier)
env_universal_barrier();
if( has_changed || env_universal_update )
if( has_changed )
{
array_list_t uni;
hash_table_t vals;
@ -896,7 +943,6 @@ char **env_export_arr( int recalc)
}
export_arr[pos]=0;
has_changed=0;
env_universal_update=0;
}
return export_arr;

View File

@ -45,8 +45,7 @@ static int get_socket_count = 0;
static wchar_t * path;
static wchar_t *user;
static void (*start_fishd)();
int env_universal_update=0;
static void (*external_callback)( int type, const wchar_t *name, const wchar_t *val );
/**
Flag set to 1 when a barrier reply is recieved
@ -149,8 +148,7 @@ static int get_socket( int fork_ok )
Callback function used whenever a new fishd message is recieved
*/
static void callback( int type, const wchar_t *name, const wchar_t *val )
{
{
if( type == BARRIER_REPLY )
{
debug( 3, L"Got barrier reply" );
@ -158,7 +156,8 @@ static void callback( int type, const wchar_t *name, const wchar_t *val )
}
else
{
env_universal_update=1;
if( external_callback )
external_callback( type, name, val );
}
}
@ -173,7 +172,7 @@ static void check_connection()
if( env_universal_server.killme )
{
debug( 3, L"Lost connection to universal variable server." );
debug( 2, L"Lost connection to universal variable server." );
close( env_universal_server.fd );
env_universal_server.fd = -1;
env_universal_server.killme=0;
@ -204,12 +203,17 @@ static void reconnect()
}
void env_universal_init( wchar_t * p, wchar_t *u, void (*sf)() )
void env_universal_init( wchar_t * p,
wchar_t *u,
void (*sf)(),
void (*cb)( int type, const wchar_t *name, const wchar_t *val ))
{
debug( 2, L"env_universal_init()" );
path=p;
user=u;
start_fishd=sf;
external_callback = cb;
env_universal_server.fd = -1;
env_universal_server.killme = 0;
env_universal_server.fd = get_socket(1);

View File

@ -14,11 +14,6 @@
*/
extern connection_t env_universal_server;
/**
Update flag. Set to 1 whenever an update has occured.
*/
extern int env_universal_update;
/**
Initialize the envuni library
*/

View File

@ -163,9 +163,20 @@ void read_message( connection_t *src )
{
if( res == L'\n' )
{
parse_message( (wchar_t *)src->input.buff, src );
/*
Before calling parse_message, we must empty reset
everything, since the callback function could
potentially call read_message.
*/
wchar_t *msg = wcsdup( (wchar_t *)src->input.buff );
sb_clear( &src->input );
memset (&src->wstate, '\0', sizeof (mbstate_t));
memset (&src->wstate, '\0', sizeof (mbstate_t));
parse_message( msg, src );
free( msg );
}
else
{
@ -203,7 +214,7 @@ static void parse_message( wchar_t *msg,
connection_t *src )
{
debug( 2, L"parse_message( %ls );", msg );
if( msg[0] == L'#' )
return;

29
event.c
View File

@ -280,7 +280,7 @@ static void event_fire_internal( event_t *event, array_list_t *arguments )
for( i=0; i<al_get_count( events ); i++ )
{
event_t *criterion = (event_t *)al_get( events, i );
/*
Check if this event is a match
*/
@ -329,8 +329,16 @@ static void event_fire_internal( event_t *event, array_list_t *arguments )
sb_append( b, arg_esc );
free( arg_esc );
}
// debug( 1, L"Event handler fires command '%ls'", (wchar_t *)b->buff );
is_subshell=1;
is_interactive=1;
eval( (wchar_t *)b->buff, 0, TOP );
is_subshell=0;
is_interactive=1;
}
if( b )
@ -349,7 +357,7 @@ static void event_fire_internal( event_t *event, array_list_t *arguments )
Free killed events
*/
event_free_kills();
}
/**
@ -394,9 +402,8 @@ static void event_fire_signal_events()
void event_fire( event_t *event, array_list_t *arguments )
{
int is_event_old = is_event;
is_event=1;
//int is_event_old = is_event;
is_event++;
if( event && (event->type == EVENT_SIGNAL) )
{
@ -411,20 +418,16 @@ void event_fire( event_t *event, array_list_t *arguments )
else
sig_list[active_list].overflow=1;
return;
}
}
else
{
event_fire_signal_events();
if( event )
event_fire_internal( event, arguments );
}
is_event = is_event_old;
if( !is_event )
job_do_notification();
is_event--;// = is_event_old;
}

3
exec.c
View File

@ -548,8 +548,7 @@ static int internal_exec_helper( const wchar_t *def,
buff->out_buffer->used );
*/
io_untransmogrify( io, io_internal );
if( !is_event )
job_do_notification();
job_reap( 0 );
is_block=is_block_old;
return res;
}

View File

@ -857,7 +857,7 @@ static void init()
env_universal_init( 0, 0, 0);
env_universal_init( 0, 0, 0, 0);
input_common_init( &interrupt_handler );
sigemptyset( & act.sa_mask );

View File

@ -1244,7 +1244,7 @@ static void add_vi_bindings()
static int interrupt_handler()
{
if( job_do_notification() )
if( job_reap( 1 ) )
repaint();
if( reader_interupted() )
{
@ -1256,7 +1256,7 @@ static int interrupt_handler()
int input_init()
{
wchar_t *fn;
input_common_init( &interrupt_handler );
if( setupterm( 0, STDOUT_FILENO, 0) == ERR )

View File

@ -116,6 +116,7 @@ static wint_t readb()
{
debug( 3, L"Wake up on universal variable event" );
env_universal_read_all();
debug( 3, L"Return R_NULL" );
return R_NULL;
}
}

1
main.c
View File

@ -289,7 +289,6 @@ int main( int argc, char **argv )
{
eval( L"fish_on_exit", 0, TOP );
}
job_do_notification();
reader_pop_current_filename();

View File

@ -1680,8 +1680,8 @@ static void eval_job( tokenizer *tok )
j->command=0;
j->fg=1;
j->constructed=0;
j->skip_notification = is_subshell;
j->skip_notification = is_subshell || is_block || is_event || (!is_interactive);
proc_had_barrier=0;
if( is_interactive )
@ -1694,7 +1694,7 @@ static void eval_job( tokenizer *tok )
break;
}
}
j->first_process = calloc( 1, sizeof( process_t ) );
/* Copy the command name */
@ -1773,13 +1773,8 @@ static void eval_job( tokenizer *tok )
if( (!current_block->if_state) &&
(!current_block->skip) )
{
/*
We need to call job_do_notification,
since this is the function which sets
the status of the last process to exit
*/
// debug( 2, L"Result of if block is %d\n", proc_get_last_status() );
current_block->skip = proc_get_last_status()!= 0;
current_block->if_state++;
}
@ -1824,6 +1819,8 @@ static void eval_job( tokenizer *tok )
}
}
job_reap( 0 );
// debug( 2, L"end eval_job()\n" );
}
@ -1835,16 +1832,16 @@ int eval( const wchar_t *cmd, io_data_t *io, int block_type )
block_t *start_current_block = current_block;
io_data_t *prev_io = block_io;
block_io = io;
debug( 2, L"Eval command %ls", cmd );
job_reap( 0 );
if( !cmd )
{
debug( 1,
L"Tried to evaluate null pointer\n" BUGREPORT_MSG,
PACKAGE_BUGREPORT );
return 1;
}
@ -1945,6 +1942,7 @@ int eval( const wchar_t *cmd, io_data_t *io, int block_type )
eval_level--;
job_reap( 0 );
return code;
}

85
proc.c
View File

@ -47,6 +47,7 @@ Some of the code in this file is based on code from the Glibc manual.
#include "env.h"
#include "parser.h"
#include "signal.h"
#include "event.h"
/**
Size of message buffer
@ -460,33 +461,82 @@ static void format_job_info( const job_t *j, const wchar_t *status )
fwprintf (stdout, L"\n" );
}
int job_do_notification()
static void fire_process_event( const wchar_t *msg, pid_t pid, int status )
{
static event_t ev;
static array_list_t event_arg;
static string_buffer_t event_pid, event_status;
static int init=0;
event_t e;
if( !init )
{
al_init( &event_arg );
sb_init( &event_pid );
sb_init( &event_status );
init=1;
}
e.function_name=0;
ev.type=EVENT_EXIT;
ev.pid = pid;
al_push( &event_arg, msg );
sb_printf( &event_pid, L"%d", pid );
al_push( &event_arg, event_pid.buff );
sb_printf( &event_status, L"%d", status );
al_push( &event_arg, event_status.buff );
event_fire( &ev, &event_arg );
al_truncate( &event_arg, 0 );
sb_clear( &event_pid );
sb_clear( &event_status );
}
int job_reap( int interactive )
{
job_t *j, *jnext;
int found=0;
static int locked = 0;
locked++;
if( locked>1 )
return;
for( j=first_job; j; j=jnext)
{
process_t *p;
jnext = j->next;
if( (!j->skip_notification) && (!interactive) )
{
continue;
}
for( p=j->first_process; p; p=p->next )
{
int s;
if( !p->completed )
continue;
if( p->type )
continue;
if( !p->pid )
continue;
if( WIFSIGNALED(p->status) )
fire_process_event( L"PROCESS_EXIT", p->pid, WEXITSTATUS( s ) );
s = p->status;
if( WIFSIGNALED(s) )
{
/*
Ignore signal SIGPIPE.We issue it ourselves to the pipe
writer when the pipe reader dies.
*/
if( WTERMSIG(p->status) != SIGPIPE )
if( WTERMSIG(s) != SIGPIPE )
{
int proc_is_job = ((p==j->first_process) && (p->next == 0));
if( proc_is_job )
@ -519,40 +569,47 @@ int job_do_notification()
*/
p->status = 0;
}
}
}
}
/*
If all processes have completed, tell the user the job has
completed and delete it from the active job list.
*/
if( job_is_completed(j) ) {
if( job_is_completed( j ) )
{
if( !j->fg && !j->notified )
{
if( !j->skip_notification )
{
format_job_info (j, L"ended");
format_job_info( j, L"ended" );
found=1;
}
}
job_free(j);
fire_process_event( L"JOB_EXIT", -j->pgid, 0 );
}
else if(job_is_stopped (j) && !j->notified) {
else if( job_is_stopped( j ) && !j->notified )
{
/*
Notify the user about newly stopped jobs.
*/
if( !j->skip_notification )
{
format_job_info(j, L"stopped");
format_job_info( j, L"stopped" );
found=1;
}
j->notified = 1;
}
}
if( found )
fflush( stdout );
return found;
locked = 0;
return found;
}

6
proc.h
View File

@ -92,7 +92,7 @@ typedef struct job
*/
int constructed;
/**
Whether the specified job is a part of a subshell or some other form of special job that should not be reported
Whether the specified job is a part of a subshell, event handler or some other form of special job that should not be reported
*/
int skip_notification;
@ -185,8 +185,10 @@ void job_continue( job_t *j, int cont );
/**
Notify user of nog events. Notify the user about stopped or
terminated jobs. Delete terminated jobs from the active job list.
\param interactive whether interactive jobs should be reaped as well
*/
int job_do_notification();
int job_reap( int interactive );
/**
Signal handler for SIGCHLD. Mark any processes with relevant
information.

View File

@ -623,7 +623,6 @@ void reader_write_title()
if( exec_subshell( title, &l ) != -1 )
{
int i;
job_do_notification();
writestr( L"\e]2;" );
for( i=0; i<al_get_count( &l ); i++ )
{
@ -659,7 +658,6 @@ static void write_prompt()
{
if( exec_subshell( data->prompt, &prompt_list ) == -1 )
{
job_do_notification();
/* If executing the prompt fails, make sure we at least don't print any junk */
al_foreach( &prompt_list, (void (*)(const void *))&free );
al_destroy( &prompt_list );
@ -2154,7 +2152,7 @@ void reader_run_command( wchar_t *cmd )
term_donate();
eval( cmd, 0, TOP );
job_do_notification();
job_reap( 1 );
term_steal();