Processes

Terms defined: background a process, callback function, child process, flush, foreground a process, fork (a process), parent process, process, process ID, process tree, resume (a process), signal, signal handler, suspend (a process)

Program vs. Process

Viewing Processes

ps -a -l
UID   PID  PPID        F CPU PRI NI        SZ    RSS       TTY       TIME CMD
  0 13215 83470     4106   0  31  0 408655632   9504   ttys001    0:00.02 login -pfl gvwilson /
501 13216 13215     4006   0  31  0 408795632   5424   ttys001    0:00.04 -bash
501 13569 13216     4046   0  31  0 408895008  20864   ttys001    0:00.10 python -m http.server
  0 13577 13216     4106   0  31  0 408766128   1888   ttys001    0:00.01 ps -a -l

Exercise

  1. What does the top command do? What does top -o cpu do?

  2. What does the pgrep command do?

Parent and Child Processes

Signals

Table 3.1: Signals
Number Name Default Action Description
1 SIGHUP terminate process terminal line hangup
2 SIGINT terminate process interrupt program
3 SIGQUIT create core image quit program
4 SIGILL create core image illegal instruction
8 SIGFPE create core image floating-point exception
9 SIGKILL terminate process kill program
11 SIGSEGV create core image segmentation violation
12 SIGSYS create core image non-existent system call invoked
14 SIGALRM terminate process real-time timer expired
15 SIGTERM terminate process software termination signal
17 SIGSTOP stop process stop (cannot be caught or ignored)
24 SIGXCPU terminate process CPU time limit exceeded
25 SIGXFSZ terminate process file size limit exceeded
import signal
import sys

COUNT = 0

def handler(sig, frame):
    global COUNT
    COUNT += 1
    print(f"interrupt {COUNT}")
    if COUNT >= 3:
        sys.exit(0)

signal.signal(signal.SIGINT, handler)
print("use Ctrl-C three times")
while True:
    signal.pause()
python src/catch_interrupt.py
use Ctrl-C three times
^Cinterrupt 1
^Cinterrupt 2
^Cinterrupt 3

Background Processes

import time

for i in range(3):
    print(f"loop {i}")
    time.sleep(1)
print("loop finished")
python src/show_timer.py &
ls site
$ src/show_timer.sh
birds.csv       cert_authority.srl  sandbox         server.pem      species.csv
cert_authority.key  motto.json      server.csr      server_first_cert.pem   yukon.db
cert_authority.pem  motto.txt       server.key      server_first_key.pem
loop 0
$ loop 1
loop 2
loop finished
$ python src/show_timer.py
loop 0
^Z
[1]+  Stopped                 python src/show_timer.py
$ jobs
[1]+  Stopped                 python src/show_timer.py
$ bg
[1]+ python src/show_timer.py &
loop 1
$ loop 2
loop finished
[1]+  Done                    python src/show_timer.py

Killing Processes

$ python src/show_timer.py
loop 0
^Z
[1]+  Stopped                 python src/show_timer.py
$ kill %1
[1]+  Terminated: 15          python src/show_timer.py
$ python src/show_timer.py
loop 0
^Z
[1]+  Stopped                 python src/show_timer.py
$ kill -s INT %1
[1]+  Stopped                 python src/show_timer.py
$ fg
python src/show_timer.py
Traceback (most recent call last):
  File "/tut/sys/src/show_timer.py", line 5, in <module>
    time.sleep(1)
KeyboardInterrupt

Fork

import os

print(f"starting {os.getpid()}")
pid = os.fork()
if pid == 0:
    print(f"child got {pid} is {os.getpid()}")
else:
    print(f"parent got {pid} is {os.getpid()}")
starting 41618
parent got 41619 is 41618
child got 0 is 41619

Unpredictability

Flushing I/O

import os
import sys

print(f"starting {os.getpid()}")
sys.stdout.flush()
pid = os.fork()
if pid == 0:
    print(f"child got {pid} is {os.getpid()}")
else:
    print(f"parent got {pid} is {os.getpid()}")
starting 41536
parent got 41537 is 41536
child got 0 is 41537

Exec

import os
import sys

print(f"starting {os.getpid()}")
sys.stdout.flush()
pid = os.fork()
if pid == 0:
    os.execl("/bin/echo", "echo", f"child echoing {pid} from {os.getpid()}")
else:
    print(f"parent got {pid} is {os.getpid()}")
starting 46713
parent got 46714 is 46713
child echoing 0 from 46714

Exercise

  1. What are the differences between os.execl, os.execlp, and os.execv? When and why would you use each?