Skip to content

Instantly share code, notes, and snippets.

@JPEWdev
Created February 5, 2021 18:59
Show Gist options
  • Save JPEWdev/c9206cf531a38ee71476ca3c94af3386 to your computer and use it in GitHub Desktop.
Save JPEWdev/c9206cf531a38ee71476ca3c94af3386 to your computer and use it in GitHub Desktop.
Python program demonstration
#! /usr/bin/env python3
#
# Demonstrates how a short write can occur when writing to a pipe, even though
# Python normally restarts system calls that fail with EINTR
#
# If you are making small writes (<= 1 page size) to a pipe, the kernel will
# wait to copy any data into the pipe buffer until there is enough space. Thus,
# when the pipe is full and the alarm signal occurs, nothing from the current
# write() call have been written, the syscall will return EINTR, and python (>=
# 3.5) will retry the system call. This mean that the script never "sees" the
# short write
#
# However if the application is writing more than one page of data, the kernel
# will do a partial copy of the data into the pipe buffer. Then, when the alarm
# signal occurs the kernel will return the number of bytes written instead of
# EINTR and python is unable to restart the syscall and will return a short
# write
#
import os
import signal
# If you change this value to <= the kernel pagesize, you'll never get a short
# write. If it's larger, the program will exit with a short write
WRITE_SIZE = 4097
(rfd, wfd) = os.pipe()
wfile = os.fdopen(wfd, "wb", 0)
def handle_alarm(sig, frame):
print("Got SIGALRM")
signal.signal(signal.SIGALRM, handle_alarm)
signal.alarm(5)
total = 0
while True:
msg = b"0" * WRITE_SIZE
l = wfile.write(msg)
total += l
if l < len(msg):
print("Short write of %d bytes" % l)
break
print("Wrote %d bytes" % total)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment