Job Control
Job and process tracking for foreground/background execution.
A job is one pipeline launched by the shell (foreground or background). Each job has its own process group (pgid) so the controlling terminal can deliver signals to the whole pipeline at once, and so the shell can suspend or resume it independently of itself.
- Author
pulgamecanica
t_shell.jobs:t_list*oft_job*(one entry per known job)t_job.processes:t_list*oft_process*(one entry per pipeline stage)
Enums
-
enum t_job_status
Lifecycle state of a job, recomputed from its processes.
Values:
-
enumerator JOB_RUNNING
At least one process is still running and none stopped.
-
enumerator JOB_STOPPED
At least one process received SIGTSTP/SIGSTOP (Ctrl-Z).
-
enumerator JOB_DONE
Every process exited normally (any exit code).
-
enumerator JOB_TERMINATED
At least one process was killed by a signal.
-
enumerator JOB_RUNNING
Functions
-
int job_control_init(struct s_shell *shell)
Place the shell in its own process group and claim the terminal.
Idempotent when the shell is already a session leader. Skipped when
shell->interactiveis 0 (job control is a no-op without a controlling TTY). On returnshell->shell_pgidis authoritative andshell->original_termiosholds the saved terminal settings.- Returns:
0 on success, 1 on
setpgidfailure.
-
t_job *job_create(struct s_shell *shell, const char *cmd_line)
Allocate a job, append it to
shell->jobs, and make itcurrent_job.The next free id is
max(existing ids) + 1.cmd_lineis duplicated withft_strdupand released byjob_free.- Returns:
Newly created job, or NULL on allocation failure.
-
void job_add_process(t_job *job, pid_t pid, const char *cmd)
Register a forked child as a stage of
job.Appends a
t_processtojob->processes.cmdis duplicated.
-
t_job *job_find_by_pid(struct s_shell *shell, pid_t pid)
Find the job containing a given pid, or NULL.
-
t_job *job_find_by_spec(struct s_shell *shell, const char *spec)
Resolve a bash-style job spec to a
t_job*.Accepted forms: NULL / “” / “%” / “%+” / “%%” → current job; “%-” → the job preceding the current one; “%N” → id N; “%prefix” → first job whose
cmd_linestarts withprefix.- Returns:
Matching job or NULL if spec is malformed / no such job.
-
void job_free(void *job_ptr)
Free a job and all of its processes.
Matches the
void (*)(void *)deleter signature offt_lstdel.
-
void job_remove(struct s_shell *shell, t_job *job)
Unlink
jobfromshell->jobsand release it.Clears
shell->current_jobif it referenced the removed job. No-op ifjobis not in the list (silent for safety).
-
int job_launch_background(struct s_shell *shell, t_job *job)
Hand a job off to the background and print
[id] pgidon stderr.The child was already forked with its own pgid by the caller. This does not wait - the job is reaped later by
job_update_statusesbetween prompts.- Returns:
0 on success, 1 if
jobis NULL.
-
int job_launch_foreground(struct s_shell *shell, t_job *job)
Hand the terminal to
job, wait for it, then take it back.Uses
tcsetpgrp(terminal_fd, job->pgid)to transfer terminal ownership soSIGINT/SIGTSTPreach the pipeline. Afterjob_waitreturns, the shell reclaims the terminal and restores its saved termios. Non-interactive shells skip the tc* handoff and just reap the pgid.- Returns:
Exit status of the pipeline (last completed process), or 128+WSTOPSIG if the job was stopped.
-
int job_continue_foreground(struct s_shell *shell, t_job *job)
Resume a stopped job in the foreground.
Sends
SIGCONTto the job’s pgid, hands the terminal back to it, and waits. Leaves the job inshell->jobsif it stops again, removes it on completion.- Returns:
Exit status, or 128+WSTOPSIG if stopped again.
-
int job_continue_background(struct s_shell *shell, t_job *job)
Resume a stopped job in the background.
Sends
SIGCONTand prints[id] cmd_line &on stderr. Does not wait - the job is reaped between prompts like any bg job.- Returns:
0 on success, 1 on invalid input or
killfailure.
-
int job_wait(struct s_shell *shell, t_job *job)
Blocking reap of every process in
job.Loops
waitpid(-pgid, ..., WUNTRACED)until every process is completed or at least one is stopped. Per-process flags and the aggregatestatusare updated in place.- Returns:
Exit status of the last completed process, 128+WSTOPSIG on stop, -1 on unrecoverable waitpid error.
-
int job_apply_status(t_job *job, pid_t pid, int status)
Apply a single
waitpidresult to one process ofjob.Updates
status,completed,stopped, clearsnotified, and flips the aggregatestatusto JOB_TERMINATED on a signalled death. Does not recompute running/stopped - calljob_recompute_statusafterwards.- Returns:
1 if
pidbelonged to this job, 0 otherwise.
-
void job_recompute_status(t_job *job)
Recompute
job->statusfrom the flags of its processes.Result is JOB_DONE (all completed, no signalled), JOB_TERMINATED (preserved if set by
job_apply_status), JOB_STOPPED (any stopped), or JOB_RUNNING. Idempotent.
-
void job_update_statuses(struct s_shell *shell)
Non-blocking reap of every shell-owned child.
Loops
waitpid(-1, ..., WNOHANG | WUNTRACED | WCONTINUED)until there is nothing more to collect. Updates per-process flags and recomputes the owning job’sstatus. Safe to call when no jobs are tracked.
-
void job_notify(struct s_shell *shell)
Print a status line for every job that has not been notified yet, then drop JOB_DONE / JOB_TERMINATED jobs from
shell->jobs.Call between prompts.
shell->current_jobis cleared if it referenced a job that gets removed.
-
const char *job_status_str(t_job_status s)
Human-readable label for a
t_job_statusvalue (for listings).
-
void job_print_line(int fd, struct s_shell *shell, t_job *job)
Print one job listing line, bash-compatible.
Format: “[N]M Status[(SIG)]<pad> cmd-line\n”, where M is the current-job marker (‘+’, ‘-’, or ‘ ‘) and (SIG) is appended only for non-SIGTSTP stops or signal-terminated jobs.
- Parameters:
fd – File descriptor to write to (STDOUT for
jobs, STDERR for auto-notifications).
-
void job_print_termination(t_job *job)
Print “Segmentation fault (core dumped)”-style message for a foreground job whose last process died by signal.
Mirrors bash’s foreground signal-death output. Silent for SIGINT and SIGPIPE (bash suppresses those to avoid noise from Ctrl-C and broken-pipe situations). Adds “ (core dumped)” when WCOREDUMP indicates a core file was produced.
-
void job_control_cleanup(struct s_shell *shell)
Release every job and process still tracked by
shell.Called from
shell_cleanupon exit. Leavesshell->jobsNULL andshell->current_jobNULL.
-
struct t_process
- #include <job_control.h>
A single process belonging to a job (one pipeline stage).
Stored in
t_job.processesas thecontentof at_listnode. Reaped and updated byjob_update_statuses.Public Members
-
pid_t pid
Child pid returned by fork().
-
char *cmd
Human-readable description of this stage (for listings).
-
int status
Raw
wstatusvalue from the last waitpid() on this pid.
-
int completed
1 once the process has exited (normally or by signal).
-
int stopped
1 while the process is stopped (SIGTSTP/SIGSTOP).
-
pid_t pid
-
struct t_job
- #include <job_control.h>
One pipeline launched by the shell (background or foreground).
Stored in
t_shell.jobsas thecontentof at_listnode. Built byjob_create, grown byjob_add_process, reaped byjob_update_statuses, and released byjob_free(either viajob_notifywhen completed, orjob_control_cleanupon exit).Public Members
-
int id
Shell-assigned sequential id (1-based); used by
Njob-spec and byjobslistings.
-
pid_t pgid
Process-group id shared by every pipeline stage.
-
char *cmd_line
Displayed by
jobs/notifications. Built from the AST subtree viaast_to_string, not the raw input line, sols ; sleep 5 &shows onlysleep 5.
-
t_list *processes
t_list*oft_process*- one per pipeline stage.
-
t_job_status status
Aggregate lifecycle state (see
t_job_status).
-
int notified
1 once the user has been informed about the current
status; cleared wheneverstatuschanges so the nextjob_notifyprints it again.
-
int foreground
1 if the job currently owns the controlling terminal.
-
int id