Increase tar --totals context, use codeblock titles + line highlights

Also remove unnecessary lines from code example
This commit is contained in:
2023-11-28 02:14:33 -06:00
parent 2c893f74d1
commit 14f311d8f7

View File

@@ -1,8 +1,17 @@
--- ---
title: "Race Conditions in Signal Handlers" title: "Race Conditions in Signal Handlers"
pubDate: 2023-07-26 16:08:12 -0500 pubDate: "2023-07-26 16:08:12 -0500"
description: "Signals offer a unique, low-level way of communicating with processes. But under certain circumstances, they can kill processes, even when they shouldn't." description: "Signals offer a unique, low-level way of communicating with processes. But under certain circumstances, they can kill processes, even when they shouldn't."
tags: ["tar", "signals", "interrupt", "handler", "process", "unix", "race-condition"] tags:
[
"tar",
"signals",
"interrupt",
"handler",
"process",
"unix",
"race-condition",
]
--- ---
Signals offer a unique, low-level way of communicating with processes. But under certain circumstances, they can kill Signals offer a unique, low-level way of communicating with processes. But under certain circumstances, they can kill
@@ -43,6 +52,11 @@ operations.
By starting `tar` with the `--totals` flag, it would emit statistics upon completion. But to request By starting `tar` with the `--totals` flag, it would emit statistics upon completion. But to request
information during the operation, a signal must be chosen, like so: `tar -x -f archive.tar --totals=SIGUSR1`. information during the operation, a signal must be chosen, like so: `tar -x -f archive.tar --totals=SIGUSR1`.
```bash
$ tar -xf image.tar --totals
Total bytes read: 43048960 (42MiB, 23MiB/s)
```
Emitting a signal can be done with the `kill` command, like so: `kill -USR1 <pid>`. This will send the `USR1` signal Emitting a signal can be done with the `kill` command, like so: `kill -USR1 <pid>`. This will send the `USR1` signal
to the process with the given PID. The `USR1` signal is a user-defined signal, and is not used by the system. to the process with the given PID. The `USR1` signal is a user-defined signal, and is not used by the system.
@@ -50,7 +64,7 @@ And so, my plan was to start a tar process as usual with the `--totals` flag, an
process occasionally to query an extraction operation's progress. In Python, I used the `subprocess` module to start process occasionally to query an extraction operation's progress. In Python, I used the `subprocess` module to start
and manage the process. and manage the process.
```python ```python {8,19}
import os import os
import subprocess import subprocess
import signal import signal
@@ -66,13 +80,14 @@ process = subprocess.Popen(command, preexec_fn=os.setsid, stderr=subprocess.PIPE
try: try:
while True: while True:
# Both of these don't work! Why?
# process.send_signal(signal.SIGUSR1)
# os.killpg(os.getpgid(process.pid), signal.SIGUSR1)
# Ping the subprocess with SIGUSR1 signal # Ping the subprocess with SIGUSR1 signal
# NOTWORK: process.send_signal(signal.SIGUSR1)
# NOTWORK: os.killpg(os.getpgid(process.pid), signal.SIGUSR1)
subprocess.Popen(["kill", "-SIGUSR1", str(process.pid)]) subprocess.Popen(["kill", "-SIGUSR1", str(process.pid)])
print(process.stderr.readline().decode("utf-8").strip()) print(process.stderr.readline().decode("utf-8").strip())
# print(process.stdout.readline().decode("utf-8").strip())
# Wait for a specified interval # Wait for a specified interval
time.sleep(1.9) # Adjust the interval as needed time.sleep(1.9) # Adjust the interval as needed
@@ -115,9 +130,7 @@ and of course: _signal handlers_.
See below, the contents of `/proc/<pid>/status` for a process: See below, the contents of `/proc/<pid>/status` for a process:
``` ```proc title="/proc/100162/status"
File: /proc/100162/status
1 │ Name: Isolated Web Co 1 │ Name: Isolated Web Co
2 │ Umask: 0002 2 │ Umask: 0002
3 │ State: S (sleeping) 3 │ State: S (sleeping)
@@ -129,13 +142,9 @@ See below, the contents of `/proc/<pid>/status` for a process:
9 │ Uid: 1000 1000 1000 1000 9 │ Uid: 1000 1000 1000 1000
10 │ Gid: 1000 1000 1000 1000 10 │ Gid: 1000 1000 1000 1000
11 │ FDSize: 512 11 │ FDSize: 512
12 │ Groups: 4 27 123 1000 1001
13 │ NStgid: 100162
14 │ NSpid: 100162
... ...
...
...
33 │ CoreDumping: 0
34 │ THP_enabled: 1 34 │ THP_enabled: 1
35 │ Threads: 27 35 │ Threads: 27
36 │ SigQ: 0/62382 36 │ SigQ: 0/62382
@@ -148,11 +157,13 @@ See below, the contents of `/proc/<pid>/status` for a process:
43 │ CapPrm: 0000000000000000 43 │ CapPrm: 0000000000000000
``` ```
It's quite a long file (line numbers added for reference), but it contains a lot of useful information about a given process.
We're interested in `SigCgt` (line 41), which is a bitmask of signals that are caught by the process. The specific bit depends on the platform, but in Python, this can be found in the signal module: We're interested in `SigCgt` (line 41), which is a bitmask of signals that are caught by the process. The specific bit depends on the platform, but in Python, this can be found in the signal module:
```python ```python
>>> from signal import SIGUSR1 >>> from signal import SIGUSR1
>>> print(SIGUSR1) >>> SIGUSR1
10 10
``` ```