When you run a program, the code that will be executed is stored in a disk file. In general, a process can't write to the memory area. The area is for holding the program code so that the code can be loaded into memory as read-only (so, it can be safely shared).
ps command shows the processes-e option and -f to get full information (ps -ef) like last week's exerciseHere is the STAT output from ps:
$ ps -ax
  PID TTY      STAT   TIME COMMAND
    1 ?        Ss     1:48 init [3]
    2 ?        S<     0:03 [migration/0]
    3 ?        SN     0:00 [ksoftirqd/0]
 ....
 2981 ?        S<sl  10:14 auditd
 2983 ?        S<sl   3:43 /sbin/audispd
 ....
 3428 ?        SLs    0:00 ntpd -u ntp:ntp -p /var/run/ntpd.pid -g
 3464 ?        Ss     0:00 rpc.rquotad
 3508 ?        S<     0:00 [nfsd4]
 ....
 3812 tty1     Ss+    0:00 /sbin/mingetty tty1
 3813 tty2     Ss+    0:00 /sbin/mingetty tty2
 3814 tty3     Ss+    0:00 /sbin/mingetty tty3
 3815 tty4     Ss+    0:00 /sbin/mingetty tty4
.....
19874 pts/1    R+     0:00 ps -ax
19875 pts/1    S+     0:00 more
21033 ?        Ss     0:39 crond
24765 ?        Ss     0:01 /usr/sbin/httpd
init  PID TTY      STAT   TIME COMMAND
    1 ?        Ss     1:48 init [3]
init, with process ID 1.
init or by other processes started by init.init starts the getty program once for each terminal that we can use to log in, and it is shown in the ps. 3812 tty1     Ss+    0:00 /sbin/mingetty tty1
init again...The getty processes wait for activity at the terminal,
init starts another getty process.The ability to start new processes and to wait for them to finish is fundamental to the system.
You can do the same thing within your own programs with the system calls fork(), exec(), and wait().
A system call is a controlled entry point into the kernel, allowing a process to request that the kernel perform some action for the process.
Changes the processor state from user to kernel mode
Kernel has a range of services
exec()An exec() function replaces the current process with a new process specified by the path or file argument.
Use exec() to hand off execution of our program to another.
| 
 | 
 | 
exec() is C/* Execute PATH with arguments ARGV and environment from `environ'.  */
extern int execv (__const char *__path, char *__const __argv[])
     __THROW __nonnull ((1));
/* Execute PATH with all arguments after PATH until a NULL pointer,
   and the argument after that for environment.  */
extern int execle (__const char *__path, __const char *__arg, ...)
     __THROW __nonnull ((1));
/* Execute PATH with all arguments after PATH until
   a NULL pointer and environment from `environ'.  */
extern int execl (__const char *__path, __const char *__arg, ...)
     __THROW __nonnull ((1));
/* Execute FILE, searching in the `PATH' environment variable if it contains
   no slashes, with arguments ARGV and environment from `environ'.  */
extern int execvp (__const char *__file, char *__const __argv[])
     __THROW __nonnull ((1));
/* Execute FILE, searching in the `PATH' environment variable if
   it contains no slashes, with all arguments after FILE until a
   NULL pointer and environment from `environ'.  */
