Skip to content

Instantly share code, notes, and snippets.

@DivineDominion
Last active March 30, 2025 09:57
Show Gist options
  • Save DivineDominion/b577cef19218b4b00e4792a3eb45db3e to your computer and use it in GitHub Desktop.
Save DivineDominion/b577cef19218b4b00e4792a3eb45db3e to your computer and use it in GitHub Desktop.
Test writing to macOS pipes exceeding the pipe buffer size
#! /usr/bin/env bash
while read line
do
echo "$line"
done < "${1:-/dev/stdin}"
import Foundation
extension Pipe {
static func naive_stdin(string: String) throws -> Pipe {
let data = string.data(using: .utf8)!
let stdin = Pipe()
try stdin.fileHandleForWriting.write(contentsOf: data)
try stdin.fileHandleForWriting.close()
return stdin
}
static func stdin(string: String) throws -> Pipe {
let stdin = Pipe()
let data = string.data(using: .utf8)!
stdin.fileHandleForWriting.writeabilityHandler = { handle in
handle.write(data)
try! handle.close()
handle.writeabilityHandler = nil
}
return stdin
}
}
let pipeBufferSize = 64 * 1024 // 64KiB
let kilobytesToSend = 65
let string =
(0 ..< kilobytesToSend).map { thousand in
let prefix = "\(thousand)k: "
let blockSize = 1024 - prefix.count - 1 /* newline */
let block = (1 ... blockSize).map { _ in "x" }.joined()
return prefix + block
}.joined(separator: "\n") + "\n"
print(string.lengthOfBytes(using: .utf8), "vs", pipeBufferSize)
let process = Process()
// process.standardInput = try! Pipe.naive_stdin(string: string) // Hard limit at 64KiB
process.standardInput = try! Pipe.stdin(string: string) // Can take any input
process.executableURL = URL(fileURLWithPath: "/tmp/receive.sh")
try! process.run()
process.waitUntilExit()
print("Done")
@DivineDominion
Copy link
Author

I wonder how closing the file handle in the block, a throwing operation, is intended to be done.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment