Search code examples
cpidjob-control

Implementing shell-like job control in C


I am trying to implement simple shell in C language and i am having a hard time implementing job control. Everything online seems complicated enough and i think some simplicity is always good. So let me ask this ... After fork() is called can i handle Ctrl-Z signal with just 2 function and just with the pid ?

I want to call a function e.x. put_background(pid_t pid) when i hit Ctrl-Z and make process with pid = pid to run background and finally call another function e.x. put_foreground(pid_t pid) when i write fg and i want the process with pid = pid to go to foreground again.

So, is this possible? Any help is appreciated.. code more however.


Solution

  • I am trying to implement simple shell in C language and i am having a hard time implementing job control. Everything online seems complicated enough and i think some simplicity is always good.

    So let me ask this ... After fork() is called can i handle Ctrl-Z signal with just 2 function and just with the pid ?

    Note that Ctrl-Z is meaningful primarily to the terminal driver. It causes a SIGTSTP to be sent to the foreground process group of the terminal in which that character was typed -- that is, the process group that has that terminal as its controlling one, and has permission to read from it. By default, this causes the processes in that group to stop, but that's it. You don't need to do anything to achieve that.*

    I want to call a function e.x. put_background(pid_t pid) when i hit Ctrl-Z and make process with pid = pid to run background and finally call another function e.x. put_foreground(pid_t pid) when i write fg and i want the process with pid = pid to go to foreground again.

    By definition and design, at most one process group has control of a given terminal at any particular time. Thus, to move a foreground job to the background, all you need to do is move a different one to the foreground. That can be the shell itself or some other job under its control. The tcsetpgrp() library function accomplishes this. Unless it's the shell itself, you would also want to send a SIGCONT to that process group in case it was stopped.

    You additionally need a mechanism to resume a stopped background job, but that's easy: just send that process group a SIGCONT.

    So, is this possible? Any help is appreciated.. code more however.

    Well sure, you could write one function for moving a job to the foreground and resuming it, and one for resuming a background job. The only information these functions need about the jobs they operate on is their process group IDs (which is the same as the process IDs of their initial processes).

    But you also need to maintain some bookkeeping of the current active jobs, and you need to take some care about starting new jobs, and you need to monitor current jobs -- especially the foreground job -- so as to be able to orchestrate all of the transitions appropriately.

    The GLIBC manual has an entire chapter on job control, including a substantial section specifically on implementing a job-control shell. This would probably be useful to you even if you are not writing for a GLIBC-based system. The actual code needed is not all that complicated, but getting it right requires a good understanding of a fairly wide range of concepts.


    *But you do need to ensure that your shell puts commands it launches into process groups different from its own, else a Ctrl-Z will stop it, too.