aboutsummaryrefslogtreecommitdiffhomepage
path: root/proc.cpp
diff options
context:
space:
mode:
authorGravatar ridiculousfish <corydoras@ridiculousfish.com>2012-11-18 16:30:30 -0800
committerGravatar ridiculousfish <corydoras@ridiculousfish.com>2012-11-18 16:30:30 -0800
commit9992b8eb0e3366ff8a3948aa0b66a19c3c12c737 (patch)
tree6dda0fef85812016fbba9ea067c9d586092b506d /proc.cpp
parentbab69f26724028d16054a3daf5c78aad7c67bb2d (diff)
Apply new indentation, brace, and whitespace style
Diffstat (limited to 'proc.cpp')
-rw-r--r--proc.cpp1748
1 files changed, 877 insertions, 871 deletions
diff --git a/proc.cpp b/proc.cpp
index 7e6cb1a1..9a1a0cdc 100644
--- a/proc.cpp
+++ b/proc.cpp
@@ -7,7 +7,7 @@ will call proc to create representations of the running jobs as
needed.
Some of the code in this file is based on code from the Glibc manual.
-
+
*/
#include "config.h"
@@ -75,7 +75,7 @@ Some of the code in this file is based on code from the Glibc manual.
#include "output.h"
/**
- Size of message buffer
+ Size of message buffer
*/
#define MESS_SIZE 256
@@ -84,13 +84,13 @@ Some of the code in this file is based on code from the Glibc manual.
*/
#define BUFFER_SIZE 4096
-/**
- Status of last process to exit
+/**
+ Status of last process to exit
*/
static int last_status=0;
/**
- Signal flag
+ Signal flag
*/
static sig_atomic_t got_signal=0;
@@ -106,12 +106,14 @@ void job_iterator_t::reset()
this->end = job_list->end();
}
-job_iterator_t::job_iterator_t(job_list_t &jobs) : job_list(&jobs) {
+job_iterator_t::job_iterator_t(job_list_t &jobs) : job_list(&jobs)
+{
this->reset();
}
-job_iterator_t::job_iterator_t() : job_list(&parser_t::principal_parser().job_list()) {
+job_iterator_t::job_iterator_t() : job_list(&parser_t::principal_parser().job_list())
+{
this->reset();
}
@@ -129,17 +131,20 @@ static int is_interactive = -1;
static bool proc_had_barrier = false;
-int get_is_interactive(void) {
+int get_is_interactive(void)
+{
ASSERT_IS_MAIN_THREAD();
return is_interactive;
}
-bool get_proc_had_barrier() {
+bool get_proc_had_barrier()
+{
ASSERT_IS_MAIN_THREAD();
return proc_had_barrier;
}
-void set_proc_had_barrier(bool flag) {
+void set_proc_had_barrier(bool flag)
+{
ASSERT_IS_MAIN_THREAD();
proc_had_barrier = flag;
}
@@ -156,15 +161,15 @@ static std::vector<int> interactive_stack;
void proc_init()
{
- proc_push_interactive( 0 );
+ proc_push_interactive(0);
event.arguments.reset(new wcstring_list_t);
}
/**
- Remove job from list of jobs
+ Remove job from list of jobs
*/
-static int job_remove( job_t *j )
+static int job_remove(job_t *j)
{
ASSERT_IS_MAIN_THREAD();
return parser_t::principal_parser().job_remove(j);
@@ -181,9 +186,9 @@ void job_promote(job_t *job)
Remove job from the job list and free all memory associated with
it.
*/
-void job_free( job_t * j )
+void job_free(job_t * j)
{
- job_remove( j );
+ job_remove(j);
delete j;
}
@@ -191,22 +196,22 @@ void proc_destroy()
{
event.arguments.reset(NULL);
job_list_t &jobs = parser_t::principal_parser().job_list();
- while( ! jobs.empty() )
- {
- job_t *job = jobs.front();
- debug( 2, L"freeing leaked job %ls", job->command_wcstr() );
- job_free( job );
- }
+ while (! jobs.empty())
+ {
+ job_t *job = jobs.front();
+ debug(2, L"freeing leaked job %ls", job->command_wcstr());
+ job_free(job);
+ }
}
-void proc_set_last_status( int s )
+void proc_set_last_status(int s)
{
- last_status = s;
+ last_status = s;
}
int proc_get_last_status()
{
- return last_status;
+ return last_status;
}
/* Basic thread safe job IDs. The vector consumed_job_ids has a true value wherever the job ID corresponding to that slot is in use. The job ID corresponding to slot 0 is 1. */
@@ -216,7 +221,7 @@ static std::vector<bool> consumed_job_ids;
job_id_t acquire_job_id(void)
{
scoped_lock lock(job_id_lock);
-
+
/* Find the index of the first 0 slot */
std::vector<bool>::iterator slot = std::find(consumed_job_ids.begin(), consumed_job_ids.end(), false);
if (slot != consumed_job_ids.end())
@@ -238,158 +243,159 @@ void release_job_id(job_id_t jid)
assert(jid > 0);
scoped_lock lock(job_id_lock);
size_t slot = (size_t)(jid - 1), count = consumed_job_ids.size();
-
+
/* Make sure this slot is within our vector and is currently set to consumed */
assert(slot < count);
assert(consumed_job_ids.at(slot) == true);
-
+
/* Clear it and then resize the vector to eliminate unused trailing job IDs */
consumed_job_ids.at(slot) = false;
- while (count--) {
+ while (count--)
+ {
if (consumed_job_ids.at(count))
break;
}
consumed_job_ids.resize(count + 1);
}
-job_t *job_get( job_id_t id )
+job_t *job_get(job_id_t id)
{
ASSERT_IS_MAIN_THREAD();
return parser_t::principal_parser().job_get(id);
}
-job_t *job_get_from_pid( int pid )
+job_t *job_get_from_pid(int pid)
{
ASSERT_IS_MAIN_THREAD();
return parser_t::principal_parser().job_get_from_pid(pid);
}
-/*
- Return true if all processes in the job have stopped or completed.
+/*
+ Return true if all processes in the job have stopped or completed.
\param j the job to test
*/
-int job_is_stopped( const job_t *j )
+int job_is_stopped(const job_t *j)
{
- process_t *p;
-
- for (p = j->first_process; p; p = p->next)
- {
- if (!p->completed && !p->stopped)
- {
- return 0;
- }
- }
- return 1;
+ process_t *p;
+
+ for (p = j->first_process; p; p = p->next)
+ {
+ if (!p->completed && !p->stopped)
+ {
+ return 0;
+ }
+ }
+ return 1;
}
-/*
- Return true if the last processes in the job has completed.
+/*
+ Return true if the last processes in the job has completed.
\param j the job to test
*/
-int job_is_completed( const job_t *j )
+int job_is_completed(const job_t *j)
{
- process_t *p;
- assert(j->first_process != NULL);
- for (p = j->first_process; p->next; p = p->next)
- ;
-
- return p->completed;
-
+ process_t *p;
+ assert(j->first_process != NULL);
+ for (p = j->first_process; p->next; p = p->next)
+ ;
+
+ return p->completed;
+
}
-void job_set_flag( job_t *j, int flag, int set )
+void job_set_flag(job_t *j, int flag, int set)
{
- if( set )
- j->flags |= flag;
- else
- j->flags = j->flags & ((unsigned int)(-1) ^ flag);
+ if (set)
+ j->flags |= flag;
+ else
+ j->flags = j->flags & ((unsigned int)(-1) ^ flag);
}
-int job_get_flag( const job_t *j, int flag )
+int job_get_flag(const job_t *j, int flag)
{
- return j->flags&flag?1:0;
+ return j->flags&flag?1:0;
}
-int job_signal( job_t *j, int signal )
-{
- pid_t my_pid = getpid();
- int res = 0;
-
- if( j->pgid != my_pid )
- {
- res = killpg( j->pgid, SIGHUP );
- }
- else
- {
- process_t *p;
-
- for( p = j->first_process; p; p=p->next )
- {
- if( ! p->completed )
- {
- if( p->pid )
- {
- if( kill( p->pid, SIGHUP ) )
- {
- res = -1;
- break;
- }
- }
- }
- }
-
- }
-
- return res;
+int job_signal(job_t *j, int signal)
+{
+ pid_t my_pid = getpid();
+ int res = 0;
+
+ if (j->pgid != my_pid)
+ {
+ res = killpg(j->pgid, SIGHUP);
+ }
+ else
+ {
+ process_t *p;
+
+ for (p = j->first_process; p; p=p->next)
+ {
+ if (! p->completed)
+ {
+ if (p->pid)
+ {
+ if (kill(p->pid, SIGHUP))
+ {
+ res = -1;
+ break;
+ }
+ }
+ }
+ }
+
+ }
+
+ return res;
}
/**
Store the status of the process pid that was returned by waitpid.
- Return 0 if all went well, nonzero otherwise.
+ Return 0 if all went well, nonzero otherwise.
This is called from a signal handler.
*/
-static void mark_process_status( const job_t *j,
- process_t *p,
- int status )
+static void mark_process_status(const job_t *j,
+ process_t *p,
+ int status)
{
// debug( 0, L"Process %ls %ls", p->argv[0], WIFSTOPPED (status)?L"stopped":(WIFEXITED( status )?L"exited":(WIFSIGNALED( status )?L"signaled to exit":L"BLARGH")) );
- p->status = status;
-
- if (WIFSTOPPED (status))
- {
- p->stopped = 1;
- }
- else if (WIFSIGNALED(status) || WIFEXITED(status))
- {
- p->completed = 1;
- }
- else
- {
- ssize_t ignore;
-
- /* This should never be reached */
- p->completed = 1;
-
- char mess[MESS_SIZE];
- snprintf( mess,
- MESS_SIZE,
- "Process %ld exited abnormally\n",
- (long) p->pid );
- /*
- If write fails, do nothing. We're in a signal handlers error
- handler. If things aren't working properly, it's safer to
- give up.
- */
- ignore = write( 2, mess, strlen(mess) );
- }
+ p->status = status;
+
+ if (WIFSTOPPED(status))
+ {
+ p->stopped = 1;
+ }
+ else if (WIFSIGNALED(status) || WIFEXITED(status))
+ {
+ p->completed = 1;
+ }
+ else
+ {
+ ssize_t ignore;
+
+ /* This should never be reached */
+ p->completed = 1;
+
+ char mess[MESS_SIZE];
+ snprintf(mess,
+ MESS_SIZE,
+ "Process %ld exited abnormally\n",
+ (long) p->pid);
+ /*
+ If write fails, do nothing. We're in a signal handlers error
+ handler. If things aren't working properly, it's safer to
+ give up.
+ */
+ ignore = write(2, mess, strlen(mess));
+ }
}
-void job_mark_process_as_failed( const job_t *job, process_t *p )
+void job_mark_process_as_failed(const job_t *job, process_t *p)
{
/* The given process failed to even lift off (e.g. posix_spawn failed) and so doesn't have a valid pid. Mark it as dead. */
p->completed = 1;
@@ -403,99 +409,99 @@ void job_mark_process_as_failed( const job_t *job, process_t *p )
\param pid the pid of the process whose status changes
\param status the status as returned by wait
*/
-static void handle_child_status( pid_t pid, int status )
+static void handle_child_status(pid_t pid, int status)
{
- bool found_proc = false;
- const job_t *j=0;
- process_t *p=0;
-// char mess[MESS_SIZE];
- /*
- snprintf( mess,
- MESS_SIZE,
- "Process %d\n",
- (int) pid );
- write( 2, mess, strlen(mess ));
- */
+ bool found_proc = false;
+ const job_t *j=0;
+ process_t *p=0;
+// char mess[MESS_SIZE];
+ /*
+ snprintf( mess,
+ MESS_SIZE,
+ "Process %d\n",
+ (int) pid );
+ write( 2, mess, strlen(mess ));
+ */
job_iterator_t jobs;
- while (! found_proc && (j = jobs.next()))
- {
- process_t *prev=0;
- for( p=j->first_process; p; p=p->next )
- {
- if( pid == p->pid )
- {
-/* snprintf( mess,
- MESS_SIZE,
- "Process %d is %ls from job %ls\n",
- (int) pid, p->actual_cmd, j->command );
- write( 2, mess, strlen(mess ));
-*/
-
- mark_process_status ( j, p, status);
- if( p->completed && prev != 0 )
- {
- if( !prev->completed && prev->pid)
- {
- /* snprintf( mess,
- MESS_SIZE,
- "Kill previously uncompleted process %ls (%d)\n",
- prev->actual_cmd,
- prev->pid );
- write( 2, mess, strlen(mess ));
- */
- kill(prev->pid,SIGPIPE);
- }
- }
- found_proc = true;
- break;
- }
- prev = p;
- }
- }
-
-
- if( WIFSIGNALED( status ) &&
- ( WTERMSIG(status)==SIGINT ||
- WTERMSIG(status)==SIGQUIT ) )
- {
- if( !is_interactive_session )
- {
- struct sigaction act;
- sigemptyset( & act.sa_mask );
- act.sa_flags=0;
- act.sa_handler=SIG_DFL;
- sigaction( SIGINT, &act, 0 );
- sigaction( SIGQUIT, &act, 0 );
- kill( getpid(), WTERMSIG(status) );
- }
- else
- {
+ while (! found_proc && (j = jobs.next()))
+ {
+ process_t *prev=0;
+ for (p=j->first_process; p; p=p->next)
+ {
+ if (pid == p->pid)
+ {
+ /* snprintf( mess,
+ MESS_SIZE,
+ "Process %d is %ls from job %ls\n",
+ (int) pid, p->actual_cmd, j->command );
+ write( 2, mess, strlen(mess ));
+ */
+
+ mark_process_status(j, p, status);
+ if (p->completed && prev != 0)
+ {
+ if (!prev->completed && prev->pid)
+ {
+ /* snprintf( mess,
+ MESS_SIZE,
+ "Kill previously uncompleted process %ls (%d)\n",
+ prev->actual_cmd,
+ prev->pid );
+ write( 2, mess, strlen(mess ));
+ */
+ kill(prev->pid,SIGPIPE);
+ }
+ }
+ found_proc = true;
+ break;
+ }
+ prev = p;
+ }
+ }
+
+
+ if (WIFSIGNALED(status) &&
+ (WTERMSIG(status)==SIGINT ||
+ WTERMSIG(status)==SIGQUIT))
+ {
+ if (!is_interactive_session)
+ {
+ struct sigaction act;
+ sigemptyset(& act.sa_mask);
+ act.sa_flags=0;
+ act.sa_handler=SIG_DFL;
+ sigaction(SIGINT, &act, 0);
+ sigaction(SIGQUIT, &act, 0);
+ kill(getpid(), WTERMSIG(status));
+ }
+ else
+ {
/* In an interactive session, tell the principal parser to skip all blocks we're executing so control-C returns control to the user. */
- if( p && found_proc )
- {
+ if (p && found_proc)
+ {
parser_t::skip_all_blocks();
- }
- }
- }
-
- if( !found_proc )
- {
- /*
- A child we lost track of?
-
- There have been bugs in both subshell handling and in
- builtin handling that have caused this previously...
- */
-/* snprintf( mess,
- MESS_SIZE,
- "Process %d not found by %d\n",
- (int) pid, (int)getpid() );
-
- write( 2, mess, strlen(mess ));
-*/
- }
- return;
+ }
+ }
+ }
+
+ if (!found_proc)
+ {
+ /*
+ A child we lost track of?
+
+ There have been bugs in both subshell handling and in
+ builtin handling that have caused this previously...
+ */
+ /* snprintf( mess,
+ MESS_SIZE,
+ "Process %d not found by %d\n",
+ (int) pid, (int)getpid() );
+
+ write( 2, mess, strlen(mess ));
+ */
+ }
+ return;
}
process_t::process_t() :
@@ -517,7 +523,7 @@ process_t::process_t() :
#endif
{
}
-
+
process_t::~process_t()
{
if (this->next != NULL)
@@ -525,17 +531,17 @@ process_t::~process_t()
}
job_t::job_t(job_id_t jobid) :
- command_str(),
- command_narrow(),
- first_process(NULL),
- pgid(0),
- tmodes(),
- job_id(jobid),
- io(),
- flags(0)
+ command_str(),
+ command_narrow(),
+ first_process(NULL),
+ pgid(0),
+ tmodes(),
+ job_id(jobid),
+ io(),
+ flags(0)
{
}
-
+
job_t::~job_t()
{
if (first_process != NULL)
@@ -545,193 +551,193 @@ job_t::~job_t()
}
/* This is called from a signal handler */
-void job_handle_signal ( int signal, siginfo_t *info, void *con )
+void job_handle_signal(int signal, siginfo_t *info, void *con)
{
-
- int status;
- pid_t pid;
- int errno_old = errno;
- got_signal = 1;
+ int status;
+ pid_t pid;
+ int errno_old = errno;
+
+ got_signal = 1;
// write( 2, "got signal\n", 11 );
- while(1)
- {
- switch(pid=waitpid( -1,&status,WUNTRACED|WNOHANG ))
- {
- case 0:
- case -1:
- {
- errno=errno_old;
- return;
- }
- default:
-
- handle_child_status( pid, status );
- break;
- }
- }
- kill( 0, SIGIO );
- errno=errno_old;
+ while (1)
+ {
+ switch (pid=waitpid(-1,&status,WUNTRACED|WNOHANG))
+ {
+ case 0:
+ case -1:
+ {
+ errno=errno_old;
+ return;
+ }
+ default:
+
+ handle_child_status(pid, status);
+ break;
+ }
+ }
+ kill(0, SIGIO);
+ errno=errno_old;
}
-/**
- Format information about job status for the user to look at.
+/**
+ Format information about job status for the user to look at.
\param j the job to test
\param status a string description of the job exit type
*/
-static void format_job_info( const job_t *j, const wchar_t *status )
+static void format_job_info(const job_t *j, const wchar_t *status)
{
- fwprintf (stdout, L"\r" );
- fwprintf (stdout, _( L"Job %d, \'%ls\' has %ls" ), j->job_id, j->command_wcstr(), status);
- fflush( stdout );
- tputs(clr_eol,1,&writeb);
- fwprintf (stdout, L"\n" );
+ fwprintf(stdout, L"\r");
+ fwprintf(stdout, _(L"Job %d, \'%ls\' has %ls"), j->job_id, j->command_wcstr(), status);
+ fflush(stdout);
+ tputs(clr_eol,1,&writeb);
+ fwprintf(stdout, L"\n");
}
-void proc_fire_event( const wchar_t *msg, int type, pid_t pid, int status )
+void proc_fire_event(const wchar_t *msg, int type, pid_t pid, int status)
{
-
- event.type=type;
- event.param1.pid = pid;
-
+
+ event.type=type;
+ event.param1.pid = pid;
+
event.arguments->push_back(msg);
event.arguments->push_back(to_string<int>(pid));
event.arguments->push_back(to_string<int>(status));
- event_fire( &event );
+ event_fire(&event);
event.arguments->resize(0);
-}
+}
-int job_reap( bool interactive )
+int job_reap(bool interactive)
{
ASSERT_IS_MAIN_THREAD();
- job_t *jnext;
- int found=0;
-
- static int locked = 0;
-
- locked++;
-
- /*
- job_read may fire an event handler, we do not want to call
- ourselves recursively (to avoid infinite recursion).
- */
- if( locked>1 )
- return 0;
-
+ job_t *jnext;
+ int found=0;
+
+ static int locked = 0;
+
+ locked++;
+
+ /*
+ job_read may fire an event handler, we do not want to call
+ ourselves recursively (to avoid infinite recursion).
+ */
+ if (locked>1)
+ return 0;
+
job_iterator_t jobs;
jnext = jobs.next();
- while (jnext)
+ while (jnext)
{
job_t *j = jnext;
jnext = jobs.next();
- process_t *p;
-
- /*
- If we are reaping only jobs who do not need status messages
- sent to the console, do not consider reaping jobs that need
- status messages
- */
- if( (!job_get_flag( j, JOB_SKIP_NOTIFICATION ) ) && (!interactive) && (!job_get_flag( j, JOB_FOREGROUND )))
- {
- continue;
- }
-
- for( p=j->first_process; p; p=p->next )
- {
- int s;
- if( !p->completed )
- continue;
-
- if( !p->pid )
- continue;
-
- s = p->status;
-
- proc_fire_event( L"PROCESS_EXIT", EVENT_EXIT, p->pid, ( WIFSIGNALED(s)?-1:WEXITSTATUS( s )) );
-
- if( WIFSIGNALED(s) )
- {
- /*
- Ignore signal SIGPIPE.We issue it ourselves to the pipe
- writer when the pipe reader dies.
- */
- if( WTERMSIG(s) != SIGPIPE )
- {
- int proc_is_job = ((p==j->first_process) && (p->next == 0));
- if( proc_is_job )
- job_set_flag( j, JOB_NOTIFIED, 1 );
- if( !job_get_flag( j, JOB_SKIP_NOTIFICATION ) )
- {
- if( proc_is_job )
- fwprintf( stdout,
- _( L"%ls: Job %d, \'%ls\' terminated by signal %ls (%ls)" ),
- program_name,
- j->job_id,
- j->command_wcstr(),
- sig2wcs(WTERMSIG(p->status)),
- signal_get_desc( WTERMSIG(p->status) ) );
- else
- fwprintf( stdout,
- _( L"%ls: Process %d, \'%ls\' from job %d, \'%ls\' terminated by signal %ls (%ls)" ),
- program_name,
- p->pid,
- p->argv0(),
- j->job_id,
- j->command_wcstr(),
- sig2wcs(WTERMSIG(p->status)),
- signal_get_desc( WTERMSIG(p->status) ) );
- tputs(clr_eol,1,&writeb);
- fwprintf (stdout, L"\n" );
- found=1;
- }
-
- /*
- Clear status so it is not reported more than once
- */
- 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_get_flag( j, JOB_FOREGROUND) && !job_get_flag( j, JOB_NOTIFIED ) && !job_get_flag( j, JOB_SKIP_NOTIFICATION ) )
- {
- format_job_info( j, _( L"ended" ) );
- found=1;
- }
- proc_fire_event( L"JOB_EXIT", EVENT_EXIT, -j->pgid, 0 );
- proc_fire_event( L"JOB_EXIT", EVENT_JOB_ID, j->job_id, 0 );
-
- job_free(j);
- }
- else if( job_is_stopped( j ) && !job_get_flag( j, JOB_NOTIFIED ) )
- {
- /*
- Notify the user about newly stopped jobs.
- */
- if( !job_get_flag( j, JOB_SKIP_NOTIFICATION ) )
- {
- format_job_info( j, _( L"stopped" ) );
- found=1;
- }
- job_set_flag( j, JOB_NOTIFIED, 1 );
- }
- }
-
- if( found )
- fflush( stdout );
-
- locked = 0;
-
- return found;
+ process_t *p;
+
+ /*
+ If we are reaping only jobs who do not need status messages
+ sent to the console, do not consider reaping jobs that need
+ status messages
+ */
+ if ((!job_get_flag(j, JOB_SKIP_NOTIFICATION)) && (!interactive) && (!job_get_flag(j, JOB_FOREGROUND)))
+ {
+ continue;
+ }
+
+ for (p=j->first_process; p; p=p->next)
+ {
+ int s;
+ if (!p->completed)
+ continue;
+
+ if (!p->pid)
+ continue;
+
+ s = p->status;
+
+ proc_fire_event(L"PROCESS_EXIT", EVENT_EXIT, p->pid, (WIFSIGNALED(s)?-1:WEXITSTATUS(s)));
+
+ if (WIFSIGNALED(s))
+ {
+ /*
+ Ignore signal SIGPIPE.We issue it ourselves to the pipe
+ writer when the pipe reader dies.
+ */
+ if (WTERMSIG(s) != SIGPIPE)
+ {
+ int proc_is_job = ((p==j->first_process) && (p->next == 0));
+ if (proc_is_job)
+ job_set_flag(j, JOB_NOTIFIED, 1);
+ if (!job_get_flag(j, JOB_SKIP_NOTIFICATION))
+ {
+ if (proc_is_job)
+ fwprintf(stdout,
+ _(L"%ls: Job %d, \'%ls\' terminated by signal %ls (%ls)"),
+ program_name,
+ j->job_id,
+ j->command_wcstr(),
+ sig2wcs(WTERMSIG(p->status)),
+ signal_get_desc(WTERMSIG(p->status)));
+ else
+ fwprintf(stdout,
+ _(L"%ls: Process %d, \'%ls\' from job %d, \'%ls\' terminated by signal %ls (%ls)"),
+ program_name,
+ p->pid,
+ p->argv0(),
+ j->job_id,
+ j->command_wcstr(),
+ sig2wcs(WTERMSIG(p->status)),
+ signal_get_desc(WTERMSIG(p->status)));
+ tputs(clr_eol,1,&writeb);
+ fwprintf(stdout, L"\n");
+ found=1;
+ }
+
+ /*
+ Clear status so it is not reported more than once
+ */
+ 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_get_flag(j, JOB_FOREGROUND) && !job_get_flag(j, JOB_NOTIFIED) && !job_get_flag(j, JOB_SKIP_NOTIFICATION))
+ {
+ format_job_info(j, _(L"ended"));
+ found=1;
+ }
+ proc_fire_event(L"JOB_EXIT", EVENT_EXIT, -j->pgid, 0);
+ proc_fire_event(L"JOB_EXIT", EVENT_JOB_ID, j->job_id, 0);
+
+ job_free(j);
+ }
+ else if (job_is_stopped(j) && !job_get_flag(j, JOB_NOTIFIED))
+ {
+ /*
+ Notify the user about newly stopped jobs.
+ */
+ if (!job_get_flag(j, JOB_SKIP_NOTIFICATION))
+ {
+ format_job_info(j, _(L"stopped"));
+ found=1;
+ }
+ job_set_flag(j, JOB_NOTIFIED, 1);
+ }
+ }
+
+ if (found)
+ fflush(stdout);
+
+ locked = 0;
+
+ return found;
}
@@ -745,85 +751,85 @@ int job_reap( bool interactive )
/**
Get the CPU time for the specified process
*/
-unsigned long proc_get_jiffies( process_t *p )
+unsigned long proc_get_jiffies(process_t *p)
{
- wchar_t fn[FN_SIZE];
-
- char state;
- int pid, ppid, pgrp,
- session, tty_nr, tpgid,
- exit_signal, processor;
-
- long int cutime, cstime, priority,
- nice, placeholder, itrealvalue,
- rss;
- unsigned long int flags, minflt, cminflt,
- majflt, cmajflt, utime,
- stime, starttime, vsize,
- rlim, startcode, endcode,
- startstack, kstkesp, kstkeip,
- signal, blocked, sigignore,
- sigcatch, wchan, nswap, cnswap;
- char comm[1024];
-
- if( p->pid <= 0 )
- return 0;
-
- swprintf( fn, FN_SIZE, L"/proc/%d/stat", p->pid );
-
- FILE *f = wfopen( fn, "r" );
- if( !f )
- return 0;
-
- int count = fscanf( f,
- "%d %s %c "
- "%d %d %d "
- "%d %d %lu "
-
- "%lu %lu %lu "
- "%lu %lu %lu "
- "%ld %ld %ld "
-
- "%ld %ld %ld "
- "%lu %lu %ld "
- "%lu %lu %lu "
-
- "%lu %lu %lu "
- "%lu %lu %lu "
- "%lu %lu %lu "
-
- "%lu %d %d ",
-
- &pid, comm, &state,
- &ppid, &pgrp, &session,
- &tty_nr, &tpgid, &flags,
-
- &minflt, &cminflt, &majflt,
- &cmajflt, &utime, &stime,
- &cutime, &cstime, &priority,
-
- &nice, &placeholder, &itrealvalue,
- &starttime, &vsize, &rss,
- &rlim, &startcode, &endcode,
-
- &startstack, &kstkesp, &kstkeip,
- &signal, &blocked, &sigignore,
- &sigcatch, &wchan, &nswap,
-
- &cnswap, &exit_signal, &processor
- );
-
- if( count < 17 )
- {
- return 0;
- }
-
- /*
- Don't need to check exit status of fclose on read-only streams
- */
- fclose( f );
- return utime+stime+cutime+cstime;
-
+ wchar_t fn[FN_SIZE];
+
+ char state;
+ int pid, ppid, pgrp,
+ session, tty_nr, tpgid,
+ exit_signal, processor;
+
+ long int cutime, cstime, priority,
+ nice, placeholder, itrealvalue,
+ rss;
+ unsigned long int flags, minflt, cminflt,
+ majflt, cmajflt, utime,
+ stime, starttime, vsize,
+ rlim, startcode, endcode,
+ startstack, kstkesp, kstkeip,
+ signal, blocked, sigignore,
+ sigcatch, wchan, nswap, cnswap;
+ char comm[1024];
+
+ if (p->pid <= 0)
+ return 0;
+
+ swprintf(fn, FN_SIZE, L"/proc/%d/stat", p->pid);
+
+ FILE *f = wfopen(fn, "r");
+ if (!f)
+ return 0;
+
+ int count = fscanf(f,
+ "%d %s %c "
+ "%d %d %d "
+ "%d %d %lu "
+
+ "%lu %lu %lu "
+ "%lu %lu %lu "
+ "%ld %ld %ld "
+
+ "%ld %ld %ld "
+ "%lu %lu %ld "
+ "%lu %lu %lu "
+
+ "%lu %lu %lu "
+ "%lu %lu %lu "
+ "%lu %lu %lu "
+
+ "%lu %d %d ",
+
+ &pid, comm, &state,
+ &ppid, &pgrp, &session,
+ &tty_nr, &tpgid, &flags,
+
+ &minflt, &cminflt, &majflt,
+ &cmajflt, &utime, &stime,
+ &cutime, &cstime, &priority,
+
+ &nice, &placeholder, &itrealvalue,
+ &starttime, &vsize, &rss,
+ &rlim, &startcode, &endcode,
+
+ &startstack, &kstkesp, &kstkeip,
+ &signal, &blocked, &sigignore,
+ &sigcatch, &wchan, &nswap,
+
+ &cnswap, &exit_signal, &processor
+ );
+
+ if (count < 17)
+ {
+ return 0;
+ }
+
+ /*
+ Don't need to check exit status of fclose on read-only streams
+ */
+ fclose(f);
+ return utime+stime+cutime+cstime;
+
}
/**
@@ -831,18 +837,18 @@ unsigned long proc_get_jiffies( process_t *p )
*/
void proc_update_jiffies()
{
- job_t* job;
- process_t *p;
- job_iterator_t j;
-
- for( job = j.next(); job; job = j.next() )
- {
- for( p=job->first_process; p; p=p->next )
- {
- gettimeofday( &p->last_time, 0 );
- p->last_jiffies = proc_get_jiffies( p );
- }
- }
+ job_t* job;
+ process_t *p;
+ job_iterator_t j;
+
+ for (job = j.next(); job; job = j.next())
+ {
+ for (p=job->first_process; p; p=p->next)
+ {
+ gettimeofday(&p->last_time, 0);
+ p->last_jiffies = proc_get_jiffies(p);
+ }
+ }
}
@@ -850,103 +856,103 @@ void proc_update_jiffies()
/**
Check if there are buffers associated with the job, and select on
- them for a while if available.
-
+ them for a while if available.
+
\param j the job to test
\return 1 if buffers were avaialble, zero otherwise
*/
-static int select_try( job_t *j )
+static int select_try(job_t *j)
{
- fd_set fds;
- int maxfd=-1;
+ fd_set fds;
+ int maxfd=-1;
+
+ FD_ZERO(&fds);
- FD_ZERO(&fds);
-
for (size_t idx = 0; idx < j->io.size(); idx++)
- {
+ {
const io_data_t *d = j->io.at(idx);
- if( d->io_mode == IO_BUFFER )
- {
- int fd = d->param1.pipe_fd[0];
+ if (d->io_mode == IO_BUFFER)
+ {
+ int fd = d->param1.pipe_fd[0];
// fwprintf( stderr, L"fd %d on job %ls\n", fd, j->command );
- FD_SET( fd, &fds );
- maxfd = maxi(maxfd, fd);
- debug( 3, L"select_try on %d\n", fd );
- }
- }
-
- if( maxfd >= 0 )
- {
- int retval;
- struct timeval tv;
-
- tv.tv_sec=0;
- tv.tv_usec=10000;
-
- retval =select( maxfd+1, &fds, 0, 0, &tv );
- return retval > 0;
- }
-
- return -1;
+ FD_SET(fd, &fds);
+ maxfd = maxi(maxfd, fd);
+ debug(3, L"select_try on %d\n", fd);
+ }
+ }
+
+ if (maxfd >= 0)
+ {
+ int retval;
+ struct timeval tv;
+
+ tv.tv_sec=0;
+ tv.tv_usec=10000;
+
+ retval =select(maxfd+1, &fds, 0, 0, &tv);
+ return retval > 0;
+ }
+
+ return -1;
}
/**
- Read from descriptors until they are empty.
+ Read from descriptors until they are empty.
\param j the job to test
*/
-static void read_try( job_t *j )
+static void read_try(job_t *j)
{
- io_data_t *buff=NULL;
+ io_data_t *buff=NULL;
- /*
- Find the last buffer, which is the one we want to read from
- */
+ /*
+ Find the last buffer, which is the one we want to read from
+ */
for (size_t idx = 0; idx < j->io.size(); idx++)
- {
+ {
io_data_t *d = j->io.at(idx);
- if( d->io_mode == IO_BUFFER )
- {
- buff=d;
- }
- }
-
- if( buff )
- {
- debug( 3, L"proc::read_try('%ls')\n", j->command_wcstr() );
- while(1)
- {
- char b[BUFFER_SIZE];
- long l;
-
- l=read_blocked( buff->param1.pipe_fd[0],
- b, BUFFER_SIZE );
- if( l==0 )
- {
- break;
- }
- else if( l<0 )
- {
- if( errno != EAGAIN )
- {
- debug( 1,
- _( L"An error occured while reading output from code block" ) );
- wperror( L"read_try" );
- }
- break;
- }
- else
- {
+ if (d->io_mode == IO_BUFFER)
+ {
+ buff=d;
+ }
+ }
+
+ if (buff)
+ {
+ debug(3, L"proc::read_try('%ls')\n", j->command_wcstr());
+ while (1)
+ {
+ char b[BUFFER_SIZE];
+ long l;
+
+ l=read_blocked(buff->param1.pipe_fd[0],
+ b, BUFFER_SIZE);
+ if (l==0)
+ {
+ break;
+ }
+ else if (l<0)
+ {
+ if (errno != EAGAIN)
+ {
+ debug(1,
+ _(L"An error occured while reading output from code block"));
+ wperror(L"read_try");
+ }
+ break;
+ }
+ else
+ {
buff->out_buffer_append(b, l);
- }
- }
- }
+ }
+ }
+ }
}
/**
- Give ownership of the terminal to the specified job.
+ Give ownership of the terminal to the specified job.
\param j The job to give the terminal to.
@@ -954,365 +960,365 @@ static void read_try( job_t *j )
a job that has previously been stopped. In that case, we need to
set the terminal attributes to those saved in the job.
*/
-static int terminal_give_to_job( job_t *j, int cont )
+static int terminal_give_to_job(job_t *j, int cont)
{
-
- if( tcsetpgrp (0, j->pgid) )
- {
- debug( 1,
- _( L"Could not send job %d ('%ls') to foreground" ),
- j->job_id,
- j->command_wcstr() );
- wperror( L"tcsetpgrp" );
- return 0;
- }
-
- if( cont )
- {
- if( tcsetattr (0, TCSADRAIN, &j->tmodes))
- {
- debug( 1,
- _( L"Could not send job %d ('%ls') to foreground" ),
- j->job_id,
- j->command_wcstr() );
- wperror( L"tcsetattr" );
- return 0;
- }
- }
- return 1;
+
+ if (tcsetpgrp(0, j->pgid))
+ {
+ debug(1,
+ _(L"Could not send job %d ('%ls') to foreground"),
+ j->job_id,
+ j->command_wcstr());
+ wperror(L"tcsetpgrp");
+ return 0;
+ }
+
+ if (cont)
+ {
+ if (tcsetattr(0, TCSADRAIN, &j->tmodes))
+ {
+ debug(1,
+ _(L"Could not send job %d ('%ls') to foreground"),
+ j->job_id,
+ j->command_wcstr());
+ wperror(L"tcsetattr");
+ return 0;
+ }
+ }
+ return 1;
}
/**
Returns contol of the terminal to the shell, and saves the terminal
attribute state to the job, so that we can restore the terminal
- ownership to the job at a later time .
+ ownership to the job at a later time .
*/
-static int terminal_return_from_job( job_t *j)
+static int terminal_return_from_job(job_t *j)
{
-
- if( tcsetpgrp (0, getpgrp()) )
- {
- debug( 1, _( L"Could not return shell to foreground" ) );
- wperror( L"tcsetpgrp" );
- return 0;
- }
-
- /*
- Save jobs terminal modes.
- */
- if( tcgetattr (0, &j->tmodes) )
- {
- debug( 1, _( L"Could not return shell to foreground" ) );
- wperror( L"tcgetattr" );
- return 0;
- }
-
- /* Disabling this per https://github.com/adityagodbole/fish-shell/commit/9d229cd18c3e5c25a8bd37e9ddd3b67ddc2d1b72
- On Linux, 'cd . ; ftp' prevents you from typing into the ftp prompt
- See https://github.com/fish-shell/fish-shell/issues/121
- */
+
+ if (tcsetpgrp(0, getpgrp()))
+ {
+ debug(1, _(L"Could not return shell to foreground"));
+ wperror(L"tcsetpgrp");
+ return 0;
+ }
+
+ /*
+ Save jobs terminal modes.
+ */
+ if (tcgetattr(0, &j->tmodes))
+ {
+ debug(1, _(L"Could not return shell to foreground"));
+ wperror(L"tcgetattr");
+ return 0;
+ }
+
+ /* Disabling this per https://github.com/adityagodbole/fish-shell/commit/9d229cd18c3e5c25a8bd37e9ddd3b67ddc2d1b72
+ On Linux, 'cd . ; ftp' prevents you from typing into the ftp prompt
+ See https://github.com/fish-shell/fish-shell/issues/121
+ */
#if 0
- /*
- Restore the shell's terminal modes.
- */
- if( tcsetattr (0, TCSADRAIN, &shell_modes))
- {
- debug( 1, _( L"Could not return shell to foreground" ) );
- wperror( L"tcsetattr" );
- return 0;
- }
+ /*
+ Restore the shell's terminal modes.
+ */
+ if (tcsetattr(0, TCSADRAIN, &shell_modes))
+ {
+ debug(1, _(L"Could not return shell to foreground"));
+ wperror(L"tcsetattr");
+ return 0;
+ }
#endif
- return 1;
+ return 1;
}
-void job_continue (job_t *j, int cont)
+void job_continue(job_t *j, int cont)
{
- /*
- Put job first in the job list
- */
+ /*
+ Put job first in the job list
+ */
job_promote(j);
- job_set_flag( j, JOB_NOTIFIED, 0 );
-
- CHECK_BLOCK();
-
- debug( 4,
- L"Continue job %d, gid %d (%ls), %ls, %ls",
- j->job_id,
- j->pgid,
- j->command_wcstr(),
- job_is_completed( j )?L"COMPLETED":L"UNCOMPLETED",
- is_interactive?L"INTERACTIVE":L"NON-INTERACTIVE" );
-
- if( !job_is_completed( j ) )
- {
- if( job_get_flag( j, JOB_TERMINAL ) && job_get_flag( j, JOB_FOREGROUND ) )
- {
- /* Put the job into the foreground. */
- int ok;
-
- signal_block();
-
- ok = terminal_give_to_job( j, cont );
-
- signal_unblock();
-
- if( !ok )
- return;
-
- }
-
- /*
- Send the job a continue signal, if necessary.
- */
- if( cont )
- {
- process_t *p;
-
- for( p=j->first_process; p; p=p->next )
- p->stopped=0;
-
- if( job_get_flag( j, JOB_CONTROL ) )
- {
- if( killpg( j->pgid, SIGCONT ) )
- {
- wperror( L"killpg (SIGCONT)" );
- return;
- }
- }
- else
- {
- for( p=j->first_process; p; p=p->next )
- {
- if (kill ( p->pid, SIGCONT) < 0)
- {
- wperror (L"kill (SIGCONT)");
- return;
- }
- }
- }
- }
-
- if( job_get_flag( j, JOB_FOREGROUND ) )
- {
- int quit = 0;
-
- /*
- Wait for job to report. Looks a bit ugly because it has to
- handle the possibility that a signal is dispatched while
- running job_is_stopped().
- */
- while( !quit )
- {
- do
- {
- got_signal = 0;
- quit = job_is_stopped( j ) || job_is_completed( j );
- }
- while (got_signal && !quit);
-
- if( !quit )
- {
-
-// debug( 1, L"select_try()" );
- switch( select_try(j) )
- {
- case 1:
- {
- read_try( j );
- break;
- }
-
- case -1:
- {
- /*
- If there is no funky IO magic, we can use
- waitpid instead of handling child deaths
- through signals. This gives a rather large
- speed boost (A factor 3 startup time
- improvement on my 300 MHz machine) on
- short-lived jobs.
- */
- int status;
- pid_t pid = waitpid(-1, &status, WUNTRACED );
- if( pid > 0 )
- {
- handle_child_status( pid, status );
- }
- else
- {
- /*
- This probably means we got a
- signal. A signal might mean that the
- terminal emulator sent us a hup
- signal to tell is to close. If so,
- we should exit.
- */
- if( reader_exit_forced() )
- {
- quit = 1;
- }
-
- }
- break;
- }
-
- }
- }
- }
- }
- }
-
- if( job_get_flag( j, JOB_FOREGROUND ) )
- {
-
- if( job_is_completed( j ))
- {
-
- // It's possible that the job will produce output and exit before we've even read from it.
- // We'll eventually read the output, but it may be after we've executed subsequent calls
- // This is why my prompt colors kept getting screwed up - the builtin echo calls
- // were sometimes having their output combined with the set_color calls in the wrong order!
- read_try(j);
-
-
- process_t *p = j->first_process;
- while( p->next )
- p = p->next;
-
- if( WIFEXITED( p->status ) || WIFSIGNALED(p->status))
- {
- /*
- Mark process status only if we are in the foreground
- and the last process in a pipe, and it is not a short circuted builtin
- */
- if( p->pid )
- {
- int status = proc_format_status(p->status);
- //wprintf(L"setting status %d for %ls\n", job_get_flag( j, JOB_NEGATE )?!status:status, j->command);
- proc_set_last_status( job_get_flag( j, JOB_NEGATE )?!status:status);
- }
- }
- }
- /*
- Put the shell back in the foreground.
- */
- if( job_get_flag( j, JOB_TERMINAL ) && job_get_flag( j, JOB_FOREGROUND ) )
- {
- int ok;
-
- signal_block();
-
- ok = terminal_return_from_job( j );
-
- signal_unblock();
-
- if( !ok )
- return;
-
- }
- }
-
+ job_set_flag(j, JOB_NOTIFIED, 0);
+
+ CHECK_BLOCK();
+
+ debug(4,
+ L"Continue job %d, gid %d (%ls), %ls, %ls",
+ j->job_id,
+ j->pgid,
+ j->command_wcstr(),
+ job_is_completed(j)?L"COMPLETED":L"UNCOMPLETED",
+ is_interactive?L"INTERACTIVE":L"NON-INTERACTIVE");
+
+ if (!job_is_completed(j))
+ {
+ if (job_get_flag(j, JOB_TERMINAL) && job_get_flag(j, JOB_FOREGROUND))
+ {
+ /* Put the job into the foreground. */
+ int ok;
+
+ signal_block();
+
+ ok = terminal_give_to_job(j, cont);
+
+ signal_unblock();
+
+ if (!ok)
+ return;
+
+ }
+
+ /*
+ Send the job a continue signal, if necessary.
+ */
+ if (cont)
+ {
+ process_t *p;
+
+ for (p=j->first_process; p; p=p->next)
+ p->stopped=0;
+
+ if (job_get_flag(j, JOB_CONTROL))
+ {
+ if (killpg(j->pgid, SIGCONT))
+ {
+ wperror(L"killpg (SIGCONT)");
+ return;
+ }
+ }
+ else
+ {
+ for (p=j->first_process; p; p=p->next)
+ {
+ if (kill(p->pid, SIGCONT) < 0)
+ {
+ wperror(L"kill (SIGCONT)");
+ return;
+ }
+ }
+ }
+ }
+
+ if (job_get_flag(j, JOB_FOREGROUND))
+ {
+ int quit = 0;
+
+ /*
+ Wait for job to report. Looks a bit ugly because it has to
+ handle the possibility that a signal is dispatched while
+ running job_is_stopped().
+ */
+ while (!quit)
+ {
+ do
+ {
+ got_signal = 0;
+ quit = job_is_stopped(j) || job_is_completed(j);
+ }
+ while (got_signal && !quit);
+
+ if (!quit)
+ {
+
+// debug( 1, L"select_try()" );
+ switch (select_try(j))
+ {
+ case 1:
+ {
+ read_try(j);
+ break;
+ }
+
+ case -1:
+ {
+ /*
+ If there is no funky IO magic, we can use
+ waitpid instead of handling child deaths
+ through signals. This gives a rather large
+ speed boost (A factor 3 startup time
+ improvement on my 300 MHz machine) on
+ short-lived jobs.
+ */
+ int status;
+ pid_t pid = waitpid(-1, &status, WUNTRACED);
+ if (pid > 0)
+ {
+ handle_child_status(pid, status);
+ }
+ else
+ {
+ /*
+ This probably means we got a
+ signal. A signal might mean that the
+ terminal emulator sent us a hup
+ signal to tell is to close. If so,
+ we should exit.
+ */
+ if (reader_exit_forced())
+ {
+ quit = 1;
+ }
+
+ }
+ break;
+ }
+
+ }
+ }
+ }
+ }
+ }
+
+ if (job_get_flag(j, JOB_FOREGROUND))
+ {
+
+ if (job_is_completed(j))
+ {
+
+ // It's possible that the job will produce output and exit before we've even read from it.
+ // We'll eventually read the output, but it may be after we've executed subsequent calls
+ // This is why my prompt colors kept getting screwed up - the builtin echo calls
+ // were sometimes having their output combined with the set_color calls in the wrong order!
+ read_try(j);
+
+
+ process_t *p = j->first_process;
+ while (p->next)
+ p = p->next;
+
+ if (WIFEXITED(p->status) || WIFSIGNALED(p->status))
+ {
+ /*
+ Mark process status only if we are in the foreground
+ and the last process in a pipe, and it is not a short circuted builtin
+ */
+ if (p->pid)
+ {
+ int status = proc_format_status(p->status);
+ //wprintf(L"setting status %d for %ls\n", job_get_flag( j, JOB_NEGATE )?!status:status, j->command);
+ proc_set_last_status(job_get_flag(j, JOB_NEGATE)?!status:status);
+ }
+ }
+ }
+ /*
+ Put the shell back in the foreground.
+ */
+ if (job_get_flag(j, JOB_TERMINAL) && job_get_flag(j, JOB_FOREGROUND))
+ {
+ int ok;
+
+ signal_block();
+
+ ok = terminal_return_from_job(j);
+
+ signal_unblock();
+
+ if (!ok)
+ return;
+
+ }
+ }
+
}
-int proc_format_status(int status)
+int proc_format_status(int status)
{
- if( WIFSIGNALED( status ) )
- {
- return 128+WTERMSIG(status);
- }
- else if( WIFEXITED( status ) )
- {
- return WEXITSTATUS(status);
- }
- return status;
-
+ if (WIFSIGNALED(status))
+ {
+ return 128+WTERMSIG(status);
+ }
+ else if (WIFEXITED(status))
+ {
+ return WEXITSTATUS(status);
+ }
+ return status;
+
}
void proc_sanity_check()
{
- job_t *j;
- job_t *fg_job=0;
-
+ job_t *j;
+ job_t *fg_job=0;
+
job_iterator_t jobs;
while ((j = jobs.next()))
- {
- process_t *p;
-
- if( !job_get_flag( j, JOB_CONSTRUCTED ) )
- continue;
-
-
- validate_pointer( j->first_process,
- _( L"Process list pointer" ),
- 0 );
-
- /*
- More than one foreground job?
- */
- if( job_get_flag( j, JOB_FOREGROUND ) && !(job_is_stopped(j) || job_is_completed(j) ) )
- {
- if( fg_job != 0 )
- {
- debug( 0,
- _( L"More than one job in foreground: job 1: '%ls' job 2: '%ls'"),
- fg_job->command_wcstr(),
- j->command_wcstr() );
- sanity_lose();
- }
- fg_job = j;
- }
-
- p = j->first_process;
- while( p )
- {
- validate_pointer( p->get_argv(), _( L"Process argument list" ), 0 );
- validate_pointer( p->argv0(), _( L"Process name" ), 0 );
- validate_pointer( p->next, _( L"Process list pointer" ), 1 );
-
- if ( (p->stopped & (~0x00000001)) != 0 )
- {
- debug( 0,
- _( L"Job '%ls', process '%ls' has inconsistent state \'stopped\'=%d" ),
- j->command_wcstr(),
- p->argv0(),
- p->stopped );
- sanity_lose();
- }
-
- if ( (p->completed & (~0x00000001)) != 0 )
- {
- debug( 0,
- _( L"Job '%ls', process '%ls' has inconsistent state \'completed\'=%d" ),
- j->command_wcstr(),
- p->argv0(),
- p->completed );
- sanity_lose();
- }
-
- p=p->next;
- }
-
- }
+ {
+ process_t *p;
+
+ if (!job_get_flag(j, JOB_CONSTRUCTED))
+ continue;
+
+
+ validate_pointer(j->first_process,
+ _(L"Process list pointer"),
+ 0);
+
+ /*
+ More than one foreground job?
+ */
+ if (job_get_flag(j, JOB_FOREGROUND) && !(job_is_stopped(j) || job_is_completed(j)))
+ {
+ if (fg_job != 0)
+ {
+ debug(0,
+ _(L"More than one job in foreground: job 1: '%ls' job 2: '%ls'"),
+ fg_job->command_wcstr(),
+ j->command_wcstr());
+ sanity_lose();
+ }
+ fg_job = j;
+ }
+
+ p = j->first_process;
+ while (p)
+ {
+ validate_pointer(p->get_argv(), _(L"Process argument list"), 0);
+ validate_pointer(p->argv0(), _(L"Process name"), 0);
+ validate_pointer(p->next, _(L"Process list pointer"), 1);
+
+ if ((p->stopped & (~0x00000001)) != 0)
+ {
+ debug(0,
+ _(L"Job '%ls', process '%ls' has inconsistent state \'stopped\'=%d"),
+ j->command_wcstr(),
+ p->argv0(),
+ p->stopped);
+ sanity_lose();
+ }
+
+ if ((p->completed & (~0x00000001)) != 0)
+ {
+ debug(0,
+ _(L"Job '%ls', process '%ls' has inconsistent state \'completed\'=%d"),
+ j->command_wcstr(),
+ p->argv0(),
+ p->completed);
+ sanity_lose();
+ }
+
+ p=p->next;
+ }
+
+ }
}
-void proc_push_interactive( int value )
+void proc_push_interactive(int value)
{
ASSERT_IS_MAIN_THREAD();
- int old = is_interactive;
+ int old = is_interactive;
interactive_stack.push_back(is_interactive);
- is_interactive = value;
- if( old != value )
- signal_set_handlers();
+ is_interactive = value;
+ if (old != value)
+ signal_set_handlers();
}
void proc_pop_interactive()
{
ASSERT_IS_MAIN_THREAD();
- int old = is_interactive;
- is_interactive= interactive_stack.back();
+ int old = is_interactive;
+ is_interactive= interactive_stack.back();
interactive_stack.pop_back();
- if( is_interactive != old )
- signal_set_handlers();
+ if (is_interactive != old)
+ signal_set_handlers();
}