A process is a currently executing program (or command). A program is a series of instructions that tell the computer what to do. When we run a program, those instructions are copied into memory and space is allocated for variables and other stuff required to manage its execution. This running instance of a program is called a process.
The top command can show running processes in the terminal in real-time.
myuser@hostname:~$ top
...
In linux, multiple users running multiple processes, at the same time and on the same system. The CPU manages all these processes simultaneously, according to the below state diagram:
A process can be in one of several states at any given time, indicating its current status or activity. These states are important to understand for managing and troubleshooting system performance.
Here are a short description of each state:
- Running: A process is currently executing on a CPU core (a.k.a process CPU burst).
- Waiting: A process is waiting for some external event, such as user input, disk, or a network I/O operation to complete.
- Ready: Is often used to refer to a process that is waiting to be executed on a CPU. When a process is in the ready state, it is typically placed in a queue, waiting for an available CPU to execute on. Once the CPU becomes available, the process is moved from the ready state to the running state and starts executing. The amount of time a process spends in the ready state is dependent on the scheduling algorithm and the current system load.
- Zombie: A process has completed its execution but its parent process has not yet collected its exit status.
- Initialized: A process that has been created but has not yet been assigned a process identifier (PID)
- Terminated: Indicates that a process has finished its execution and has exited.
A new process is created because an existing one makes an exact copy of itself (forking). This implies a tree structure of processes:
myuser@hostname:~$ pstree
systemd─┬─ModemManager───2*[{ModemManager}]
├─NetworkManager───2*[{NetworkManager}]
├─2*[SACSrv───3*[{SACSrv}]]
├─accounts-daemon───2*[{accounts-daemon}]
├─acpid
├─atd
├─avahi-daemon───avahi-daemon
.
.
.
This child process has the same environment as its parent, only different process id (PID). When a process ends normally (it is not killed or otherwise unexpectedly interrupted), the program returns its exit code (a number) to the parent. Only exit status of 0 means success.
A process has a series of characteristics, which can be viewed with the ps
command:
myuser@hostname:~$ ps -aux
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
root 1 0.0 0.1 172752 9440 ? Ss 13 Feb 7:21 /sbin/init splash
root 2 0.0 0.0 0 0 ? S 13 Feb 0:00 [kthreadd]
The ps
command can display a lot of information about processes, including their PID, state (STAT column), CPU and memory usage, the user owning this process, and the command that initiated the process.
Processes are communicating with each other and with the kernel using signals. There are multiple signals that you can send to a process. Use the kill
command to send a signal to a process.
Signal Name | Signal Number | Meaning |
---|---|---|
SIGTERM | 15 | Terminate the process in orderly way |
SIGINT | 2 | Interrupt the process. The process can ignore this signal |
SIGKILL | 9 | Interrupt the process. The process can't ignore this signal |
SIGHUP | 1 | The parent process was terminated |
Use man 7 signal
for a comprehensive list of linux signals.
Let's kill a process by send it a KILL signal:
myuser@hostname:~$ sleep 600
The above command initiates a process that just sleeps 600 seconds, and ends.
In another terminal, use the ps
to get the PID of the process running the sleep
command:
myuser@hostname:~$ ps -a
PID TTY TIME CMD
46214 pts/1 00:00:00 sleep
46445 pts/3 00:00:00 ps
...
myuser@hostname:~$ kill -9 46214
Observe how the process running the sleep
command is terminated.
In bash, you can use keyboard shortcuts to send signals to process:
Shortcut | Signal | Meaning |
---|---|---|
CTRL+C | SIGINT | Terminate the process in orderly way |
CTRL+Z | SIGSTOP | Suspend the process in the background |
In Linux, services are background processes that run continuously and provide specific functions to the operating system or other applications. Here are some common Linux services:
ssh
: A secure remote login protocol that allows users to log in to a remote computer securely.cron
: A service that executes scheduled tasks or commands at specified intervals.ufw
: An easy-to-use interface for configuring and managing firewall rules on a Linux system.apache
: A web server that serves HTML pages and other files over the internet.
The systemctl
command is used to manage services in your system:
myuser@hostname:~$ sudo systemctl status ufw
● ufw.service - Uncomplicated firewall
Loaded: loaded (/lib/systemd/system/ufw.service; enabled; vendor preset: enabled)
Active: active (exited) since Sun 2022-01-01 07:25:58 UTC; 2h 16min ago
Docs: man:ufw(8)
Main PID: 338 (code=exited, status=0/SUCCESS)
CPU: 1ms
Jan 01 07:25:58 hostname systemd[1]: Starting Uncomplicated firewall...
Jan 01 07:25:58 hostname systemd[1]: Finished Uncomplicated firewall.
myuser@hostname:~$ sudo systemctl stop ufw
myuser@hostname:~$ sudo systemctl start ufw
myuser@hostname:~$ sudo systemctl restart <service name>
Enable a service to start automatically at boot time by:
sudo systemctl enable <service name>
As can be seen in the output of pstree
, systemd is the first process in many Linux distributions, which is a system and service manager that provides a way to manage and control system services. Systemd reads unit files, which are configuration files used by systemd to define system services.
Unit files can be found in the /etc/systemd/system
directory:
myuser@hostname:~$ ls /etc/systemd/system/*.service
/etc/systemd/system/sshd.service
/etc/systemd/system/mysql.service
/etc/systemd/system/jenkins.service
...
List all your system services:
myuser@hostname:~$ systemctl list-units --type=service
UNIT LOAD ACTIVE SUB DESCRIPTION
accounts-daemon.service loaded active running Accounts Service
acpid.service loaded active running ACPI event daemon
alsa-restore.service loaded active exited Save/Restore Sound Card
....
In the above output, UNIT represents the unit name, LOAD indicates that the unit's configuration has been read by systemd, ACTIVE is the state of the unit.
We now demonstrate a very important concept called Graceful Termination.
Graceful termination refers to the process of shutting down a program (a process) in a way that allows it to complete its current tasks and close down all processes in a safe and controlled manner. This ensures that no data is lost, and all system resources are properly released.
In our course repo, under simple_python_server/app.py
you are given a simple Python server based on the Flask package.
First, let's install the Flask package as our server depends on that app. Open up a terminal session from your IDE (e.g. PyCharm) and perform:
pip install flask
Run the server by executing the below command from the simple_python_server
dir:
cd simple_python_server
python app.py
Obviously, we can send SIGKILL (9) to the server and kill it aggressively. But we want the server to be terminated gracefully. To do so, we will first send SIGTERM, which indicates to the server "you are going to be terminated soon, so take some grace period to terminate yourself gracefully".
The server is finishing the process clients requests, closes the connection to the database, and performs some cleanup tasks. Finally, the server terminates itself, while everything is healthy.
In this exercise you'll be followed step by step on how to run the simple_python_server
as a Linux service.
-
Create an empty dir in your home dir to store the app source code:
mkdir ~/simple_python_server
. -
Create and activate a Python virtual env (venv) within the app directory:
cd ~/simple_python_server python -m venv .venv
Then activate the venv by:
source .venv/bin/activate
. You can verify that your venv is activated by runningwhich python
and ensuring it points to the virtual environment'sbin
directory. -
Copy the app source code from
simple_python_server/
dir in our course repo, into~/simple_python_server
. -
From the terminal in which the venv is activated, install the
flask
Python package by:pip install flask
. -
Under
/etc/systemd/system/simplepy.service
, create a unit file as follows:
[Unit]
Description=Simple Python Server
After=network.target
[Service]
WorkingDirectory=/path/to/your/simple_python_server
ExecStart=/path/to/your/simple_python_server/venv/bin/python /path/to/your/simple_python_server/app.py
Restart=always
[Install]
WantedBy=multi-user.target
WorkingDirectory
: Specify the path to your Flask app directory.ExecStart
: Define the command to start your Flask app.WantedBy
: Indicates system to be fully functional for multiple users without a GUI
Adjust paths according to your specific setup. This .service
file will enable systemd to manage your Flask application as a service on your Linux system.
- Reload systemd configuration:
sudo systemctl daemon-reload
. - Enable the service to start on boot:
sudo systemctl enable simplepy.service
- Start the service:
sudo systemctl start simplepy.service
. - Check the service status:
sudo systemctl status simplepy.service
. - Check the service logs (if needed):
journalctl -u simplepy.service
.