void job_continue(job_t *j, bool cont) { // Put job first in the job list. job_promote(j); j->set_flag(JOB_NOTIFIED, false); CHECK_BLOCK(); debug(4, L"%ls job %d, gid %d (%ls), %ls, %ls", cont ? L"Continue" : L"Start", 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 (j->get_flag(JOB_TERMINAL) && j->get_flag(JOB_FOREGROUND)) { // Put the job into the foreground. Hack: ensure that stdin is marked as blocking first // (issue #176). make_fd_blocking(STDIN_FILENO); if (!terminal_give_to_job(j, cont)) return; } // Send the job a continue signal, if necessary. if (cont) { for (process_ptr_t &p : j->processes) p->stopped = false; if (j->get_flag(JOB_CONTROL)) { if (killpg(j->pgid, SIGCONT)) { wperror(L"killpg (SIGCONT)"); return; } } else { for (const process_ptr_t &p : j->processes) { if (kill(p->pid, SIGCONT) < 0) { wperror(L"kill (SIGCONT)"); return; } } } } if (j->get_flag(JOB_FOREGROUND)) { // Look for finished processes first, to avoid select() if it's already done. process_mark_finished_children(false); // Wait for job to report. while (!reader_exit_forced() && !job_is_stopped(j) && !job_is_completed(j)) { // debug( 1, L"select_try()" ); switch (select_try(j)) { case 1: { read_try(j); process_mark_finished_children(false); break; } case 0: { // No FDs are ready. Look for finished processes. process_mark_finished_children(false); 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. // // This will return early if we get a signal, like SIGHUP. process_mark_finished_children(true); break; } default: { DIE("unexpected return value from select_try()"); break; } } } } } if (j->get_flag(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); const std::unique_ptr<process_t> &p = j->processes.back(); // Mark process status only if we are in the foreground and the last process in a pipe, // and it is not a short circuited builtin. if ((WIFEXITED(p->status) || WIFSIGNALED(p->status)) && p->pid) { int status = proc_format_status(p->status); // fwprintf(stdout, L"setting status %d for %ls\n", job_get_flag( j, JOB_NEGATE // )?!status:status, j->command); proc_set_last_status(j->get_flag(JOB_NEGATE) ? !status : status); } } // Put the shell back in the foreground. if (j->get_flag(JOB_TERMINAL) && j->get_flag(JOB_FOREGROUND)) { terminal_return_from_job(j); } } }
void job_continue (job_t *j, int cont) { /* 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) { // 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); } 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 )) { 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; } } }
void job_continue(job_t *j, bool cont) { /* 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. Hack: ensure that stdin is marked as blocking first (#176). */ make_fd_blocking(STDIN_FILENO); signal_block(); bool 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)) { /* Look for finished processes first, to avoid select() if it's already done. */ process_mark_finished_children(false); /* Wait for job to report. */ while (! reader_exit_forced() && ! job_is_stopped(j) && ! job_is_completed(j)) { // debug( 1, L"select_try()" ); switch (select_try(j)) { case 1: { read_try(j); process_mark_finished_children(false); break; } case 0: { /* No FDs are ready. Look for finished processes. */ process_mark_finished_children(false); 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. This will return early if we get a signal, like SIGHUP. */ process_mark_finished_children(true); 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 circuited 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; } } }