From 121643be455e33039d36cc5f02b778a82b6555ea Mon Sep 17 00:00:00 2001 From: Asger Gitz-Johansen Date: Sat, 3 Aug 2024 11:13:09 +0200 Subject: [PATCH] feat: add simple two-thread watch prototype I feel like I'm crushing it today! --- Makefile | 1 + README.md | 2 +- include/cli.h | 4 ++++ src/cli.c | 14 ++++++++++++-- src/main.c | 50 +++++++++++++++++++++++++++++++++++++++++++------- 5 files changed, 61 insertions(+), 10 deletions(-) diff --git a/Makefile b/Makefile index a673b9c..d4fdfeb 100644 --- a/Makefile +++ b/Makefile @@ -20,6 +20,7 @@ CFLAGS += -Wall -Werror -std=c23 -g # includes CFLAGS += -Iinclude # libraries +CFLAGS += -lpthread .PHONY: all clean diff --git a/README.md b/README.md index b8f00fd..a8978fa 100644 --- a/README.md +++ b/README.md @@ -81,7 +81,7 @@ If you want `compile_commands.json` files, you should use [bear](https://github. - [x] First things first, let's implement something that reacts when some provided file changes (not poll please). - [x] Second things second, implement a simple logging system with differing levels of verbosity and configurable output file using cli options. - - [ ] Third things third, implement a thing that simultaneously watches two different files (multithreading). + - [x] Third things third, implement a thing that simultaneously watches two different files (multithreading). it should be cancellable with ctrl+c, but it should just contiuously print event notifications. - [ ] Fourth things fourth, implement a prototype that reads a space-separated file and populates a struct. diff --git a/include/cli.h b/include/cli.h index 730a24a..9dbbdda 100644 --- a/include/cli.h +++ b/include/cli.h @@ -4,7 +4,11 @@ #include "optional.h" typedef struct { + // prototyping optional_str file; + optional_str file2; + + // actual int verbosity; bool help; bool version; diff --git a/src/cli.c b/src/cli.c index ae4b96f..ef764e8 100644 --- a/src/cli.c +++ b/src/cli.c @@ -9,6 +9,9 @@ cli_options new_options() { result.file.has_value = false; result.file.value = NULL; + result.file2.has_value = false; + result.file2.value = NULL; + result.verbosity = 1; result.help = false; @@ -29,10 +32,12 @@ cli_options new_options() { void free_options(cli_options v) { if(v.file.has_value) free(v.file.value); + if(v.file2.has_value) + free(v.file2.value); } // #include #include +#include + void on_event(struct inotify_event* const e) { const char* msg = "got an event:\n" @@ -17,6 +20,12 @@ void on_event(struct inotify_event* const e) { log_info(msg, e->wd, e->mask, e->cookie, e->len, e->name); } +void* listen_for_changes_thread(void* data) { + const char* f = (const char*)data; + listen_for_changes(f, &on_event); + return NULL; +} + int main(int argc, char** argv) { cli_options args = parse(argc, argv); log_settings settings; @@ -29,19 +38,46 @@ int main(int argc, char** argv) { print_help(stdout, argv[0]); exit(EXIT_SUCCESS); } - if(args.version) { fprintf(stdout, SCI_VERSION "\n"); exit(EXIT_SUCCESS); } - if(args.file.has_value) { - if(access(args.file.value, F_OK) != 0) { - fprintf(stderr, "no such file or directory %s\n", args.file.value); - exit(EXIT_FAILURE); - } - listen_for_changes(args.file.value, &on_event); + if(!args.file.has_value) { + fprintf(stderr, "no file provided see -h for usage\n"); + exit(EXIT_FAILURE); } + if(!args.file2.has_value) { + fprintf(stderr, "no second file provided see -h for usage\n"); + exit(EXIT_FAILURE); + } + + if(access(args.file.value, F_OK) != 0) { + fprintf(stderr, "no such file or directory %s\n", args.file.value); + exit(EXIT_FAILURE); + } + if(access(args.file2.value, F_OK) != 0) { + fprintf(stderr, "no such file or directory %s\n", args.file2.value); + exit(EXIT_FAILURE); + } + + + log_trace("spawning trigger thread for %s", args.file.value); + pthread_t file1_thread; + pthread_attr_t attr1; + ASSERT_SYSCALL_SUCCESS(pthread_attr_init(&attr1)); + ASSERT_SYSCALL_SUCCESS(pthread_create(&file1_thread, &attr1, &listen_for_changes_thread, (void*)args.file.value)); + ASSERT_SYSCALL_SUCCESS(pthread_attr_destroy(&attr1)); + + log_trace("spawning trigger thread for %s", args.file2.value); + pthread_t file2_thread; + pthread_attr_t attr2; + ASSERT_SYSCALL_SUCCESS(pthread_attr_init(&attr2)); + ASSERT_SYSCALL_SUCCESS(pthread_create(&file2_thread, &attr1, &listen_for_changes_thread, (void*)args.file2.value)); + ASSERT_SYSCALL_SUCCESS(pthread_attr_destroy(&attr2)); + + pthread_join(file1_thread, NULL); + pthread_join(file2_thread, NULL); free_options(args); }