After suspending child process with SIGTSTP, shell not responding - shell

I'm coding a basic shell in C, and I'm working on suspending a child process right now.
I think my signal handler is correct, and my child process is suspending, but after that, the terminal should return to the parent process and that's not happening.
The child is suspended, but my shell isn't registering any input or output anymore. tcsetpgrp() doesn't seem to be helping.
Here's my signal handler in my shell code for SIGTSTP:
void suspend(int sig) {
pid_t pid;
sigset_t mask;
//mpid is the pgid of this shell.
tcsetpgrp(STDIN_FILENO, mpid);
tcsetpgrp(STDOUT_FILENO, mpid);
sigemptyset(&mask);
sigaddset(&mask, SIGTSTP);
sigprocmask(SIG_UNBLOCK, &mask, NULL);
signal(SIGTSTP, SIG_DFL);
//active.pid is the pid of the child currently in the fg.
if (active.pid != 0) {
kill(active.pid, SIGTSTP);
}
else{
//if this code is being run in the child, child calls SIGTSTP on itself.
pid = getpid();
if (pid != 0 && pid != mpid){
kill(pid, SIGTSTP);
}
}
signal(SIGTSTP, suspend);
}
Can anyone tell me what I'm doing wrong?
Am I suspending my shell along with the child, and do I need to return stdin and stdout to the shell somehow? How would I do this?
Thanks!

It's an old question but still I think I found an answer.
You didn't write your parent's code but I'm assuming its looks something like:
int main(){
pid_t pid = fork();
if(pid == 0) //child process
//call some program
else //parent process
wait(&status); //or waitpid(pid, &status, 0)
//continue with the program
}
the problem is with the wait() or waitpid(), it's look like if you run your program on OS like Ubuntu after using Ctrl+Z your child process is getting the SIGTSTP but the wait() function in the parent process is still waiting!
The right way of doing that is to replace the wait() in the parent with pause(), and make another handler that catch SIGCHLD. For example:
void sigHandler(int signum){
switch(signum){
case SIGCHLD:
// note that the last argument is important for the wait to work
waitpid(-1, &status, WNOHANG);
break;
}
}
In this case after the child process receive Ctrl+Z the parent process also receive SIGCHLD and the pause() return.

tcsetpgrp is to specify what is the foreground job. When your shell spawns a job in foreground (without &), it should create a new process group and make that the foreground job (of the controlling terminal, not whatever's on STDIN). Then, upon pressing CTRL-Z, that job will get the TSTP. It's the terminal that suspends the job, not your shell. Your shell shouldn't trap TSTP or send TSTP to anyone.
It should just wait() for the job it has spawned and detect when it has been stopped (and claim back the foreground group and mark the job as suspended internally). Your fg command would make the job's pgid the foreground process group again and send a SIGCONT to it and wait for it again, while bg would just send the SIGCONT

i used folk with signals for make process pause and resume with ctrl+c
video while is running : link
Code:
#include <stdio.h>
#include <unistd.h>
#include <signal.h>
void reverse_handler(int sig);
_Bool isPause=0;
_Bool isRunning=1;
int main()
{
int ppid;
int counter=0;
//make parent respond for ctrl+c (pause,resume).
signal(SIGINT,reverse_handler);
while(isRunning){
while(isPause==0)
{
/*code exec while process is resuming */
printf("\nc:%d",counter++);
fflush(stdout);
sleep(1);
}
//close parent after child is alive.
if((ppid=fork())==0){ exit(0); }
//make child respond for ctrl+c (pause,resume).
signal(SIGINT,reverse_handler);
//keep child alive and listening.
while(isPause==1){ /*code exec while process is pausing */ sleep(1); }
}
return 0;
}
//if process is pause made it resume and vice versa.
void reverse_handler(int sig){
if(isPause==0){
printf("\nPaused");
fflush(stdout);
isPause=1;
}
else if(isPause==1){
printf("\nresuming");
fflush(stdout);
isPause=0;
}
}
i hope that's be useful.
please comment me if there's any questions

I might be late to answer the question here but this is what worked when I was stuck with the same problem. According to the man pages for tcsetpgrp()
The function tcsetpgrp() makes the process group with process group ID
pgrp the foreground process group on the terminal associated to fd,
which must be the controlling terminal of the calling process, and
still be associated with its session. Moreover, pgrp must be a
(nonempty) process group belonging to the same session as the calling
process.
If tcsetpgrp() is called by a member of a background process group in
its session, and the calling process is not blocking or ignoring
SIGTTOU, a SIGTTOU signal is sent to all members of this background
process group.
So, what worked for me was ignoring the signal SIGTTOU in the shell program, before I created the processes that would come to the foreground. If I do not ignore this signal, then the kernel will send this signal to my shell program and suspend it.

Related

MINIX stripped down shell example

I came across a stripped down shell program in Tannenbaum's book on MINIX.
while(1) {
read_command(command, parameters);
if (fork() != 0)
wait(&status); /* parent code */
}
else {
execve(command, parameters, 0); /* child code */
}
}
When the infinite loop executes its first iteration, fork() will return 0 indicating it created a child process, when it executes the second time, wont fork() create a new child process ? How wait(&status) will ever execute?
I am new to understanding how an OS works/is built.
Thanks!
fork creates a new process immediately, so both processes see fork return, but with different return values. In the parent, the return value is the non-zero process ID of the child, so the parent executes wait. In the child, fork returns 0, so the child executes execve.

