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": {
|
"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++"
|
|
||||||
}
|
}
|
||||||
@@ -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)
|
||||||
|
|
||||||
|
|||||||
@@ -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();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
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 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);
|
||||||
Reference in New Issue
Block a user