extern int execlp (__const char *__file, __const char *__arg, ...)
     __THROW __nonnull ((1)
execlp()#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
int main()
{
  printf("ps with execlp\n");
  execlp("ps", "ps", 0);
  printf("Done.\n");
  exit(0);
}
fork()fork().fork()#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define BUF_SIZE 150
int main()
{
  int pid = fork();
  char buf[BUF_SIZE];
  int print_count;
  switch (pid)
  {
    case -1:
      perror("fork failed");
      exit(1);
    case 0:
      /* When fork() returns 0, we are in the child process. */
      print_count = 10;
      sprintf(buf,"child process: pid = %d", pid);
      break;
    default: /* + */
      /* When fork() returns a positive number, we are in the parent process
       * (the fork return value is the PID of the newly created child process) */
      print_count = 5;
      sprintf(buf,"parent process: pid = %d", pid);
      break;
  }
  for(;print_count > 0; print_count--) {
      puts(buf);
      sleep(1);
  }
  exit(0);
}
wait()The primary role of wait() is to synchronisation with children.
Suspends current process (the parent) until one of its children terminates.
Return value is the pid of the child process that terminated, and on a successful return, the child process is reaped by the parent.
If child_status != NULL, the value of the status will be set to indicate why the child process terminated.
If parent process has multiple children, wait() will return when any of the children terminates.
The waitpid() can be used to wait on a specific child process.
wait()#include <sys/wait.h>
pid_t wait(int *child_status);
A parent process needs to know when one of its child processes changes state, when the child terminates, hence wait() or is stopped by a signal, SIGCHLD.
The system call wait() blocks the calling process until one of its child processes exits, or a signal is received.
The wait() takes the address of an integer variable and returns the process ID of the completed process.
fork() and wait()#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define BUF_SIZE 150
int main()
{
  int pid = fork();
  char buf[BUF_SIZE];
  int print_count;
  switch (pid)
  {
    case -1:
      perror("fork failed");
      exit(1);
    case 0:
      print_count = 10;
      sprintf(buf,"child process: pid = %d", pid);
      break;
    default:
      print_count = 5;
      sprintf(buf,"parent process: pid = %d", pid);
      break;
  }
  if(!pid) {
    int status;
    int pid_child = wait(&status);
  }
  for(;print_count > 0; print_count--) puts(buf);
  exit(0);
}
_exit() and exit() Library callexit() library function is layered on top of the _exit() system call.fork(), generally only one of the parent and child terminate by calling exit() the other process should terminate using _exit()Either the parent outlives the child or vice versa.
A process which has terminated, but its entry still exists in the process table until the parent terminates normally or calls wait().
The denotation defunct is used to identify a zombie process.
The kernel deals with this situation by turning the child into a zombie. This means that most of the resources held by the child are released back to the system to be reused by other processes.


EXIT_ZOMBIE and the process's parent is notified that its child process has died with the SIGCHLD signal.wait() system call to read the dead process's exit status and other information.wait() is called, the zombie process is completely removed from memory.#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define BUF_SIZE 150
int main()
{
  int pid = fork();
  char buf[BUF_SIZE];
  int print_count;
  switch (pid)
  {
    case -1:
      perror("fork failed");
      exit(1);
    case 0:
      print_count = 2;
      sprintf(buf,"child process: pid = %d", pid);
      break;
    default:
      print_count = 10;
      sprintf(buf,"parent process: pid = %d", pid);
      break;
  }
  for(;print_count > 0; print_count--) {
      puts(buf);
      sleep(1);
  }
  exit(0);
}
ctrl+c is one event that triggers a signal if executed in the terminal to stop current process/program.SIGKILL has signal number 9
kill -9 <somepid> or kill SIGKILL <somepid>SIGHUP is used to signal that a terminal hangup has occurred, and it has a value of 1With the exception of SIGKILL and SIGSTOP which always terminate the process or stops the process, respectively, processes may control what happens when they receive a signal. They can:
Signals can be:
If a process receives signals such as SIGFPE, SIGKILL, etc., the process will be terminated immediately, and a core dump file is created. The core file is an image of the process, and you can use it to debug.
#include <stdio.h>
#include <unistd.h>
#include <signal.h>
void my_signal_interrupt(int sig)
{
  printf("I got signal %d\n", sig);
  (void) signal(SIGINT, SIG_DFL);
}
int main()
{
  (void) signal(SIGINT,my_signal_interrupt);
  while(1) {
      printf("Waiting for interruption...\n");
      sleep(1);
  }
}
- N = Low priority task, nice - R = Running or runnable (either executing or about to run) - S = Sleeping. Usually waiting for an event to occur, such as a signal or input to become available. - s = The process is a session leader - < High priority task - + = The process is in the foreground process group