only allow one writer
This commit is contained in:
12
lab6/.vscode/settings.json
vendored
12
lab6/.vscode/settings.json
vendored
@@ -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"
|
||||
}
|
||||
}
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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
8
lab6/wendy_mod/.vscode/settings.json
vendored
Normal 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
20
lab6/wendy_mod/Makefile
Normal 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
|
||||
@@ -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);
|
||||
Reference in New Issue
Block a user