From c3c04b76979d4368f6b3c3613bd230e220c5ab4b Mon Sep 17 00:00:00 2001 From: Rokas Puzonas Date: Sat, 6 Jan 2024 14:32:17 +0200 Subject: [PATCH] add forking example --- .gitignore | 2 ++ README.md | 4 +++ forking/build.zig | 38 +++++++++++++++++++++++ forking/mutexes.c | 79 +++++++++++++++++++++++++++++++++++++++++++++++ forking/simple.c | 27 ++++++++++++++++ 5 files changed, 150 insertions(+) create mode 100644 .gitignore create mode 100644 README.md create mode 100644 forking/build.zig create mode 100644 forking/mutexes.c create mode 100644 forking/simple.c diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..c26d4af --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +zig-out +zig-cache diff --git a/README.md b/README.md new file mode 100644 index 0000000..e235a76 --- /dev/null +++ b/README.md @@ -0,0 +1,4 @@ +# Shared Memory Examples In C + +All of the C examples are setup to use the zig build system. +You can download zig [here](https://ziglang.org/download/) (Use version 0.11.0) and just run `zig build run` in any example. diff --git a/forking/build.zig b/forking/build.zig new file mode 100644 index 0000000..c5d656a --- /dev/null +++ b/forking/build.zig @@ -0,0 +1,38 @@ +const std = @import("std"); + +pub fn build(b: *std.build.Builder) void { + const target = b.standardTargetOptions(.{}); + const optimize = b.standardOptimizeOption(.{}); + + { + const exe = b.addExecutable(.{ + .name = "forking-simple", + .root_source_file = .{ .path = "simple.c" }, + .optimize = optimize, + .target = target + }); + exe.linkLibC(); + + const run_cmd = b.addRunArtifact(exe); + const run_step = b.step("run", "Run simple program"); + run_step.dependOn(&run_cmd.step); + + b.installArtifact(exe); + } + + { + const exe = b.addExecutable(.{ + .name = "forking-mutexes", + .root_source_file = .{ .path = "mutexes.c" }, + .optimize = optimize, + .target = target + }); + exe.linkLibC(); + + const run_cmd = b.addRunArtifact(exe); + const run_step = b.step("run-mutexes", "Run mutexes program"); + run_step.dependOn(&run_cmd.step); + + b.installArtifact(exe); + } +} diff --git a/forking/mutexes.c b/forking/mutexes.c new file mode 100644 index 0000000..857fc8f --- /dev/null +++ b/forking/mutexes.c @@ -0,0 +1,79 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// WARNING: This example does not work, I couldn't figure out why the child process goes into a deadlock on `pthread_mutex_lock` + +struct shared_data { + pthread_mutex_t mutex; + int counter; +}; + +void milli_sleep(int milliseconds) { + struct timespec ts; + ts.tv_sec = milliseconds / 1000; + ts.tv_nsec = (milliseconds % 1000) * 1000000; + nanosleep(&ts, &ts); +} + +float random_float() { + return (float)rand()/(float)RAND_MAX; +} + +int random_range(int from, int to) { + return random_float()*(to-from) + from; +} + +void run(const char *name, struct shared_data *data) { + printf("[%s] started, mutex: %p\n", name, &data->mutex); + for (int i = 0; i < 10; i++) { + if (pthread_mutex_lock(&data->mutex) != 0) { + perror("pthread_mutex_lock"); + } + + int counter = data->counter; + milli_sleep(random_range(0, 100)); + data->counter = counter + 1; + printf("[%s] counter is %d\n", name, counter + 1); + + if (pthread_mutex_unlock(&data->mutex) != 0) { + perror("pthread_mutex_unlock"); + } + } + printf("[%s] finished\n", name); +} + +int main() { + struct shared_data *shared_data = mmap(NULL, sizeof(struct shared_data), PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0); + if (shared_data == NULL) { + perror("mmap"); + return -1; + } + + if (pthread_mutex_init(&shared_data->mutex, NULL) < 0) { + printf("Failed to initialise mutex\n"); + return -1; + } + + shared_data->counter = 0; + + int pid = fork(); + if (pid == 0) { + srand(time(NULL)+1); + run("Child ", shared_data); + return 0; + } else { + srand(time(NULL)+2); + run("Parent", shared_data); + } + + int child_status; + waitpid(pid, &child_status, 0); +} + diff --git a/forking/simple.c b/forking/simple.c new file mode 100644 index 0000000..01328ac --- /dev/null +++ b/forking/simple.c @@ -0,0 +1,27 @@ +#include +#include +#include +#include +#include + +int main() { + char parent_message[] = "hello"; + char child_message[] = "goodbye"; + + void* shmem = mmap(NULL, 128, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0); + + memcpy(shmem, parent_message, sizeof(parent_message)); + + int pid = fork(); + + if (pid == 0) { + printf("Child read: %s\n", (char*)shmem); + memcpy(shmem, child_message, sizeof(child_message)); + printf("Child wrote: %s\n", (char*)shmem); + + } else { + printf("Parent read: %s\n", (char*)shmem); + sleep(1); + printf("After 1s, parent read: %s\n", (char*)shmem); + } +}