aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--builtin.c23
-rw-r--r--doc_src/function.txt1
-rw-r--r--doc_src/set.txt4
-rw-r--r--env.c74
-rw-r--r--env_universal.c18
-rw-r--r--env_universal.h5
-rw-r--r--env_universal_common.c17
-rw-r--r--event.c29
-rw-r--r--exec.c3
-rw-r--r--fish_pager.c2
-rw-r--r--input.c4
-rw-r--r--input_common.c1
-rw-r--r--main.c1
-rw-r--r--parser.c24
-rw-r--r--proc.c85
-rw-r--r--proc.h6
-rw-r--r--reader.c4
17 files changed, 209 insertions, 92 deletions
diff --git a/builtin.c b/builtin.c
index f621611a..394231b9 100644
--- a/builtin.c
+++ b/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;
@@ -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 );
}
diff --git a/doc_src/function.txt b/doc_src/function.txt
index 4eb555c9..085072ef 100644
--- a/doc_src/function.txt
+++ b/doc_src/function.txt
@@ -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.
diff --git a/doc_src/set.txt b/doc_src/set.txt
index c06e62fa..fdcfc350 100644
--- a/doc_src/set.txt
+++ b/doc_src/set.txt
@@ -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
diff --git a/env.c b/env.c
index e5a38dd3..8ffa9565 100644
--- a/env.c
+++ b/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,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;
diff --git a/env_universal.c b/env_universal.c
index bb03c7fa..9e9d8839 100644
--- a/env_universal.c
+++ b/env_universal.c
@@ -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);
diff --git a/env_universal.h b/env_universal.h
index 0b42bb72..54923554 100644
--- a/env_universal.h
+++ b/env_universal.h
@@ -15,11 +15,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
*/
void env_universal_init();
diff --git a/env_universal_common.c b/env_universal_common.c
index d4a31fcd..226859f1 100644
--- a/env_universal_common.c
+++ b/env_universal_common.c
@@ -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;
diff --git a/event.c b/event.c
index 66540657..47d93c00 100644
--- a/event.c
+++ b/event.c
@@ -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;
}
diff --git a/exec.c b/exec.c
index 90b07393..dc0ca1ee 100644
--- a/exec.c
+++ b/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;
}
diff --git a/fish_pager.c b/fish_pager.c
index d200205d..c7ebb49a 100644
--- a/fish_pager.c
+++ b/fish_pager.c
@@ -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 );
diff --git a/input.c b/input.c
index 41578ae2..9871bb85 100644
--- a/input.c
+++ b/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() )
{
@@ -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 )
diff --git a/input_common.c b/input_common.c
index 55d9580c..908dfc72 100644
--- a/input_common.c
+++ b/input_common.c
@@ -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;
}
}
diff --git a/main.c b/main.c
index 88f671db..a899d081 100644
--- a/main.c
+++ b/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();
diff --git a/parser.c b/parser.c
index b12c358d..17ce457a 100644
--- a/parser.c
+++ b/parser.c
@@ -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;
}
diff --git a/proc.c b/proc.c
index 0e73f518..1389c6cc 100644
--- a/proc.c
+++ b/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 )
- 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;
}
diff --git a/proc.h b/proc.h
index 9f8e85d6..9c11a386 100644
--- a/proc.h
+++ b/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.
diff --git a/reader.c b/reader.c
index 0807cce9..2b283865 100644
--- a/reader.c
+++ b/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();