Child process won't suicide if parent dies

I have a subprocess (running on MacOS) that I want to kill itself if the parent quits, exits, terminates, is killed or crashes. Having followed the advice from How to make child process die after parent exits? I can't get it to quietly kill itself if the parent program crashes. It will go to 100% CPU until I manually kill it.
Here are the key points of the code:
int main(int argc, char *argv[])
{
// Catch signals
signal(SIGINT, interruptHandler);
signal(SIGABRT, interruptHandler);
signal(SIGTERM, interruptHandler);
signal(SIGPIPE, interruptHandler);
// Create kqueue event filter
int kqueue_fd = kqueue();
struct kevent kev, recv_kev;
EV_SET(&kev, parent_pid, EVFILT_PROC, EV_ADD|EV_ENABLE, NOTE_EXIT, 0, NULL);
kevent(kqueue_fd, &kev, 1, NULL, 0, NULL);
struct pollfd kqpoll;
kqpoll.fd = kqueue_fd;
kqpoll.events = POLLIN;
// Start a run loop
while(processEvents())
{
if(kill(parent_pid, 0) == -1)
if(errno == ESRCH)
break;
if(poll(&kqpoll, 1, 0) == 1)
if(kevent(kqueue_fd, NULL, 0, &recv_kev, 1, NULL))
break;
parent_pid = getppid();
if(parent_pid == 1)
break;
sleep(a_short_time);
// (simple code here causes subprocess to sleep longer if it hasn't
// received any events recently)
}
}
Answering my own question here:
The reason for this problem was not down to detecting whether the parent process had died. In processEvents() I was polling the pipe from the parent process to see if there was any communication. When the parent died, poll() returned a value of 1 and the read loop thought there was infinite data waiting to be read.
The solution was to detect whether the pipe had been disconnected or not.

Emulating pipes

I've just recently learned about pipes and I would like to emulate the "|" gimmick provided by shells.
In the code below, the parent process spawns 2 child processes, after which they do their piping and get replaced by ls and grep. While that happens the parent process waits patiently. The problem is that the child processes never finish although they manage to send some data though the pipe and onto the screen.
There are other posts regarding pipes on SO, but I've never seen the setup in which the parent process launches 2 children. I've only seen the parent communicating with one child.
int p0[2];
pipe(p0); //creating pipe
if(fork() == 0) { //child 1
dup2(p0[0], STDIN_FILENO);
close(p0[0]); close(p0[1]);
execlp("grep","grep","a",NULL);
}
else { //parent
if(fork() == 0) { //child 2
dup2(p0[1], STDOUT_FILENO);
close(p0[0]); close(p0[1]);
execlp("ls","ls",NULL);
}
else { //parent
wait(NULL);
wait(NULL); //waiting for c1 and c2
close(p0[0]); close(p0[1]);
printf("parent exit\n");
}
}
My questions are: Why don't the child processes finish? Is fork-pipe structure sound or am I doing it completely wrong?
Close the pipe before starting to wait in the last section.

Debugging child processes- GDB/DDD

