diff --git a/lab6/.vscode/settings.json b/lab6/.vscode/settings.json index 51ea255..5314f20 100644 --- a/lab6/.vscode/settings.json +++ b/lab6/.vscode/settings.json @@ -1,9 +1,5 @@ { "files.associations": { - "cdev.h": "c", - "module.h": "c", - "types.h": "c", - "init.h": "c", "any": "cpp", "array": "cpp", "atomic": "cpp", @@ -72,13 +68,11 @@ "stdfloat": "cpp", "stop_token": "cpp", "streambuf": "cpp", + "syncstream": "cpp", "text_encoding": "cpp", "thread": "cpp", "cinttypes": "cpp", "typeinfo": "cpp", - "variant": "cpp", - "csignal": "cpp", - "syncstream": "cpp" - }, - "C_Cpp.default.compilerPath": "/usr/bin/clang++" + "variant": "cpp" + } } \ No newline at end of file diff --git a/lab6/Makefile b/lab6/Makefile index dc91a14..fa8b75b 100644 --- a/lab6/Makefile +++ b/lab6/Makefile @@ -1,18 +1,18 @@ obj-m += wendy.o OUT_DIR := build -.PHONY: all kern_mod install uninstall clean reader writer tester dirprepare +.PHONY: all kern_mod install rm clean reader writer tester dirprepare all: kern_mod reader writer tester -kern_mod: wendy.c - make -C /lib/modules/$(shell uname -r)/build M=$(PWD) MO=$(PWD)/build/kern +kern_mod: + make -C wendy_mod -install: - sudo insmod ./build/kern/wendy.ko +install: kern_mod + make -C wendy_mod install -uninstall: - sudo rmmod wendy +rm: + make -C wendy_mod uninstall reader: dirprepare gcc pipe_read.c -o $(OUT_DIR)/pread @@ -27,6 +27,6 @@ dirprepare: mkdir -p $(OUT_DIR) clean: - $(MAKE) -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean + make -C wendy_mod clean rm -rf $(OUT_DIR) diff --git a/lab6/pipe_tester.cpp b/lab6/pipe_tester.cpp index 66b1528..7ce67ea 100644 --- a/lab6/pipe_tester.cpp +++ b/lab6/pipe_tester.cpp @@ -7,60 +7,22 @@ void writer() { std::osyncstream(std::cout) << "Writer started" << std::endl; - char *buffer = new char[8192]; - - for (int i = 0; i < 8192; ++i) { - buffer[i] = static_cast((i % 95) + 32); // Printable range - } - - FILE *fl = fopen("/dev/wendy_in", "w"); - if (!fl) { - std::osyncstream(std::cerr) << "Cannot open wendy_in" << std::endl; - } - - int wrote = 0; - wrote = fwrite(buffer, sizeof(char), 8192, fl); - if (wrote < 0) { - std::osyncstream(std::cerr) << "Write error: " << wrote << std::endl; - } - std::osyncstream(std::cout) << "Wrote " << wrote << std::endl; - - std::this_thread::sleep_for(std::chrono::milliseconds(500)); - wrote = fwrite(buffer, sizeof(char), 8192, fl); - if (wrote < 0) { - std::osyncstream(std::cerr) << "2nd write error: " << wrote << std::endl; - } - std::osyncstream(std::cout) << "2nd wrote " << wrote << std::endl; + std::ofstream pipe_write("/dev/wendy_in"); + pipe_write << "Hello from the other side\n"; + std::osyncstream(std::cout) << "Writer ended" << std::endl; } void reader() { std::osyncstream(std::cout) << "Reader started" << std::endl; - FILE *fl = fopen("/dev/wendy_out", "r"); - if (!fl) { - std::osyncstream(std::cerr) << "Cannot open wendy_out" << std::endl; - return; - } - - char *buffer = new char[257]; - - int read = 0; - int total_read = 0; - do { - read = fread(buffer, sizeof(char), 100, fl); - if (read <= 0) { - break; - } - total_read += read; - std::osyncstream(std::cout) << "Read " << read << "bytes, content: " << buffer << ", total " << total_read << std::endl; - } while (1); - - std::osyncstream(std::cout) << "Read failed: read = " << read << std::endl; + std::ifstream pipe_read("/dev/wendy_out"); + std::osyncstream(std::cout) << "Reader read content: " << pipe_read.rdbuf(); + std::osyncstream(std::cout) << "Reader ended" << std::endl; } int main() { + std::thread writer_thread(writer); std::thread reader_thread(reader); std::this_thread::sleep_for(std::chrono::milliseconds(100)); - std::thread writer_thread(writer); if (reader_thread.joinable()) { reader_thread.join(); } diff --git a/lab6/.vscode/c_cpp_properties.json b/lab6/wendy_mod/.vscode/c_cpp_properties.json similarity index 94% rename from lab6/.vscode/c_cpp_properties.json rename to lab6/wendy_mod/.vscode/c_cpp_properties.json index 7a9b4b6..a059d8f 100644 --- a/lab6/.vscode/c_cpp_properties.json +++ b/lab6/wendy_mod/.vscode/c_cpp_properties.json @@ -1,7 +1,7 @@ { "configurations": [ { - "name": "Linux Kernel Module", + "name": "Linux", "includePath": [ "/usr/lib/modules/6.14.3-arch1-1/build/include", "/usr/lib/modules/6.14.3-arch1-1/build/arch/x86/include", diff --git a/lab6/wendy_mod/.vscode/settings.json b/lab6/wendy_mod/.vscode/settings.json new file mode 100644 index 0000000..8f59094 --- /dev/null +++ b/lab6/wendy_mod/.vscode/settings.json @@ -0,0 +1,8 @@ +{ + "files.associations": { + "cdev.h": "c", + "module.h": "c", + "types.h": "c", + "init.h": "c", + } +} \ No newline at end of file diff --git a/lab6/wendy_mod/Makefile b/lab6/wendy_mod/Makefile new file mode 100644 index 0000000..13087f8 --- /dev/null +++ b/lab6/wendy_mod/Makefile @@ -0,0 +1,20 @@ +obj-m += wendy.o +OUT_DIR := build +CUR_DIR := $(shell pwd) + +.PHONY: kern_mod install uninstall dirprepare clean + +kern_mod: wendy.c dirprepare + make -C /lib/modules/$(shell uname -r)/build M=$(CUR_DIR) MO=$(CUR_DIR)/$(OUT_DIR) + +install: + sudo insmod build/wendy.ko + +uninstall: + sudo rmmod wendy + +dirprepare: + mkdir -p $(CUR_DIR)/$(OUT_DIR) + +clean: + make -C /lib/modules/$(shell uname -r)/build M=$(CUR_DIR) clean \ No newline at end of file diff --git a/lab6/wendy.c b/lab6/wendy_mod/wendy.c similarity index 81% rename from lab6/wendy.c rename to lab6/wendy_mod/wendy.c index b2121d1..9192bd5 100644 --- a/lab6/wendy.c +++ b/lab6/wendy_mod/wendy.c @@ -20,6 +20,8 @@ enum MyPipeMinors { struct mypipe_data { struct cdev cdev; + // Whether opened by some writer + bool is_active; u8 buffer[MYPIPE_BUFFER_SIZE]; size_t write_pos; size_t read_pos; @@ -33,18 +35,43 @@ static struct class *mypipedev_class = NULL; // Protects the buffer static DEFINE_MUTEX(mypipe_lock); +// Protects the is_active value +static DEFINE_MUTEX(isactive_lock); // These are two wait_queue_head_t for storing tasks that are waiting for // writing/ reading static DECLARE_WAIT_QUEUE_HEAD(read_queue); static DECLARE_WAIT_QUEUE_HEAD(write_queue); static int mypipe_open(struct inode *inode, struct file *file) { - printk(KERN_INFO "Wendy opened."); + int minor = iminor(inode); + printk(KERN_INFO "%s opened, minor = %d", MYPIPE_DEVICE_NAME, minor); + + // If its opening the writing end, we limit it to only one writer + if (minor == MYPIPE_MINOR_IN) { + if (mutex_lock_interruptible(&isactive_lock)) { + return -ERESTARTSYS; + } + + if (pdata.is_active) { + return -EBUSY; + } + pdata.is_active = true; + mutex_unlock(&isactive_lock); + } return 0; } static int mypipe_release(struct inode *inode, struct file *file) { - printk(KERN_INFO "Wendy released."); + int minor = iminor(inode); + printk(KERN_INFO "%s released, minor = %d", MYPIPE_DEVICE_NAME, minor); + + if (minor == MYPIPE_MINOR_IN) { + mutex_lock(&isactive_lock); + pdata.is_active = false; + mutex_unlock(&isactive_lock); + wake_up_interruptible(&read_queue); + + } return 0; } @@ -65,7 +92,21 @@ static ssize_t mypipe_read(struct file *filep, char __user *buf, size_t size, // We currently have no data, but we can wait for possible new to write in while (pdata.data_len == 0) { mutex_unlock(&mypipe_lock); + + // Check if the writer is still active + if (mutex_lock_interruptible(&isactive_lock)) { + return -ERESTARTSYS; + } + bool writer_is_active = pdata.is_active; + mutex_unlock(&isactive_lock); + + if (!writer_is_active) { + return 0; // No data left and the writer is gone -> EOF for reader + } + + // There is still writer, wait for data if (filep->f_flags & O_NONBLOCK) { + // The caller says no waiting, so we don't wait return -EAGAIN; } if (wait_event_interruptible(read_queue, pdata.data_len > 0)) { @@ -211,7 +252,9 @@ static int __init mypipe_init(void) { device_create(mypipedev_class, NULL, MKDEV(dev_major, MYPIPE_MINOR_OUT), NULL, "%s_out", MYPIPE_DEVICE_NAME); - printk(KERN_INFO "Wendy: module loaded\n"); + pdata.is_active = false; + + printk(KERN_INFO "%s: module loaded\n", MYPIPE_DEVICE_NAME); return 0; del_cdev: @@ -229,7 +272,7 @@ static void __exit mypipe_destroy(void) { class_destroy(mypipedev_class); cdev_del(&pdata.cdev); unregister_chrdev_region(MKDEV(dev_major, 0), MYPIPE_MINOR_COUNT); - printk(KERN_INFO "Wendy: module unloaded"); + printk(KERN_INFO "%s: module unloaded", MYPIPE_DEVICE_NAME); } module_init(mypipe_init);