From 817328f03f78eb5a2853411d64b411c67b9f63f7 Mon Sep 17 00:00:00 2001 From: Jake Hillion Date: Mon, 13 Dec 2021 13:33:22 +0000 Subject: [PATCH] fork/join copying --- examples/cp/Makefile | 5 +- examples/cp/cp_cgroup.c | 144 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 148 insertions(+), 1 deletion(-) create mode 100644 examples/cp/cp_cgroup.c diff --git a/examples/cp/Makefile b/examples/cp/Makefile index 7b2a56c..c67ab5e 100644 --- a/examples/cp/Makefile +++ b/examples/cp/Makefile @@ -1,6 +1,6 @@ C=clang -all: c ml +all: c c_cgroup ml clean: rm -f c ml @@ -8,6 +8,9 @@ clean: c: cp.c ${C} -o c cp.c +c_cgroup: cp_cgroup.c + ${C} -o c_cgroup cp_cgroup.c + ml: cp.ml opam switch default ocamlopt -o ml cp.ml diff --git a/examples/cp/cp_cgroup.c b/examples/cp/cp_cgroup.c new file mode 100644 index 0000000..977209f --- /dev/null +++ b/examples/cp/cp_cgroup.c @@ -0,0 +1,144 @@ +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include +#include + +#define IO_BLOCK_SIZE 4096 + +/* + * Get size of regular file or error otherwise. + */ +off_t get_file_size(int fd) { + struct stat st; + + if (fstat(fd, &st) < 0) { + perror("fstat"); + return -1; + } + + if (S_ISREG(st.st_mode)) { + return st.st_size; + } else { + return -1; + } +} + +/* + * Move self to a leaf node of the cgroup. + */ +int leaf_self() {} + +/* + * Perform the copy between the two file descriptors. + */ +int copy(int src_fd, int dst_fd) { + off_t src_len; + + int passwd_fd; + if ((passwd_fd = open("/home/jake/plot", O_RDONLY)) == -1) { + perror("open 2"); + return 1; + } else { + // TODO: Debug this + fprintf(stderr, "opened second file successfully\n"); + } + + if ((src_len = get_file_size(src_fd)) == -1) { + return 1; + } + + char buf[IO_BLOCK_SIZE]; + off_t blocks = + (src_len / IO_BLOCK_SIZE) + ((src_len % IO_BLOCK_SIZE) > 0 ? 1 : 0); + + for (off_t i = 0; i < blocks; i++) { + off_t len; + if (i == blocks - 1 && src_len % IO_BLOCK_SIZE != 0) { + len = src_len % IO_BLOCK_SIZE; + } else { + len = IO_BLOCK_SIZE; + } + + if (read(src_fd, &buf, len) == -1) { + perror("read"); + return -1; + }; + if (write(dst_fd, &buf, len) == -1) { + perror("write"); + return -1; + } + } + + return 0; +} + +int main(int argc, char **argv) { + if (argc != 3) { + fprintf(stderr, "usage: %s \n", argv[0]); + return 1; + } + + int src_fd, dst_fd; + + if ((src_fd = open(argv[1], O_RDONLY)) == -1) { + perror("open"); + return 1; + } + if ((dst_fd = open(argv[2], O_WRONLY | O_CREAT | O_TRUNC, 0666)) == -1) { + perror("open"); + return 1; + } + + // all necessary files opened, drop filesystem + // if (unshare(CLONE_FS) == -1) { + // perror("unshare"); + // return -1; + // } + + // fork and copy in a second process + pid_t child_pid = fork(); + if (child_pid == -1) { + perror("fork"); + return -1; + } else if (child_pid == 0) { + // pause(); // await cgroup setup + raise(SIGSTOP); // await cgroup setup + return copy(src_fd, dst_fd); + } + + // setup a cgroup for the child + + // wait for the child to pause and restart it + int status; + if (waitpid(child_pid, &status, WUNTRACED | WSTOPPED) == -1) { + perror("waitpid"); + return -1; + } + + if (WIFSTOPPED(status)) { + if (kill(child_pid, SIGCONT) == -1) { + perror("kill"); + return -1; + } + } else { + fprintf(stderr, "child behaved unexpectedly\n"); + return -1; + } + + // wait for the child process to terminate + if (waitpid(child_pid, &status, 0) == -1) { + perror("waitpid"); + return -1; + } + + if (WIFEXITED(status)) { + return WEXITSTATUS(status); + } + + return -1; +}