My project is to implement a simple shell program with background processing by way of ending an arglist with &, as in most UNIX shells. My problem is how to debug the shell in GDB when background processing requires child processes to be created.
My child processing code goes like
int id;
int child=-1;
int running=0;
if ((strcmp(args[0], "&")==0){
if ((id==fork())==-1)
perror("Couldn't start the background process");
else if (id==0){ //start the child process
running++;
printf("Job %d started, PID: %d\n", running, getpid());
signal(SIGINT, SIG_DFL);
signal(SIGQUIT, SIG_DFL);
execvp(args[0], args);
perror("Can't execute command);
exit(1);
else {
int jobNum= running-(running-1);
if ( (waitpid(-1, &child, WNOHANG) == -1)
perror("Child Wait");
else
printf("[%d] exited with status %d\n", jobNum, child>>8);
}
When I try to run a command, like ps &, and set the breakpoint to the function parser, the command executes without hitting the breakpoint. This is confusing and renders the debugger useless in this instance. What can I do about it?
I think you want
set follow-fork-mode child
also note that the line
if ((id==fork())==-1)
is comparing an uninitialized value against the return value of fork().
I believe you wanted an assignment.

Waiting for grandchild processes in windows

Is it possible to wait for all processes launched by a child process in Windows? I can't modify the child or grandchild processes.
Specifically, here's what I want to do. My process launches uninstallA.exe. The process uninistallA.exe launches uninstallB.exe and immediately exits, and uninstallB.exe runs for a while. I'd like to wait for uninstallB.exe to exit so that I can know when the uninstall is finished.
Create a Job Object with CreateJobObject. Use CreateProcess to start UninstallA.exe in a suspended state. Assign that new process to your job object with AssignProcessToJobObject. Start UninstallA.exe running by calling ResumeThread on the handle of the thread you got back from CreateProcess.
Then the hard part: wait for the job object to complete its execution. Unfortunately, this is quite a bit more complex than anybody would reasonably hope for. The basic idea is that you create an I/O completion port, then you create the object object, associate it with the I/O completion port, and finally wait on the I/O completion port (getting its status with GetQueuedCompletionStatus). Raymond Chen has a demonstration (and explanation of how this came about) on his blog.
Here's a technique that, while not infallible, can be useful if for some reason you can't use a job object. The idea is to create an anonymous pipe and let the child process inherit the handle to the write end of the pipe.
Typically, grandchild processes will also inherit the write end of the pipe. In particular, processes launched by cmd.exe (e.g., from a batch file) will inherit handles.
Once the child process has exited, the parent process closes its handle to the write end of the pipe, and then attempts to read from the pipe. Since nobody is writing to the pipe, the read operation will block indefinitely. (Of course you can use threads or asynchronous I/O if you want to keep doing stuff while waiting for the grandchildren.)
When (and only when) the last handle to the write end of the pipe is closed, the write end of the pipe is automatically destroyed. This breaks the pipe and the read operation completes and reports an ERROR_BROKEN_PIPE failure.
I've been using this code (and earlier versions of the same code) in production for a number of years.
// pwatch.c
//
// Written in 2011 by Harry Johnston, University of Waikato, New Zealand.
// This code has been placed in the public domain. It may be freely
// used, modified, and distributed. However it is provided with no
// warranty, either express or implied.
//
// Launches a process with an inherited pipe handle,
// and doesn't exit until (a) the process has exited
// and (b) all instances of the pipe handle have been closed.
//
// This effectively waits for any child processes to exit,
// PROVIDED the child processes were created with handle
// inheritance enabled. This is usually but not always
// true.
//
// In particular if you launch a command shell (cmd.exe)
// any commands launched from that command shell will be
// waited on.
#include <windows.h>
#include <stdio.h>
void error(const wchar_t * message, DWORD err) {
wchar_t msg[512];
swprintf_s(msg, sizeof(msg)/sizeof(*msg), message, err);
printf("pwatch: %ws\n", msg);
MessageBox(NULL, msg, L"Error in pwatch utility", MB_OK | MB_ICONEXCLAMATION | MB_SYSTEMMODAL);
ExitProcess(err);
}
int main(int argc, char ** argv) {
LPWSTR lpCmdLine = GetCommandLine();
wchar_t ch;
DWORD dw, returncode;
HANDLE piperead, pipewrite;
STARTUPINFO si;
PROCESS_INFORMATION pi;
SECURITY_ATTRIBUTES sa;
char buffer[1];
while (ch = *(lpCmdLine++)) {
if (ch == '"') while (ch = *(lpCmdLine++)) if (ch == '"') break;
if (ch == ' ') break;
}
while (*lpCmdLine == ' ') lpCmdLine++;
sa.nLength = sizeof(sa);
sa.bInheritHandle = TRUE;
sa.lpSecurityDescriptor = NULL;
if (!CreatePipe(&piperead, &pipewrite, &sa, 1)) error(L"Unable to create pipes: %u", GetLastError());
GetStartupInfo(&si);
if (!CreateProcess(NULL, lpCmdLine, NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi))
error(L"Error %u creating process.", GetLastError());
if (WaitForSingleObject(pi.hProcess, INFINITE) == WAIT_FAILED) error(L"Error %u waiting for process.", GetLastError());
if (!GetExitCodeProcess(pi.hProcess, &returncode)) error(L"Error %u getting exit code.", GetLastError());
CloseHandle(pipewrite);
if (ReadFile(piperead, buffer, 1, &dw, NULL)) {
error(L"Unexpected data received from pipe; bug in application being watched?", ERROR_INVALID_HANDLE);
}
dw = GetLastError();
if (dw != ERROR_BROKEN_PIPE) error(L"Unexpected error %u reading from pipe.", dw);
return returncode;
}
There is not a generic way to wait for all grandchildren but for your specific case you may be able to hack something together. You know you are looking for a specific process instance. I would first wait for uninstallA.exe to exit (using WaitForSingleObject) because at that point you know that uninstallB.exe has been started. Then use EnumProcesses and GetProcessImageFileName from PSAPI to find the running uninstallB.exe instance. If you don't find it you know it has already finished, otherwise you can wait for it.
An additional complication is that if you need to support versions of Windows older than XP you can't use GetProcessImageFileName, and for Windows NT you can't use PSAPI at all. For Windows 2000 you can use GetModuleFileNameEx but it has some caveats that mean it might fail sometimes (check docs). If you have to support NT then look up Toolhelp32.
Yes this is super ugly.
Use a named mutex.
One possibility is to install Cygwin and then use the ps command to watch for the grandchild to exit

Resources