Skip to content

Instantly share code, notes, and snippets.

@voutilad
Created December 22, 2022 19:12
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save voutilad/e5b7acd37aefddac61facc052ac09797 to your computer and use it in GitHub Desktop.
Save voutilad/e5b7acd37aefddac61facc052ac09797 to your computer and use it in GitHub Desktop.
Example of sharing a page between processes after fork+exec.
/*
* Copyright (c) 2022 Dave Voutila <dave@sisu.io>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
/*
* An example of using shm_mkstemp, execve, and pledge altogether.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <time.h>
#include <err.h>
#include <errno.h>
#include <sys/mman.h>
#include <sys/wait.h>
static const int TICKS = 8;
static const size_t SZ = 4096;
static char *PAGE = NULL;
static int FD = -1;
int main(int, char**);
int
read_int(void)
{
return *(int*)(PAGE);
}
void
write_int(int i)
{
int *p = (int*)PAGE;
*p = i;
}
int
child(void)
{
struct timespec timeout;
int cnt = TICKS, ms = 1000;
printf("child starting. my main is @ %p\n", main);
timeout.tv_sec = ms / 1000;
timeout.tv_nsec = ms * 1000000 % 1000000000;
printf("pledging in child\n");
if (pledge("stdio", NULL))
return (errno);
do {
if (nanosleep(&timeout, NULL) == -1) {
printf("! %s interrupted?!\n", __func__);
break;
}
write_int(cnt);
printf("...tick\n");
} while ((--cnt) > 0);
printf("child finishing\n");
return (0);
}
int
parent(pid_t child)
{
struct timespec timeout;
int cnt = TICKS, ms = 900, status = 0;
timeout.tv_sec = ms / 1000;
timeout.tv_nsec = ms * 1000000 % 1000000000;
printf("parent starting. my main is @ %p\n", main);
printf("pledging in parent\n");
if (pledge("stdio", NULL))
err(1, "parent pledge");
do {
if (nanosleep(&timeout, NULL) == -1) {
printf("! %s interrupted?!\n", __func__);
break;
}
printf("... %d\n", read_int());
} while ((--cnt) > 0);
printf("parent waiting for child %d to finish\n", child);
if (wait(&status) != child) {
warn("waitpid");
return (1);
}
return (0);
}
int
main(int argc, char **argv)
{
char *nargv[3], arg[13], *path;
int prot, flags, isParent = 0;
pid_t pid = 0;
path = calloc(32, sizeof(char));
if (argc > 1) {
// coming in via fork+exec
const char *errstr = NULL;
FD = strtonum(argv[1], 3, 10, &errstr);
if (errstr != NULL)
errx(1, "failed to parse fd argument: %s", errstr);
printf("got FD = %d\n", FD);
} else {
isParent = 1;
strlcpy(path, "/tmp/fun.XXXXXXX", 32);
printf("calling shm_mkstemp(%s)\n", path);
FD = shm_mkstemp(path);
if (FD < 0)
err(1, "shm_mkstemp");
printf("made temp file, FD=%d\n", FD);
/* We need to "size" the file */
ftruncate(FD, SZ);
fcntl(FD, F_SETFD, 0);
shm_unlink(path); // cleanup filesystem
free(path);
}
prot = PROT_READ | PROT_WRITE;
flags = MAP_SHARED | MAP_CONCEAL;
PAGE = (char*)mmap(NULL, SZ, prot, flags, FD, 0);
if (PAGE == MAP_FAILED)
err(1, "mmap");
printf("%s MMAP'd @ %p\n", isParent ? "parent" : "child", PAGE);
if (!isParent) {
close(FD);
child();
} else {
// zero our page
memset(PAGE, 0, SZ);
// fork you!
printf("...forking\n");
if ((pid = fork()) == -1) {
if (munmap(PAGE, SZ))
err(3, "munmap");
err(2, "fork");
}
if (pid == 0) {
// Child
memset(&arg, 0, sizeof(arg));
snprintf(arg, sizeof(arg), "%d", FD);
nargv[0] = argv[0];
nargv[1] = arg;
nargv[2] = NULL;
execvp(argv[0], nargv);
err(3, "execvp");
// catch you on the flip side
}
close(FD);
parent(pid);
}
return (0);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment