335 karma · joined September 13, 2023
prepare() is a proposed API to simplify process creation. When calling prepare(), the current thread enters “preparation state.” That means, a nascent process is created and the current thread is moved to the context of this process, but without changing memory maps (this is similar to how vfork() works). Inside the nascent process, you can configure the environment as desired and then call prep_execve() to execute a new program. On success, prep_execve() leaves preparation state, moving the current thread back to the parent's process context and returns (!) the pid of the now grownup child. You can also use prep_exit() to abort the child without executing a new process, it similarly returns the pid of the now zombified child.
Here's an example for executing a child with stdout redirected to /dev/null:
int stfu(char prog, char argv[]) { if (prepare(NULL) == -1) return (-1);
int fd = open("/dev/null", O_WRONLY);
if (fd == -1) {
return (prep_exit(1));
}
dup2(fd, 1);
close(fd);
int pid = prep_execve(prog, argv, environ);
if (pid == -1) {
return (prep_exit(1));
}
return (pid);
}The key advantage of this API is that it has completely linear control flow like spawn, while preserving the flexible builder-pattern provided by fork+exec. No double-return shenanigans like with fork and execve. And because the nascent process shares memory with the parent, it's possible to communicate failure to execute and similar stuff using simple variables.
Array languages and SIMD are a match made in heaven. This should be the paradigm of choice for high-performance programming, but it's unfortunately pretty obscure.
Also, if the size was reported in-band, it would mess up applications that are not aware of that in-band signalling.
SIGWINCH and the TIOCGWINSZ ioctl() were originally omitted from POSIX as they were considered relevant for windowing systems only and GUI-stuff was considered out of scope for POSIX. Furthermore, POSIX only specifies ioctl() for STREAMS; other interfaces that traditionally use ioctl() calls are specified in POSIX using wrapper functions (which is what the new interface is; it is specified such that you can implement it just by wrapping the traditional TIOCGWINSZ/TIOCSWINSZ ioctl calls).
My original proposal had functions tcgetsize() and tcsetsize(), but it turns out that QNX already uses these identifiers with an incompatible signature, so a last minute change was made to name these tcgetwinsize() and tcsetwinsize().
Furthermore, the winsize structure traditionally also has ws_xpixel and ws_ypixel members indicating the resolution of the terminal. This existed primarily becaus on some historical virtual terminals, a client could change the video mode by calling the TIOCSWINSZ ioctl, providing resolution and row/column count for the desired video mode. While no current virtual terminal known to me supports this, the POSIX spec mandates that if a slave PTY calls tcsetwinsize(), the window size update is propagated to the master, allowing terminal emulators to implement this feature if desired. Another objection raised was that the traditional unsigned short type may be insufficient for future high-definition screens and a resolution may not be well defined for some types of terminals like hardcopy or braille terminals.
I maintain that submitting a feature to POSIX and waiting for a new version of the standard to be released is probably the easiest way to get glibc to implement a feature you want.
Thank you for doing that. This is very valuable.