Open-Source Internship opportunity by OpenGenus for programmers. Apply now.
A process is a running instance of a program, it starts when a command/program is executed/started. In this article we discuss various process manipulation functions and their implementation in the Linux system.
Table of contents.
- Introduction.
- Listing processes.
- Creating processes.
- Scheduling processes.
- Summary.
- References.
Introduction.
A process is a running instance of a program, i.e running having two terminals open means running two terminal programs. These terminals might each run a shell and the shells can be running other processes. In this article we describe processes manipulation functions some of which are declared in the <unistd.h> header file.
This article is meant to discuss process functions in Linux, we have discussed process management commands in another article, the link is provided in the references section.
Listing processes.
Every program uses one or more processes. To view processes you can execute the ps command.
PIDs.
Each Linux process is identified by a process id, which is a 16-bit number assigned to a process sequentially as it is created.
Every process has a parent process the ppid is the PID of the parent process.
The getpid() system call is used by a program to obtain its process id and getppid() to obtain process id of its parent.
#include <stdio.h>
#include <unistd.h>
int main (){
printf (“The process ID is %d\n”, (int) getpid ());
printf (“The parent process ID is %d\n”, (int) getppid ());
return 0;
}
Active processes.
In a previous article we have discussed the ps command which shows running processes.
ps
To get a detailed output, we write,
ps -e -o pid,ppid,command
-e is for displaying all processes.
-o pid,ppid,command specifies what output we want.
From the output, notice that the PID of the /bin/bash command is the PPID for the ps -e -o pid,ppid,command command.
Killing a process.
The kill command kills processes, it works by sending a SIGTERM/termination signal to the process.
Creating a process.
We can either create a process by using system or using fork and exec, the former although simple, it is inefficient and poses security risks and thus should be used sparingly, the latter is complex but flexible, faster and secure.
System
This function provides an easier way to execute commands within a program much like it was typed into a shell.
An example, ping.c
#include <stdlib.h>
int main (){
int returnVal;
returnVal = system (“ping 8.8.8.8 -c 3”);
return returnVal;
}
The above program runs 3 pings and displays the output as if the command was typed into the shell.
system function returns the exit status of the shell command, if the shell cannot be run, 127 is returned otherwise if there exists an error, -1 is returned.
This function is subject to the features, limitations and flaws of the system's shell(/bin/sh) and different shells can have different results on different Linux system.
Fork and exec.
fork makes a child processes that is the exact copy of its parent process.
exec family of functions can cause a process to cease being an instance of one program and instead become an instance of another.
We can create a new process as follows,
Use fork to create a copy of the current process.
Use exec to transform one of the processes into an instance of the program we want to create.
Fork
When fork is called a child process is created while the parent continues executing the program from the point fork was called.
This newly created child process executes the same program from the same place.
The child process will have a new PID different from its parent, we can use the getpid() to be sure.
The fork function will provide different return values for the two, for the parent its return value is the PID of the child and for the child process, its return value is zero.
Exec
When a program calls this function, the process ceases executing the program and begins executing a new program from the beginning assuming no error is encountered.
The exec family functions include,
- p functions - these have letter p in their names, they accept a program name and search for it using the provided name in the current execution path. e.g, execp, execlp.
- v functions - these functions have a letter v in their names, their accept the new program's argument list as a NULL-terminated array of pointers to strings. e.g execv, execvp, execve.
- l functions follow the same convention, they accept the new program's argument list using the C language varargs mechanism, they include, execl, execlp.
- e functions accept an additional argument(a NULL-terminated array of pointers to character strings) and an array of environment variables. they include execve, execle
Exec functions never return unless errors occur.
The passed argument list is similar to the specified command line arguments, in that, when a program is invoked from the shell, the shell sets the first element of the argument list as argv[0] to the name of the program, argv[1] to the first command-line argument, argv[2] to the second and so on. We shall see this in a program shortly.
Fork and exec
To run a subprogram within a program we first fork the process then exec the subprogram, this will allow the calling program to proceed with execution in the parent process while the calling program is replaced by the subprogram in the child process.
An example - fork-exec.c
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
int spawn (char* program, char** argList){
pid_t childPID;
// Duplicate process.
childPID = fork();
if (childPID != 0){
// parent process.
return childPID;
}else {
// execute program
execvp (program, argList);
// execvp returns if an error exists
fprintf (stderr, "An error occurred in execvp \n");
abort ();
}
}
int main (){
// ping's argument list
// argv[0] - program name, argv[1] - desination.
// argv[2] - options, argv[3] - end argument list with NULL.
char* argList[] = {"ping", "8.8.8.8", "-c3", NULL};
// Spawn a child process running "ping" command.
// Ignore returned child PID. */
spawn("ping", argList);
printf("FINISHED MAIN PROGRAM!! \n");
return 0;
}
Compilation and execution
gcc fork-exec.c
./a.out
Scheduling processes.
Parent and child processes are scheduled independently thereby there is no guarantee which runs first or how long it takes before it is interrupted. e.g ls command may run in the child process before the parent completes.
Eventually all process will run.
A niceness value specifies a process' priority and the lower the niceness value the higher the process' priority. Only processes with root privileges can run programs with -ve niceness values so as to prevent ordinary users grabbing execution priority away from others.
An example
nice -n 10 sort input.txt > output.txt
The above command executes the processes with a 10 niceness value, assuming that input.txt is a very large file, we reduce the process priority so as not to slow the system down.
Programmatically, the niceness function takes the priority value as its argument.
Summary.
Processes can be leveraged by applications so as to allow them to multi-task thereby increasing their robustness. This can be done by making use of already existing processes.
In this article at OpenGenus, we have discuss listing, creation and scheduling of processes as implemented in the Linux operating system.
References.
- Process management commands.
- Advanced Programming in the UNIX Environment 3rd Edition W. Richard Stevens