only allow one writer

This commit is contained in:
2025-04-24 22:31:06 +08:00
parent 86c6bb3f55
commit 2f794d04b7
7 changed files with 94 additions and 67 deletions

View File

@@ -1,9 +1,5 @@
{ {
"files.associations": { "files.associations": {
"cdev.h": "c",
"module.h": "c",
"types.h": "c",
"init.h": "c",
"any": "cpp", "any": "cpp",
"array": "cpp", "array": "cpp",
"atomic": "cpp", "atomic": "cpp",
@@ -72,13 +68,11 @@
"stdfloat": "cpp", "stdfloat": "cpp",
"stop_token": "cpp", "stop_token": "cpp",
"streambuf": "cpp", "streambuf": "cpp",
"syncstream": "cpp",
"text_encoding": "cpp", "text_encoding": "cpp",
"thread": "cpp", "thread": "cpp",
"cinttypes": "cpp", "cinttypes": "cpp",
"typeinfo": "cpp", "typeinfo": "cpp",
"variant": "cpp", "variant": "cpp"
"csignal": "cpp", }
"syncstream": "cpp"
},
"C_Cpp.default.compilerPath": "/usr/bin/clang++"
} }

View File

@@ -1,18 +1,18 @@
obj-m += wendy.o obj-m += wendy.o
OUT_DIR := build 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 all: kern_mod reader writer tester
kern_mod: wendy.c kern_mod:
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) MO=$(PWD)/build/kern make -C wendy_mod
install: install: kern_mod
sudo insmod ./build/kern/wendy.ko make -C wendy_mod install
uninstall: rm:
sudo rmmod wendy make -C wendy_mod uninstall
reader: dirprepare reader: dirprepare
gcc pipe_read.c -o $(OUT_DIR)/pread gcc pipe_read.c -o $(OUT_DIR)/pread
@@ -27,6 +27,6 @@ dirprepare:
mkdir -p $(OUT_DIR) mkdir -p $(OUT_DIR)
clean: clean:
$(MAKE) -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean make -C wendy_mod clean
rm -rf $(OUT_DIR) rm -rf $(OUT_DIR)

View File

@@ -7,60 +7,22 @@
void writer() { void writer() {
std::osyncstream(std::cout) << "Writer started" << std::endl; std::osyncstream(std::cout) << "Writer started" << std::endl;
char *buffer = new char[8192]; std::ofstream pipe_write("/dev/wendy_in");
pipe_write << "Hello from the other side\n";
for (int i = 0; i < 8192; ++i) { std::osyncstream(std::cout) << "Writer ended" << std::endl;
buffer[i] = static_cast<char>((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;
} }
void reader() { void reader() {
std::osyncstream(std::cout) << "Reader started" << std::endl; std::osyncstream(std::cout) << "Reader started" << std::endl;
FILE *fl = fopen("/dev/wendy_out", "r"); std::ifstream pipe_read("/dev/wendy_out");
if (!fl) { std::osyncstream(std::cout) << "Reader read content: " << pipe_read.rdbuf();
std::osyncstream(std::cerr) << "Cannot open wendy_out" << std::endl; std::osyncstream(std::cout) << "Reader ended" << 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;
} }
int main() { int main() {
std::thread writer_thread(writer);
std::thread reader_thread(reader); std::thread reader_thread(reader);
std::this_thread::sleep_for(std::chrono::milliseconds(100)); std::this_thread::sleep_for(std::chrono::milliseconds(100));
std::thread writer_thread(writer);
if (reader_thread.joinable()) { if (reader_thread.joinable()) {
reader_thread.join(); reader_thread.join();
} }

View File

@@ -1,7 +1,7 @@
{ {
"configurations": [ "configurations": [
{ {
"name": "Linux Kernel Module", "name": "Linux",
"includePath": [ "includePath": [
"/usr/lib/modules/6.14.3-arch1-1/build/include", "/usr/lib/modules/6.14.3-arch1-1/build/include",
"/usr/lib/modules/6.14.3-arch1-1/build/arch/x86/include", "/usr/lib/modules/6.14.3-arch1-1/build/arch/x86/include",

8
lab6/wendy_mod/.vscode/settings.json vendored Normal file
View File

@@ -0,0 +1,8 @@
{
"files.associations": {
"cdev.h": "c",
"module.h": "c",
"types.h": "c",
"init.h": "c",
}
}

20
lab6/wendy_mod/Makefile Normal file
View File

@@ -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

View File

@@ -20,6 +20,8 @@ enum MyPipeMinors {
struct mypipe_data { struct mypipe_data {
struct cdev cdev; struct cdev cdev;
// Whether opened by some writer
bool is_active;
u8 buffer[MYPIPE_BUFFER_SIZE]; u8 buffer[MYPIPE_BUFFER_SIZE];
size_t write_pos; size_t write_pos;
size_t read_pos; size_t read_pos;
@@ -33,18 +35,43 @@ static struct class *mypipedev_class = NULL;
// Protects the buffer // Protects the buffer
static DEFINE_MUTEX(mypipe_lock); 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 // These are two wait_queue_head_t for storing tasks that are waiting for
// writing/ reading // writing/ reading
static DECLARE_WAIT_QUEUE_HEAD(read_queue); static DECLARE_WAIT_QUEUE_HEAD(read_queue);
static DECLARE_WAIT_QUEUE_HEAD(write_queue); static DECLARE_WAIT_QUEUE_HEAD(write_queue);
static int mypipe_open(struct inode *inode, struct file *file) { 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; return 0;
} }
static int mypipe_release(struct inode *inode, struct file *file) { 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; 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 // We currently have no data, but we can wait for possible new to write in
while (pdata.data_len == 0) { while (pdata.data_len == 0) {
mutex_unlock(&mypipe_lock); 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) { if (filep->f_flags & O_NONBLOCK) {
// The caller says no waiting, so we don't wait
return -EAGAIN; return -EAGAIN;
} }
if (wait_event_interruptible(read_queue, pdata.data_len > 0)) { 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), device_create(mypipedev_class, NULL, MKDEV(dev_major, MYPIPE_MINOR_OUT),
NULL, "%s_out", MYPIPE_DEVICE_NAME); 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; return 0;
del_cdev: del_cdev:
@@ -229,7 +272,7 @@ static void __exit mypipe_destroy(void) {
class_destroy(mypipedev_class); class_destroy(mypipedev_class);
cdev_del(&pdata.cdev); cdev_del(&pdata.cdev);
unregister_chrdev_region(MKDEV(dev_major, 0), MYPIPE_MINOR_COUNT); 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); module_init(mypipe_init);