Skip to content

Instantly share code, notes, and snippets.

@ig0rmin
Last active January 30, 2024 19:54
Show Gist options
  • Save ig0rmin/8452e39dfc318c16126549389915fc7e to your computer and use it in GitHub Desktop.
Save ig0rmin/8452e39dfc318c16126549389915fc7e to your computer and use it in GitHub Desktop.
Create a child and parent process that share the same virtual memory
#define _GNU_SOURCE
#include <stdlib.h>
#include <stdarg.h>
#include <stdio.h>
#include <string.h>
#include <sched.h>
#include <unistd.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/mman.h>
struct ChildArgs
{
int fdChildParent[2];
int fdParentChild[2];
};
static int global = 0;
static void LOG(const char* fmt, ...) {
char msgBuff[1024] = {0};
va_list ap;
va_start(ap, fmt);
vsnprintf(msgBuff, sizeof(msgBuff), fmt, ap);
va_end(ap);
write(STDOUT_FILENO, msgBuff, strlen(msgBuff));
}
static void writeByte(int fd[2]) {
char ch = 0;
if (write(fd[1], &ch, sizeof(ch)) != 1) {
perror("write");
exit(EXIT_FAILURE);
}
}
static void readByte(int fd[2]) {
char ch = 0;
if (read(fd[0], &ch, sizeof(ch)) != 1) {
perror("read");
exit(EXIT_FAILURE);
}
}
static void readEOF(int fd[2]) {
char ch = 0;
if (read(fd[0], &ch, sizeof(ch)) != 0) {
perror("read EOF");
exit(EXIT_FAILURE);
}
}
static int childFunc(void* arg) {
struct ChildArgs* args = (struct ChildArgs*)arg;
LOG("Child PID: %d\n", getpid());
LOG("Global variable (first read): %d\n", global);
readByte(args->fdParentChild);
writeByte(args->fdChildParent);
readByte(args->fdParentChild);
writeByte(args->fdChildParent);
LOG("Global variable (second read): %d\n", global);
close(args->fdParentChild[1]);
readEOF(args->fdParentChild);
close(args->fdChildParent[1]);
LOG("Child Bye!\n");
exit(EXIT_SUCCESS);
}
void waitChild(pid_t pid) {
int status;
pid_t res = waitpid(pid, &status, 0);
if (res == -1) {
printf("waitpid returned error, errno: %d\n", errno);
return;
}
if (WIFEXITED(status)) {
printf("child %d exited with exit status %d\n", pid, WEXITSTATUS(status));
} else if (WIFSIGNALED(status)) {
printf("child %d was killed by a signal %d (core dumped: %d)\n",
pid, WTERMSIG(status), __WCOREDUMP(status));
} else {
printf("error: unexpected waitpid result\n");
}
}
int main(int argc, char* argv[]) {
LOG("Parent PID: %d\n", getpid());
int opt = getopt(argc, argv, "m");
int flags = SIGCHLD;
switch (opt) {
case -1:
break;
case 'm':
flags |= CLONE_VM;
break;
default:
exit(EXIT_FAILURE);
break;
}
const int STACK_SIZE = 1024 * 1024;
char* stack = mmap(NULL, STACK_SIZE, PROT_READ | PROT_WRITE,
MAP_PRIVATE | MAP_ANONYMOUS | MAP_STACK, -1, 0);
char* stackTop = stack + STACK_SIZE;
struct ChildArgs args;
pipe(args.fdParentChild);
pipe(args.fdChildParent);
pid_t pid = clone(childFunc, stackTop, flags, &args);
writeByte(args.fdParentChild);
readByte(args.fdChildParent);
LOG("Parent, setting variable\n");
global = 42;
writeByte(args.fdParentChild);
readByte(args.fdChildParent);
close(args.fdParentChild[1]);
close(args.fdChildParent[1]);
readEOF(args.fdChildParent);
waitChild(pid);
LOG("Parent Bye!\n");
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment