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": {
"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"
}
}

View File

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

View File

@@ -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<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;
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();
}

View File

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

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 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);