Rename the 'terminal' flag to 'job_control', make sure fg and bg only considers jobs under job control and make it configurable which jobs are put under job control using the status builtin. Also add an option to the status builtin to print a stack trace.

darcs-hash:20060130175426-ac50b-46fb79797284cb600c67cb19462b53761446f00a.gz
This commit is contained in:
axel 2006-01-31 03:54:26 +10:00
parent 1c6f685522
commit f59e9baab9
6 changed files with 119 additions and 53 deletions

View file

@ -1668,6 +1668,7 @@ static int builtin_status( wchar_t **argv )
SUBST,
BLOCK,
INTERACTIVE,
STACK_TRACE,
LOGIN
}
;
@ -1700,6 +1701,22 @@ static int builtin_status( wchar_t **argv )
L"is-login", no_argument, 0, 'l'
}
,
{
L"full-job-control", no_argument, 0, 'f'
}
,
{
L"interactive-job-control", no_argument, 0, 'I'
}
,
{
L"no-job-control", no_argument, 0, 'n'
}
,
{
L"print-stack-trace", no_argument, 0, 't'
}
,
{
0, 0, 0, 0
}
@ -1712,7 +1729,7 @@ static int builtin_status( wchar_t **argv )
int opt = wgetopt_long( argc,
argv,
L"hcbil",
L"hcbilfInt",
long_options,
&opt_index );
if( opt == -1 )
@ -1751,6 +1768,22 @@ static int builtin_status( wchar_t **argv )
mode = LOGIN;
break;
case 'f':
job_control_mode = JOB_CONTROL_ALL;
break;
case 'I':
job_control_mode = JOB_CONTROL_INTERACTIVE;
break;
case 'n':
job_control_mode = JOB_CONTROL_NONE;
break;
case 't':
mode = STACK_TRACE;
break;
case '?':
builtin_print_help( argv[0], sb_err );
@ -1773,7 +1806,13 @@ static int builtin_status( wchar_t **argv )
case LOGIN:
return !is_login;
case STACK_TRACE:
{
parser_stack_trace( current_block, sb_out );
break;
}
}
return 0;
@ -2047,7 +2086,7 @@ static int builtin_fg( wchar_t **argv )
*/
for( j=first_job; j; j=j->next )
{
if( j->constructed && (!job_is_completed(j)) && (job_is_stopped(j) || !j->fg))
if( j->constructed && (!job_is_completed(j)) && ( (job_is_stopped(j) || !j->fg) && (j->job_control)))
break;
}
if( !j )
@ -2098,6 +2137,17 @@ static int builtin_fg( wchar_t **argv )
pid );
builtin_print_help( argv[0], sb_err );
}
if( !j->job_control )
{
sb_printf( sb_err,
_( L"%ls: Can't put job %d, '%ls' to foreground because it is not under job control\n" ),
argv[0],
pid,
j->command );
builtin_print_help( argv[0], sb_err );
j=0;
}
}
if( j )
@ -2150,6 +2200,16 @@ static int send_to_bg( job_t *j, const wchar_t *name )
builtin_print_help( L"bg", sb_err );
return 1;
}
else if( !j->job_control )
{
sb_printf( sb_err,
_( L"%ls: Can't put job %d, '%ls' to background because it is not under job control\n" ),
L"bg",
j->job_id,
j->command );
builtin_print_help( L"bg", sb_err );
return 1;
}
else
{
sb_printf( sb_err,
@ -2176,7 +2236,7 @@ static int builtin_bg( wchar_t **argv )
job_t *j;
for( j=first_job; j; j=j->next )
{
if( job_is_stopped(j) )
if( job_is_stopped(j) && j->job_control && (!job_is_completed(j)) )
break;
}

16
exec.c
View file

@ -393,7 +393,7 @@ static int setup_child_process( job_t *j, process_t *p )
{
int res;
if( j->terminal )
if( j->job_control )
{
pid_t pid;
/*
@ -602,7 +602,7 @@ static void internal_exec_helper( const wchar_t *def,
static int handle_new_child( job_t *j, process_t *p )
{
if( j->terminal )
if( j->job_control )
{
int new_pgid=0;
@ -636,18 +636,6 @@ static int handle_new_child( job_t *j, process_t *p )
return -1;
}
}
if( j->fg && new_pgid)
{
if( tcsetpgrp (0, j->pgid) )
{
debug( 1, _( L"Could not send job %d ('%ls') to foreground" ),
j->job_id,
j->command );
wperror( L"tcsetpgrp" );
return -1;
}
}
}
else
{

View file

@ -1031,7 +1031,7 @@ int eval_args( const wchar_t *line, array_list_t *args )
return 1;
}
static void parser_stack_trace( block_t *b, string_buffer_t *buff)
void parser_stack_trace( block_t *b, string_buffer_t *buff)
{
if( !b )
return;
@ -1363,7 +1363,7 @@ static void parse_job_main_loop( process_t *p,
case TOK_BACKGROUND:
j->fg = 0;
j->terminal=0;
case TOK_END:
{
p->argv = list_to_char_arr( args );
@ -2183,7 +2183,6 @@ static void eval_job( tokenizer *tok )
j->fg=1;
j->constructed=0;
j->skip_notification = is_subshell || is_block || is_event || (!is_interactive);
j->terminal = is_interactive && !is_subshell;
current_block->job = j;

View file

@ -348,5 +348,10 @@ int parser_is_help( wchar_t *s, int min_match );
*/
const wchar_t *parser_current_filename();
/**
Write a stack trace starting at the specified block to the specified string_buffer_t
*/
void parser_stack_trace( block_t *b, string_buffer_t *buff);
#endif

60
proc.c
View file

@ -83,6 +83,7 @@ int is_login=0;
int is_event=0;
int proc_had_barrier;
pid_t proc_last_bg_pid = 0;
int job_control_mode = JOB_CONTROL_INTERACTIVE;
/**
The event variable used to send all process event
@ -229,6 +230,10 @@ job_t *job_create()
res->next = first_job;
res->job_id = free_id;
first_job = res;
res->job_control = (job_control_mode==JOB_CONTROL_ALL) ||
((job_control_mode == JOB_CONTROL_INTERACTIVE) && (is_interactive));
// if( res->job_id > 2 )
// fwprintf( stderr, L"Create job %d\n", res->job_id );
return res;
@ -875,37 +880,34 @@ void job_continue (job_t *j, int cont)
if( !job_is_completed( j ) )
{
if( j->terminal )
{
if( j->job_control && j->fg )
{
/* Put the job into the foreground. */
if( j->fg )
signal_block();
if( tcsetpgrp (0, j->pgid) )
{
signal_block();
if( tcsetpgrp (0, j->pgid) )
{
debug( 1,
_( L"Could not send job %d ('%ls') to foreground" ),
j->job_id,
j->command );
wperror( L"tcsetpgrp" );
return;
}
if( cont )
{
if( tcsetattr (0, TCSADRAIN, &j->tmodes))
{
debug( 1,
_( L"Could not send job %d ('%ls') to foreground" ),
j->job_id,
j->command );
wperror( L"tcsetattr" );
return;
}
}
signal_unblock();
debug( 1,
_( L"Could not send job %d ('%ls') to foreground" ),
j->job_id,
j->command );
wperror( L"tcsetpgrp" );
return;
}
if( cont )
{
if( tcsetattr (0, TCSADRAIN, &j->tmodes))
{
debug( 1,
_( L"Could not send job %d ('%ls') to foreground" ),
j->job_id,
j->command );
wperror( L"tcsetattr" );
return;
}
}
signal_unblock();
}
/*
@ -1005,7 +1007,7 @@ void job_continue (job_t *j, int cont)
/*
Put the shell back in the foreground.
*/
if( j->terminal )
if( j->job_control && j->fg )
{
signal_block();
if( tcsetpgrp (0, getpid()) )

18
proc.h
View file

@ -48,6 +48,13 @@ enum
}
;
enum
{
JOB_CONTROL_ALL,
JOB_CONTROL_INTERACTIVE,
JOB_CONTROL_NONE,
}
;
/**
A structure representing a single fish process. Contains variables
@ -156,9 +163,9 @@ typedef struct job
/** Skip executing this job. This flag is set by the short-circut builtins, i.e. and and or */
int skip;
/** Whether this job wants to have control of the terminal when it is in the foreground */
int terminal;
/** Whether the job is under job control */
int job_control;
/** Pointer to the next job */
struct job *next;
}
@ -216,6 +223,11 @@ extern int proc_had_barrier;
*/
extern pid_t proc_last_bg_pid;
/**
Can be one of JOB_CONTROL_ALL, JOB_CONTROL_INTERACTIVE and JOB_CONTROL_NONE
*/
extern int job_control_mode;
/**
Sets the status of the last process to exit
*/