Last active
January 30, 2024 19:54
-
-
Save ig0rmin/8452e39dfc318c16126549389915fc7e to your computer and use it in GitHub Desktop.
Create a child and parent process that share the same virtual memory
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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