|
|
Log in / Subscribe / Register

Fork() in the road paper

Fork() in the road paper

Posted Jun 5, 2026 23:11 UTC (Fri) by gutschke (subscriber, #27910)
In reply to: Fork() in the road paper by malmedal
Parent article: Moving beyond fork() + exec()

It's been ages since I last experimented with CLONE_VM, so I probably don't remember all the details. But I think it had really awkward calling conventions that made it pretty much impossible to use from C code.

If my cover ever was productized in some form, adding yet another assembly wrapper is obviously doable. But I intentionally tried to keep things as high level and portable as it's possible with this sort of low level code.

And yes, it's ugly, and very far from portable without at least some effort. That's the nature of these APIs


to post comments

Fork() in the road paper

Posted Jun 5, 2026 23:35 UTC (Fri) by malmedal (subscriber, #56172) [Link]

I was curious as to what it would look like, so I coded it up. It's not too bad, unless I'm missing something.

The stack for each process can be reused as soon at it has called exec. Not sure how to best detect that. Options include things like FD_CLOEXEC or when /proc/<pid>/exe of the child has changed.

#include <fcntl.h>
#include <linux/sched.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/time.h>
#include <sys/wait.h>
#include <unistd.h>

int clone(int (*fn)(void *), void *stack, int flags, void *arg, ...
/* pid_t *parent_tid, void *tls, pid_t *child_tid */);

int target(void *arg) {
char fname[256];
int i = *(int *)arg;
snprintf(fname, sizeof(fname), "file%d.txt", i);
int fd = open(fname, O_CREAT | O_RDWR, 0777);
dup2(fd, 1);
dup2(fd, 2);
execl("/usr/bin/bash", "bash", "-c", "sleep 100 ; date", NULL);
return -1;
}

double dtime() {
struct timeval tv;
gettimeofday(&tv, NULL);
return (double)tv.tv_sec + tv.tv_usec / 1000000.0L;
}

int main(int argc, char **argv, char **envp) {
const int STACK_SIZE = 65536;
const int STACKS = 200;
int pids[STACKS];
int args[STACKS];
char *stack = malloc(STACK_SIZE * STACKS);
const long SIZE = 20 * 1024L * 1024 * 1024;
char *buffer = malloc(SIZE);
memset(buffer, 1, SIZE);
double start = dtime();
for (int i = 0; i < STACKS; i++) {
args[i] = i + 1;
pids[i] = clone(target, stack + STACK_SIZE * (i % STACKS + 1), CLONE_VM,
&args[i]);
}
fprintf(stderr, "Avg %d %f\n", 0, (dtime() - start) / 200.0);
for (int i = 0; i < STACKS; i++) {
int status;
int ret = waitpid(pids[i], &status, 0);
if (status != 0 || ret < 0) {
printf("status %d %d %d %d\n", i, pids[i], status, ret);
}
}
printf("done\n");
}


Copyright © 2026, Eklektix, Inc.
Comments and public postings are copyrighted by their creators.
Linux is a registered trademark of Linus Torvalds