0% found this document useful (0 votes)
4 views2 pages

Unix Process Management Exercises

The document outlines three exercises focused on Unix system calls for process and IO management. Exercise 1 involves creating a process to execute a print binary that receives output from a gendoc binary. Exercise 2 requires implementing communication between two programs, A and B, while Exercise 3 involves creating a C program that mimics the shell command 'ps -ef | grep firefox | wc -l' using multiple processes and pipes.

Uploaded by

nq796065
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
4 views2 pages

Unix Process Management Exercises

The document outlines three exercises focused on Unix system calls for process and IO management. Exercise 1 involves creating a process to execute a print binary that receives output from a gendoc binary. Exercise 2 requires implementing communication between two programs, A and B, while Exercise 3 involves creating a C program that mimics the shell command 'ps -ef | grep firefox | wc -l' using multiple processes and pipes.

Uploaded by

nq796065
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd

Exercice 1

In this exercise, we rely on Unix system calls for process management and IO management.
You must use the following system calls: fork(), execvp(), pipe(), dup2(), close()

We assume that 2 binaries are accessible in the PATH:


• gendoc allows to generate a document. The document is written on the standard output of
the process.
• print allows to print document on the printer. The document is read from the standard input
of the process.
You must write a program which:
• creates one process which executes the print binary
• the program then executes the gendoc binary
• the output from gendoc is transmitted to the input of print

Print
stdin
Gendoc

stdout

Exercice 2
We want to implement the following communication pattern between two programs A and B.

Program A Program B

resA = Acompute1(); resB = Bcompute1();


printf(“%d”,resA); printf(“%d”,resB);
scanf(“%d”, &resB); scanf(“%d”, &resA);
Acompute2(resB); Bcompute2(resA);

Program A writes its result from Acompute1() to STDOUT, then it reads the result from B from
STDIN in order to perform the second computation Acompute2(). Symmetrically, Program B
writes its result from Bcompute1() to STDOUT, then it reads the result from A from STDIN in
order to perform the second computation Bcompute2().

You must write a program (main.c) that will create 2 processes that execute programs A and B,
the STDOUT of program A being redirected to the STDIN of program B and the STDOUT of
program B being redirected to the STDIN of program A.
Exercice 3

We want to implement a C program that implements the same behavior as the following shell
command:
ps -ef | grep firefox | wc -l

Your program has to create 3 processes that respectively execute the ps, grep and wc binaries that
are accessible from your path variable. The standard input and output of these processes are
interconnected with pipes to implement the requested communication flow.
Here is a list of the Unix functions that you should use in your program:
int fork();
int execlp(char *file, char *arg, ...);
void perror(const char *s);
int pipe(int pipefd[2]);
int dup2(int oldfd, int newfd);
int close(int fd);

Common questions

Powered by AI

Pipes are critical for enabling inter-process communication, acting as connective conduits for data streams between processes. They ensure orderly data exchange, allowing output from one process to be input to another seamlessly. Incorrect implementation can lead to broken data flows, resulting in processes attempting to read from empty buffers (leading to blocking) or failing to redirect outputs correctly, causing data to be lost or misdirected. Furthermore, improperly closed pipes can lead to resource leaks or deadlocks, where processes wait indefinitely for data exchanges that never complete .

Synchronization between two processes like programs A and B involves managing concurrent reads and writes without data races or deadlocks. Using pipes, the main challenge is ensuring both processes' STDOUT writes are correctly received and processed by the other's STDIN. This requires careful ordering—writing must be completed before reading is attempted, necessitated by the non-blocking nature of system calls, which can lead to partial reads or timing mismatches. Additionally, using select() or implementing reader-writer locks can offer necessary blocking mechanisms to orchestrate read-write execution states between dependent commands efficiently .

fork() is used to create a child process, necessary for running separate command line operations concurrently. execvp() replaces the child's process image with a specified program (such as a command in the pipeline), enabling it to run independently while maintaining original process attributes such as open file descriptors. dup2() is crucial in redirecting file descriptors, providing the means to alter standard input or output to read from or write to a pipe instead, effectively maintaining a flow of data between successive processes in a manner similar to shell-implemented pipelines .

This shell pipeline can be translated into a C program by creating separate processes for each command (ps, grep, wc) and using pipes to connect their standard inputs and outputs. The process is initiated by fork(), creating three child processes. execlp() is used to execute each command within the process. As each command reads from the previous command's output, pipe() is employed to create a linear data flow: ps outputs to the first pipe, grep reads from this output, and its output is then piped to wc. dup2() redirects stdout of each process to the next command's stdin, maintaining the command flow as in the shell pipeline .

Unix system calls provide a low-level interface to control the execution environment of applications. For the gendoc and print binaries, fork() is used to create a new process specifically for executing print, allowing separate execution threads. execvp() is then utilized to replace the current process image with the gendoc binary, which produces output to STDOUT. Communication between these binaries is managed with pipe(), enabling the direct transmission of gendoc's output to print's input via a pipe file descriptor. This file descriptor is redirected using dup2() to bridge the standard input and output streams of the processes effectively .

Pipes allow for directed, synchronous data communication between processes, emulating stream-like behavior that interconnects sequential execution inputs and outputs. In the case of gendoc and print, a pipe is employed to redirect the output of gendoc to the input of print without intermediate storage. Redirection through dup2() maps these communication streams to appropriate file descriptors, allowing the piped data from gendoc to directly reach print, ensuring efficient, real-time document generation and printing without extra I/O overhead .

The inter-process communication pattern between programs A and B is a bidirectional data exchange where each program's computations rely on data from the other. Program A performs Acompute1() and outputs the result to STDOUT; this output becomes the STDIN of Program B. Program B's computation Bcompute1() outputs to STDOUT, which is read by Program A. Implementing this in C requires creating pipes to transmit these STDOUT outputs to the respective STDIN inputs. The processes must be forked to allow concurrent execution, and dup2() is pivotal for redirecting output to input streams .

Implementing error handling involves checking the return values of all system calls, as they return -1 upon failure, setting errno. For instance, fork() should be checked for negative returns to detect process creation failures. Similarly, execvp() needs checks, with perror() providing detailed error descriptions. Moreover, pipe() and dup2() both need validation to prevent issues in data stream readiness and redirection. Implementing robust error handling also requires managing cleanup processes, such as releasing file descriptors using close() in case of failure, to prevent resource leaks .

System calls provide direct interfacing with the operating system's kernel, enabling lower-level control and efficiency benefits that traditional high-level constructs don't offer. For process management, fork() allows seamless process creation with minimal overhead, while execvp() facilitates command execution without spawning additional I/O redirections manually. For I/O management, pipes and related calls (dup2(), pipe()) offer optimized, memory-safe data streams between processes. These approaches allow fine-grained, high-performance management of concurrent operations, yielding system-level resource control and optimal communication pattern implementation .

When executing different binaries sequentially in C to emulate a shell command, consideration must be given to process execution and correct data flow via piping. It's critical to ensure that each process correctly inherits its execution environment using fork() and that execvp() replaces these processes appropriately with their respective binaries. Inter-process data must flawlessly transition from one process's standard output to another's standard input, necessitating the precise use of pipes and dup2() to establish input/output redirection. Each stage's process must be initiated and completed with order precision to maintain functional interdependencies .

You might also like