diff options
author | ridiculousfish <corydoras@ridiculousfish.com> | 2011-12-26 19:18:46 -0800 |
---|---|---|
committer | ridiculousfish <corydoras@ridiculousfish.com> | 2011-12-26 19:18:46 -0800 |
commit | 8d2f107d61a8b0e099ab9a59b8a32c236da5a5fc (patch) | |
tree | 89f718ab74f8400332534aee237c6f925348f05c /proc.cpp | |
parent | 3f16ace6784caab54fb054836ee93902e9701913 (diff) |
Some changes to migrate towards C++ and a multithreaded model
Diffstat (limited to 'proc.cpp')
-rw-r--r-- | proc.cpp | 412 |
1 files changed, 206 insertions, 206 deletions
@@ -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" @@ -76,7 +76,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 @@ -85,13 +85,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; @@ -139,7 +139,7 @@ void proc_init() /** - Remove job from list of jobs + Remove job from list of jobs */ static int job_remove( job_t *j ) { @@ -156,7 +156,7 @@ static int job_remove( job_t *j ) sanity_lose(); return 0; } - + if( prev == 0 ) first_job = j->next; else @@ -184,7 +184,7 @@ void proc_destroy() { debug( 2, L"freeing leaked job %ls", first_job->command ); job_free( first_job ); - } + } } void proc_set_last_status( int s ) @@ -201,25 +201,25 @@ job_t *job_create() { int free_id=1; job_t *res; - + while( job_get( free_id ) != 0 ) free_id++; - res = halloc( 0, sizeof(job_t) ); + res = (job_t *)halloc( 0, sizeof(job_t) ); res->next = first_job; res->job_id = free_id; first_job = res; - job_set_flag( res, - JOB_CONTROL, - (job_control_mode==JOB_CONTROL_ALL) || + job_set_flag( 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 ); +// fwprintf( stderr, L"Create job %d\n", res->job_id ); return res; } - + job_t *job_get( int id ) { job_t *res = first_job; @@ -227,7 +227,7 @@ job_t *job_get( int id ) { return res; } - + while( res != 0 ) { if( res->job_id == id ) @@ -240,7 +240,7 @@ job_t *job_get( int id ) job_t *job_get_from_pid( int pid ) { job_t *res = first_job; - + while( res != 0 ) { if( res->pgid == pid ) @@ -251,8 +251,8 @@ job_t *job_get_from_pid( int 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 */ @@ -271,20 +271,20 @@ int job_is_stopped( const job_t *j ) } -/* - 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 ) { process_t *p; - + for (p = j->first_process; p->next; p = p->next) ; - + return p->completed; - + } void job_set_flag( job_t *j, int flag, int set ) @@ -301,10 +301,10 @@ int job_get_flag( job_t *j, int flag ) } 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 ); @@ -337,7 +337,7 @@ int job_signal( job_t *j, int signal ) /** 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. */ static void mark_process_status( job_t *j, process_t *p, @@ -345,19 +345,19 @@ static void mark_process_status( job_t *j, { // 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)) + else if (WIFSIGNALED(status) || WIFEXITED(status)) { p->completed = 1; } else { ssize_t ignore; - + /* This should never be reached */ p->completed = 1; @@ -388,10 +388,10 @@ static void handle_child_status( pid_t pid, int status ) int found_proc = 0; job_t *j=0; process_t *p=0; -// char mess[MESS_SIZE]; - found_proc = 0; +// char mess[MESS_SIZE]; + found_proc = 0; /* - snprintf( mess, + snprintf( mess, MESS_SIZE, "Process %d\n", (int) pid ); @@ -410,8 +410,8 @@ static void handle_child_status( pid_t pid, int status ) "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 ) { @@ -420,7 +420,7 @@ static void handle_child_status( pid_t pid, int status ) /* snprintf( mess, MESS_SIZE, "Kill previously uncompleted process %ls (%d)\n", - prev->actual_cmd, + prev->actual_cmd, prev->pid ); write( 2, mess, strlen(mess )); */ @@ -435,15 +435,15 @@ static void handle_child_status( pid_t pid, int status ) } - if( WIFSIGNALED( status ) && - ( WTERMSIG(status)==SIGINT || + 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_flags=0; act.sa_handler=SIG_DFL; sigaction( SIGINT, &act, 0 ); sigaction( SIGQUIT, &act, 0 ); @@ -458,34 +458,34 @@ static void handle_child_status( pid_t pid, int status ) { c->skip=1; c=c->outer; - } - } + } + } } } - + 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, +/* snprintf( mess, MESS_SIZE, "Process %d not found by %d\n", (int) pid, (int)getpid() ); write( 2, mess, strlen(mess )); */ - } + } return; } void job_handle_signal ( int signal, siginfo_t *info, void *con ) { - + int status; pid_t pid; int errno_old = errno; @@ -503,19 +503,19 @@ void job_handle_signal ( int signal, siginfo_t *info, void *con ) { 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 @@ -531,46 +531,46 @@ static void format_job_info( const job_t *j, const wchar_t *status ) void proc_fire_event( const wchar_t *msg, int type, pid_t pid, int status ) { - + event.type=type; event.param1.pid = pid; - - al_push( &event.arguments, msg ); + + al_push( &event.arguments, msg ); sb_printf( &event_pid, L"%d", pid ); al_push( &event.arguments, event_pid.buff ); - - sb_printf( &event_status, L"%d", status ); + + sb_printf( &event_status, L"%d", status ); al_push( &event.arguments, event_status.buff ); event_fire( &event ); al_truncate( &event.arguments, 0 ); - sb_clear( &event_pid ); - sb_clear( &event_status ); -} + sb_clear( &event_pid ); + sb_clear( &event_status ); +} int job_reap( int interactive ) { - job_t *j, *jnext; + job_t *j, *jnext; int found=0; - + static int locked = 0; - - locked++; - + + 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; - + for( j=first_job; j; j=jnext) - { + { process_t *p; jnext = j->next; - + /* If we are reaping only jobs who do not need status messages sent to the console, do not consider reaping jobs that need @@ -580,28 +580,28 @@ int job_reap( int interactive ) { continue; } - + for( p=j->first_process; p; p=p->next ) { int s; if( !p->completed ) continue; - + if( !p->pid ) - continue; - + continue; + s = p->status; - - proc_fire_event( L"PROCESS_EXIT", EVENT_EXIT, p->pid, ( WIFSIGNALED(s)?-1:WEXITSTATUS( s )) ); - + + 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 ); @@ -611,7 +611,7 @@ int job_reap( int interactive ) fwprintf( stdout, _( L"%ls: Job %d, \'%ls\' terminated by signal %ls (%ls)" ), program_name, - j->job_id, + j->job_id, j->command, sig2wcs(WTERMSIG(p->status)), signal_get_desc( WTERMSIG(p->status) ) ); @@ -627,43 +627,43 @@ int job_reap( int interactive ) signal_get_desc( WTERMSIG(p->status) ) ); tputs(clr_eol,1,&writeb); fwprintf (stdout, L"\n" ); - found=1; + 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. + completed and delete it from the active job list. */ - if( job_is_completed( j ) ) + 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 ); + 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 ) ) + } + else if( job_is_stopped( j ) && !job_get_flag( j, JOB_NOTIFIED ) ) { - /* - Notify the user about newly stopped jobs. + /* + 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 ); } } @@ -672,8 +672,8 @@ int job_reap( int interactive ) fflush( stdout ); locked = 0; - - return found; + + return found; } @@ -692,36 +692,36 @@ unsigned long proc_get_jiffies( process_t *p ) wchar_t fn[FN_SIZE]; char state; - int pid, ppid, pgrp, + int pid, ppid, pgrp, session, tty_nr, tpgid, - exit_signal, processor; - - long int cutime, cstime, priority, - nice, placeholder, itrealvalue, + exit_signal, processor; + + long int cutime, cstime, priority, + nice, placeholder, itrealvalue, rss; - unsigned long int flags, minflt, cminflt, - majflt, cmajflt, utime, - stime, starttime, vsize, + 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 " + + int count = fscanf( f, + "%d %s %c " "%d %d %d " "%d %d %lu " - + "%lu %lu %lu " "%lu %lu %lu " "%ld %ld %ld " @@ -735,15 +735,15 @@ unsigned long proc_get_jiffies( process_t *p ) "%lu %lu %lu " "%lu %d %d ", - - &pid, comm, &state, - &ppid, &pgrp, &session, + + &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, @@ -765,7 +765,7 @@ unsigned long proc_get_jiffies( process_t *p ) */ fclose( f ); return utime+stime+cutime+cstime; - + } /** @@ -775,14 +775,14 @@ void proc_update_jiffies() { job_t *j; process_t *p; - + for( j=first_job; j; j=j->next ) { for( p=j->first_process; p; p=p->next ) { gettimeofday( &p->last_time, 0 ); p->last_jiffies = proc_get_jiffies( p ); - } + } } } @@ -791,8 +791,8 @@ 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 @@ -804,7 +804,7 @@ static int select_try( job_t *j ) io_data_t *d; FD_ZERO(&fds); - + for( d = j->io; d; d=d->next ) { if( d->io_mode == IO_BUFFER ) @@ -816,15 +816,15 @@ static int select_try( job_t *j ) 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; } @@ -833,7 +833,7 @@ static int select_try( job_t *j ) } /** - Read from descriptors until they are empty. + Read from descriptors until they are empty. \param j the job to test */ @@ -846,13 +846,13 @@ static void read_try( job_t *j ) */ for( d = j->io; d; d=d->next ) { - + if( d->io_mode == IO_BUFFER ) { buff=d; } } - + if( buff ) { debug( 3, L"proc::read_try('%ls')\n", j->command ); @@ -860,7 +860,7 @@ static void read_try( job_t *j ) { char b[BUFFER_SIZE]; int l; - + l=read_blocked( buff->param1.pipe_fd[0], b, BUFFER_SIZE ); if( l==0 ) @@ -871,23 +871,23 @@ static void read_try( job_t *j ) { if( errno != EAGAIN ) { - debug( 1, + debug( 1, _( L"An error occured while reading output from code block" ) ); - wperror( L"read_try" ); - } + wperror( L"read_try" ); + } break; } else { b_append( buff->param2.out_buffer, 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. @@ -897,19 +897,19 @@ static void read_try( job_t *j ) */ 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, + debug( 1, + _( L"Could not send job %d ('%ls') to foreground" ), + j->job_id, j->command ); wperror( L"tcsetpgrp" ); return 0; } - + if( cont ) - { + { if( tcsetattr (0, TCSADRAIN, &j->tmodes)) { debug( 1, @@ -926,20 +926,20 @@ static int terminal_give_to_job( job_t *j, int cont ) /** 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) { - + if( tcsetpgrp (0, getpgrp()) ) { debug( 1, _( L"Could not return shell to foreground" ) ); wperror( L"tcsetpgrp" ); return 0; } - - /* - Save jobs terminal modes. + + /* + Save jobs terminal modes. */ if( tcgetattr (0, &j->tmodes) ) { @@ -947,9 +947,9 @@ static int terminal_return_from_job( job_t *j) wperror( L"tcgetattr" ); return 0; } - - /* - Restore the shell's terminal modes. + + /* + Restore the shell's terminal modes. */ if( tcsetattr (0, TCSADRAIN, &shell_modes)) { @@ -972,35 +972,35 @@ void job_continue (job_t *j, int cont) job_set_flag( j, JOB_NOTIFIED, 0 ); CHECK_BLOCK(); - + debug( 4, L"Continue job %d, gid %d (%ls), %ls, %ls", - j->job_id, + j->job_id, j->pgid, - j->command, - job_is_completed( j )?L"COMPLETED":L"UNCOMPLETED", + j->command, + 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(); + + signal_unblock(); if( !ok ) return; - + } - - /* - Send the job a continue signal, if necessary. + + /* + Send the job a continue signal, if necessary. */ if( cont ) { @@ -1025,16 +1025,16 @@ void job_continue (job_t *j, int cont) { 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(). @@ -1052,16 +1052,16 @@ void job_continue (job_t *j, int cont) if( !quit ) { - -// debug( 1, L"select_try()" ); + +// debug( 1, L"select_try()" ); switch( select_try(j) ) { - case 1: + case 1: { read_try( j ); break; } - + case -1: { /* @@ -1072,7 +1072,7 @@ void job_continue (job_t *j, int cont) improvement on my 300 MHz machine) on short-lived jobs. */ - int status; + int status; pid_t pid = waitpid(-1, &status, WUNTRACED ); if( pid > 0 ) { @@ -1091,20 +1091,20 @@ void job_continue (job_t *j, int cont) { quit = 1; } - + } break; } - + } - } + } } - } + } } - + if( job_get_flag( j, JOB_FOREGROUND ) ) { - + if( job_is_completed( j )) { process_t *p = j->first_process; @@ -1113,51 +1113,51 @@ void job_continue (job_t *j, int cont) 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); - + proc_set_last_status( job_get_flag( j, JOB_NEGATE )?!status:status); } - } + } } - /* - Put the shell back in the foreground. + /* + 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 ) ) + if( WIFSIGNALED( status ) ) { return 128+WTERMSIG(status); - } - else if( WIFEXITED( status ) ) + } + else if( WIFEXITED( status ) ) { return WEXITSTATUS(status); } return status; - + } @@ -1165,22 +1165,22 @@ void proc_sanity_check() { job_t *j; job_t *fg_job=0; - + for( j = first_job; j ; j=j->next ) { process_t *p; if( !job_get_flag( j, JOB_CONSTRUCTED ) ) continue; - - - validate_pointer( j->command, - _( L"Job command" ), + + + validate_pointer( j->command, + _( L"Job command" ), 0 ); validate_pointer( j->first_process, _( L"Process list pointer" ), 0 ); - validate_pointer( j->next, + validate_pointer( j->next, _( L"Job list pointer" ), 1 ); @@ -1191,7 +1191,7 @@ void proc_sanity_check() { if( fg_job != 0 ) { - debug( 0, + debug( 0, _( L"More than one job in foreground: job 1: '%ls' job 2: '%ls'"), fg_job->command, j->command ); @@ -1199,39 +1199,39 @@ void proc_sanity_check() } fg_job = j; } - + p = j->first_process; while( p ) - { + { validate_pointer( p->argv, _( L"Process argument list" ), 0 ); validate_pointer( p->argv[0], _( L"Process name" ), 0 ); validate_pointer( p->next, _( L"Process list pointer" ), 1 ); validate_pointer( p->actual_cmd, _( L"Process command" ), 1 ); - + if ( (p->stopped & (~0x00000001)) != 0 ) { debug( 0, _( L"Job '%ls', process '%ls' has inconsistent state \'stopped\'=%d" ), - j->command, + j->command, p->argv[0], p->stopped ); sanity_lose(); } - + if ( (p->completed & (~0x00000001)) != 0 ) { debug( 0, _( L"Job '%ls', process '%ls' has inconsistent state \'completed\'=%d" ), - j->command, + j->command, p->argv[0], p->completed ); sanity_lose(); } - + p=p->next; } - - } + + } } void proc_push_interactive( int value ) |