Пример #1
0
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);
        }
    }
}
Пример #2
0
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;
			
		}
	}
	
}
Пример #3
0
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;

        }
    }

}