diff --git a/builtin.cpp b/builtin.cpp index e2374f1d7..5d27d654b 100644 --- a/builtin.cpp +++ b/builtin.cpp @@ -2906,25 +2906,7 @@ static int builtin_source( parser_t &parser, wchar_t ** argv ) */ static void make_first( job_t *j ) { - job_t *prev=0; - job_t *curr; - for( curr = first_job; curr != j; curr = curr->next ) - { - prev=curr; - } - if( curr == j ) - { - if( prev == 0 ) - { - return; - } - else - { - prev->next = curr->next; - curr->next = first_job; - first_job = curr; - } - } + job_promote(j); } @@ -2933,7 +2915,7 @@ static void make_first( job_t *j ) */ static int builtin_fg( parser_t &parser, wchar_t **argv ) { - job_t *j=0; + job_t *j=NULL; if( argv[1] == 0 ) { @@ -2941,7 +2923,9 @@ static int builtin_fg( parser_t &parser, wchar_t **argv ) Select last constructed job (I.e. first job in the job que) that is possible to put in the foreground */ - for( j=first_job; j; j=j->next ) + + job_iterator_t jobs; + while ((j = jobs.next())) { if( job_get_flag( j, JOB_CONSTRUCTED ) && (!job_is_completed(j)) && ( (job_is_stopped(j) || (!job_get_flag(j, JOB_FOREGROUND)) ) && job_get_flag( j, JOB_CONTROL) ) ) @@ -3121,8 +3105,9 @@ static int builtin_bg( parser_t &parser, wchar_t **argv ) if( argv[1] == 0 ) { job_t *j; - for( j=first_job; j; j=j->next ) - { + job_iterator_t jobs; + while ((j = jobs.next())) + { if( job_is_stopped(j) && job_get_flag( j, JOB_CONTROL ) && (!job_is_completed(j)) ) { break; diff --git a/builtin_jobs.cpp b/builtin_jobs.cpp index 7d8995997..229a7cbeb 100644 --- a/builtin_jobs.cpp +++ b/builtin_jobs.cpp @@ -271,8 +271,11 @@ static int builtin_jobs( parser_t &parser, wchar_t **argv ) /* Ignore unconstructed jobs, i.e. ourself. */ - for( j=first_job; j; j=j->next ) + job_iterator_t jobs; + job_t *j; + while ((j = jobs.next())) { + if( (j->flags & JOB_CONSTRUCTED) && !job_is_completed(j) ) { builtin_jobs_print( j, mode, !found ); @@ -322,8 +325,10 @@ static int builtin_jobs( parser_t &parser, wchar_t **argv ) } else { - for( j= first_job; j; j=j->next ) - { + job_iterator_t jobs; + job_t *j; + while ((j = jobs.next())) + { /* Ignore unconstructed jobs, i.e. ourself. */ diff --git a/expand.cpp b/expand.cpp index 7b347b5c6..473f855a1 100644 --- a/expand.cpp +++ b/expand.cpp @@ -397,7 +397,8 @@ static int find_process( const wchar_t *proc, if( flags & ACCEPT_INCOMPLETE ) { - for( j=first_job; j != 0; j=j->next ) + job_iterator_t jobs; + while ((j = jobs.next())) { wchar_t jid[16]; if( j->command == 0 ) @@ -454,7 +455,8 @@ static int find_process( const wchar_t *proc, if( found ) return 1; - for( j=first_job; j != 0; j=j->next ) + job_iterator_t jobs; + while ((j = jobs.next())) { int offset; @@ -487,7 +489,8 @@ static int find_process( const wchar_t *proc, return 1; } - for( j=first_job; j; j=j->next ) + jobs.reset(); + while ((j = jobs.next())) { process_t *p; if( j->command == 0 ) diff --git a/proc.cpp b/proc.cpp index b1dc85a5e..25a6df036 100644 --- a/proc.cpp +++ b/proc.cpp @@ -95,7 +95,12 @@ static int last_status=0; */ static sig_atomic_t got_signal=0; -job_t *first_job=0; +static std::list s_job_list; + +job_list_t &job_list(void) { + return s_job_list; +} + int is_interactive=-1; int is_interactive_session=0; int is_subshell=0; @@ -143,25 +148,26 @@ void proc_init() */ static int job_remove( job_t *j ) { - job_t *prev=0, *curr=first_job; - while( (curr != 0) && (curr != j) ) - { - prev = curr; - curr = curr->next; - } - - if( j != curr ) - { + job_list_t &jobs = job_list(); + job_list_t::iterator iter = find(jobs.begin(), jobs.end(), j); + if (iter != jobs.end()) { + jobs.erase(iter); + return 1; + } else { debug( 1, _( L"Job inconsistency" ) ); sanity_lose(); - return 0; - } - - if( prev == 0 ) - first_job = j->next; - else - prev->next = j->next; - return 1; + return 0; + } +} + +void job_promote(job_t *job) +{ + job_list_t &jobs = job_list(); + job_list_t::iterator loc = find(jobs.begin(), jobs.end(), job); + assert(loc != jobs.end()); + + /* Move the job to the beginning */ + jobs.splice(jobs.begin(), jobs, loc); } @@ -181,10 +187,12 @@ void proc_destroy() event.arguments = NULL; sb_destroy( &event_pid ); sb_destroy( &event_status ); - while( first_job ) + job_list_t &jobs = job_list(); + while( ! jobs.empty() ) { - debug( 2, L"freeing leaked job %ls", first_job->command ); - job_free( first_job ); + job_t *job = jobs.front(); + debug( 2, L"freeing leaked job %ls", job->command ); + job_free( job ); } } @@ -206,10 +214,9 @@ job_t *job_create() while( job_get( free_id ) != 0 ) free_id++; res = (job_t *)halloc( 0, sizeof(job_t) ); - res->next = first_job; res->job_id = free_id; - first_job = res; - + job_list().push_front(res); + job_set_flag( res, JOB_CONTROL, (job_control_mode==JOB_CONTROL_ALL) || @@ -223,30 +230,22 @@ job_t *job_create() job_t *job_get( int id ) { - job_t *res = first_job; - if( id <= 0 ) - { - return res; + job_iterator_t jobs; + job_t *job; + while ((job = jobs.next())) { + if( id <= 0 || job->job_id == id) + return job; } - - while( res != 0 ) - { - if( res->job_id == id ) - return res; - res = res->next; - } - return 0; + return NULL; } job_t *job_get_from_pid( int pid ) { - job_t *res = first_job; - - while( res != 0 ) - { - if( res->pgid == pid ) - return res; - res = res->next; + job_iterator_t jobs; + job_t *job; + while ((job = jobs.next())) { + if( job->pgid == pid ) + return job; } return 0; } @@ -399,7 +398,8 @@ static void handle_child_status( pid_t pid, int status ) write( 2, mess, strlen(mess )); */ - for( j=first_job; j && !found_proc; j=j->next ) + job_iterator_t jobs; + while ((j = jobs.next())) { process_t *prev=0; for( p=j->first_process; p; p=p->next ) @@ -546,7 +546,7 @@ void proc_fire_event( const wchar_t *msg, int type, pid_t pid, int status ) int job_reap( int interactive ) { - job_t *j, *jnext; + job_t *jnext; int found=0; static int locked = 0; @@ -559,11 +559,14 @@ int job_reap( int interactive ) */ if( locked>1 ) return 0; - - for( j=first_job; j; j=jnext) - { + + job_iterator_t jobs; + jnext = jobs.next(); + while (jnext) + { + job_t *j = jnext; + jnext = jobs.next(); process_t *p; - jnext = j->next; /* If we are reaping only jobs who do not need status messages @@ -960,9 +963,7 @@ void job_continue (job_t *j, int cont) /* Put job first in the job list */ - job_remove( j ); - j->next = first_job; - first_job = j; + job_promote(j); job_set_flag( j, JOB_NOTIFIED, 0 ); CHECK_BLOCK(); @@ -1160,7 +1161,8 @@ void proc_sanity_check() job_t *j; job_t *fg_job=0; - for( j = first_job; j ; j=j->next ) + job_iterator_t jobs; + while ((j = jobs.next())) { process_t *p; @@ -1174,9 +1176,6 @@ void proc_sanity_check() validate_pointer( j->first_process, _( L"Process list pointer" ), 0 ); - validate_pointer( j->next, - _( L"Job list pointer" ), - 1 ); /* More than one foreground job? diff --git a/proc.h b/proc.h index 46fb3ea74..e04267b98 100644 --- a/proc.h +++ b/proc.h @@ -15,6 +15,7 @@ #include #include #include +#include #include "util.h" #include "io.h" @@ -233,14 +234,15 @@ typedef struct process A struct represeting a job. A job is basically a pipeline of one or more processes and a couple of flags. */ -typedef struct job +class job_t { + public: /** The original command which led to the creation of this job. It is used for displaying messages about job status on the terminal. */ - const wchar_t *command; + const wchar_t *command; /** A linked list of all the processes in this job. @@ -276,15 +278,14 @@ typedef struct job /** A pointer to the next job in the job queue */ - struct job *next; + //struct job *next; /** Bitset containing information about the job. A combination of the JOB_* constants. */ int flags; -} - job_t; +}; /** Whether we are running a subshell command @@ -316,10 +317,35 @@ extern int is_login; */ extern int is_event; -/** - Linked list of all living jobs -*/ -extern job_t *first_job; + +/** List of all living jobs */ +typedef std::list job_list_t; +job_list_t &job_list(void); + +/** A class to aid iteration over jobs list */ +class job_iterator_t { + job_list_t::iterator current, end; + public: + + void reset(void) { + job_list_t &jobs = job_list(); + this->current = jobs.begin(); + this->end = jobs.end(); + } + + job_t *next() { + job_t *job = NULL; + if (current != end) { + job = *current; + ++current; + } + return job; + } + + job_iterator_t() { + this->reset(); + } +}; /** Whether a universal variable barrier roundtrip has already been @@ -377,6 +403,11 @@ int proc_get_last_status(); */ void job_free( job_t* j ); +/** + Promotes a job to the front of the job list. +*/ +void job_promote(job_t *job); + /** Create a new job. Job struct is allocated using halloc, so anything that should be freed with the job can uset it as a halloc context @@ -390,6 +421,7 @@ job_t *job_create(); */ job_t *job_get(int id); + /** Return the job with the specified pid. */ diff --git a/reader.cpp b/reader.cpp index 0381eae92..a04fb9ac0 100644 --- a/reader.cpp +++ b/reader.cpp @@ -2519,7 +2519,7 @@ static void reader_super_highlight_me_plenty( int match_highlight_pos, array_lis int exit_status() { if( is_interactive ) - return first_job == 0 && data->end_loop; + return job_list().empty() && data->end_loop; else return end_loop; } @@ -2549,7 +2549,8 @@ static void handle_end_loop() } } - for( j=first_job; j; j=j->next ) + job_iterator_t jobs; + while ((j = jobs.next())) { if( !job_is_completed(j) ) { @@ -2574,7 +2575,8 @@ static void handle_end_loop() in interactive mode. If isatty returns false, it means stdin must have been closed. */ - for( j = first_job; j; j=j->next ) + job_iterator_t jobs; + while ((j = jobs.next())) { if( ! job_is_completed( j ) ) {