Event handling and job reaping updates
darcs-hash:20051011192343-ac50b-aa3f5ae5e2b34d122f10e3b59ceb6fdd447f4ae3.gz
This commit is contained in:
parent
0a4b983afa
commit
838ba08eaa
19
builtin.c
19
builtin.c
@ -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;
|
||||
@ -866,13 +871,11 @@ static int builtin_function( wchar_t **argv )
|
||||
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 )
|
||||
{
|
||||
@ -2270,11 +2273,11 @@ static int builtin_jobs( wchar_t **argv )
|
||||
|
||||
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 );
|
||||
|
||||
}
|
||||
|
@ -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.
|
||||
|
@ -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
|
||||
|
52
env.c
52
env.c
@ -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,6 +406,7 @@ void env_set( const wchar_t *key,
|
||||
export = (var_mode & ENV_EXPORT );
|
||||
|
||||
env_universal_set( key, val, export );
|
||||
is_universal = 1;
|
||||
|
||||
}
|
||||
else
|
||||
@ -424,6 +464,7 @@ void env_set( const wchar_t *key,
|
||||
export = (var_mode & ENV_EXPORT );
|
||||
|
||||
env_universal_set( key, val, export );
|
||||
is_universal = 1;
|
||||
|
||||
done = 1;
|
||||
|
||||
@ -476,6 +517,8 @@ void env_set( const wchar_t *key,
|
||||
|
||||
}
|
||||
|
||||
if( !is_universal )
|
||||
{
|
||||
ev.type=EVENT_VARIABLE;
|
||||
ev.variable = key;
|
||||
ev.function_name = 0;
|
||||
@ -484,10 +527,14 @@ void env_set( const wchar_t *key,
|
||||
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 );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
Attempt to remove/free the specified key/value pair from the
|
||||
specified hash table.
|
||||
@ -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;
|
||||
|
@ -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
|
||||
@ -150,7 +149,6 @@ static int get_socket( int fork_ok )
|
||||
*/
|
||||
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);
|
||||
|
@ -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
|
||||
*/
|
||||
|
@ -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));
|
||||
|
||||
|
||||
parse_message( msg, src );
|
||||
free( msg );
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
|
19
event.c
19
event.c
@ -330,7 +330,15 @@ static void event_fire_internal( event_t *event, array_list_t *arguments )
|
||||
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 )
|
||||
@ -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,7 +418,6 @@ void event_fire( event_t *event, array_list_t *arguments )
|
||||
else
|
||||
sig_list[active_list].overflow=1;
|
||||
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -421,10 +427,7 @@ void event_fire( event_t *event, array_list_t *arguments )
|
||||
event_fire_internal( event, arguments );
|
||||
|
||||
}
|
||||
is_event = is_event_old;
|
||||
|
||||
if( !is_event )
|
||||
job_do_notification();
|
||||
is_event--;// = is_event_old;
|
||||
}
|
||||
|
||||
|
||||
|
3
exec.c
3
exec.c
@ -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;
|
||||
}
|
||||
|
@ -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 );
|
||||
|
2
input.c
2
input.c
@ -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() )
|
||||
{
|
||||
|
@ -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
1
main.c
@ -289,7 +289,6 @@ int main( int argc, char **argv )
|
||||
{
|
||||
eval( L"fish_on_exit", 0, TOP );
|
||||
}
|
||||
job_do_notification();
|
||||
|
||||
reader_pop_current_filename();
|
||||
|
||||
|
14
parser.c
14
parser.c
@ -1680,7 +1680,7 @@ 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;
|
||||
|
||||
@ -1773,11 +1773,6 @@ 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;
|
||||
@ -1824,6 +1819,8 @@ static void eval_job( tokenizer *tok )
|
||||
}
|
||||
}
|
||||
|
||||
job_reap( 0 );
|
||||
|
||||
// debug( 2, L"end eval_job()\n" );
|
||||
}
|
||||
|
||||
@ -1838,13 +1835,13 @@ int eval( const wchar_t *cmd, io_data_t *io, int block_type )
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
71
proc.c
71
proc.c
@ -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 )
|
||||
if( !p->pid )
|
||||
continue;
|
||||
|
||||
fire_process_event( L"PROCESS_EXIT", p->pid, WEXITSTATUS( s ) );
|
||||
s = p->status;
|
||||
|
||||
if( WIFSIGNALED(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 )
|
||||
@ -526,7 +576,8 @@ int job_do_notification()
|
||||
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 )
|
||||
@ -536,8 +587,11 @@ int job_do_notification()
|
||||
}
|
||||
}
|
||||
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.
|
||||
*/
|
||||
@ -549,10 +603,13 @@ int job_do_notification()
|
||||
j->notified = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if( found )
|
||||
fflush( stdout );
|
||||
return found;
|
||||
|
||||
locked = 0;
|
||||
|
||||
return found;
|
||||
}
|
||||
|
||||
|
||||
|
6
proc.h
6
proc.h
@ -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.
|
||||
|
4
reader.c
4
reader.c
@ -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();
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user