使用 make check 來查看輸出
Last active
May 10, 2025 15:13
-
-
Save afcidk/18508eaa63da55a5b9799fa6edf936e2 to your computer and use it in GitHub Desktop.
A simple kernel module to show why mutex locks matters.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <stdio.h> | |
#include <stdlib.h> | |
#include <pthread.h> | |
#include <unistd.h> | |
#include <string.h> | |
#include <sys/types.h> | |
#include <fcntl.h> | |
#define FIB_DEV "/dev/test_mutex" | |
int s = 0; | |
void child(void *data) { | |
int fd = open(FIB_DEV, O_RDWR); | |
int tmp = ++s; | |
if (fd < 0) { | |
perror("Failed to open character device"); | |
return ; | |
} | |
printf("%d: Writing %s to kernel\n", tmp, (char*)data); | |
write(fd, (char*)data, strlen((char*)data)); | |
usleep(10); | |
char buf[100]; | |
read(fd, buf, 100); | |
printf("%d: Received %s from kernel (Should receive %s)\n", tmp, buf, (char*)data); | |
} | |
int main() | |
{ | |
pthread_t t[10]; | |
char strings[][10] = {"aaa", "bbb", "CCC", "ddd", "eee", "fff", "ggg", "hhh", "iii", "jjj"}; | |
for (int i=0; i<10; ++i) { | |
pthread_create(&(t[i]), NULL, (void*)child, strings[i]); | |
} | |
for (int i=0; i<10; ++i) { | |
pthread_join(t[i], NULL); | |
} | |
return 0; | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
CONFIG_MODULE_SIG = n | |
TARGET_MODULE := test_mutex | |
obj-m := $(TARGET_MODULE).o | |
ccflags-y := -std=gnu99 -Wno-declaration-after-statement | |
KDIR := /lib/modules/$(shell uname -r)/build | |
PWD := $(shell pwd) | |
all: client | |
$(MAKE) -C $(KDIR) M=$(PWD) modules | |
clean: | |
$(MAKE) -C $(KDIR) M=$(PWD) clean | |
$(RM) client out *.out test | |
load: | |
sudo insmod $(TARGET_MODULE).ko | |
unload: | |
sudo rmmod $(TARGET_MODULE) || true >/dev/null | |
client: | |
gcc -o test client_mtt.c -lpthread | |
check: all | |
$(MAKE) unload | |
$(MAKE) load | |
sudo ./test | |
$(MAKE) unload |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <linux/cdev.h> | |
#include <linux/device.h> | |
#include <linux/uaccess.h> | |
#include <linux/fs.h> | |
#include <linux/init.h> | |
#include <linux/kdev_t.h> | |
#include <linux/kernel.h> | |
#include <linux/module.h> | |
#include <linux/mutex.h> | |
MODULE_LICENSE("Dual MIT/GPL"); | |
MODULE_DESCRIPTION("Kernel module without mutex lock functionality"); | |
MODULE_VERSION("0.1"); | |
#define DEV_FIBONACCI_NAME "test_mutex" | |
static dev_t fib_dev = 0; | |
static struct cdev *fib_cdev; | |
static struct class *fib_class; | |
#define MUTEX 1 | |
#define MAX_LENGTH 92 | |
static DEFINE_MUTEX(fib_mutex); | |
char data[100]; | |
static int open(struct inode *inode, struct file *file) | |
{ | |
if (!mutex_trylock(&fib_mutex)) { | |
printk(KERN_ALERT "fibdrv is in use, but will still go on."); | |
// FIXME: If we want the mutex lock to work well, need to return -EBUSY | |
// return -EBUSY; | |
} | |
return 0; | |
} | |
static int release(struct inode *inode, struct file *file) | |
{ | |
mutex_unlock(&fib_mutex); | |
return 0; | |
} | |
/* calculate the fibonacci number at given offset */ | |
static ssize_t read(struct file *file, | |
char *buf, | |
size_t size, | |
loff_t *offset) | |
{ | |
copy_to_user(buf, data, strlen(data)); | |
return 0; | |
} | |
/* write operation is skipped */ | |
static ssize_t write(struct file *file, | |
const char *buf, | |
size_t size, | |
loff_t *offset) | |
{ | |
copy_from_user(data, buf, 100); | |
return 1; | |
} | |
static loff_t device_lseek(struct file *file, loff_t offset, int orig) | |
{ | |
loff_t new_pos = 0; | |
switch (orig) { | |
case 0: /* SEEK_SET: */ | |
new_pos = offset; | |
break; | |
case 1: /* SEEK_CUR: */ | |
new_pos = file->f_pos + offset; | |
break; | |
case 2: /* SEEK_END: */ | |
new_pos = MAX_LENGTH - offset; | |
break; | |
} | |
if (new_pos > MAX_LENGTH) | |
new_pos = MAX_LENGTH; // max case | |
if (new_pos < 0) | |
new_pos = 0; // min case | |
file->f_pos = new_pos; // This is what we'll use now | |
return new_pos; | |
} | |
const struct file_operations fops = { | |
.owner = THIS_MODULE, | |
.read = read, | |
.write = write, | |
.open = open, | |
.release = release, | |
.llseek = device_lseek, | |
}; | |
static int __init init_dev(void) | |
{ | |
int rc = 0; | |
mutex_init(&fib_mutex); | |
// Let's register the device | |
// This will dynamically allocate the major number | |
rc = alloc_chrdev_region(&fib_dev, 0, 1, DEV_FIBONACCI_NAME); | |
if (rc < 0) { | |
printk(KERN_ALERT | |
"Failed to register the fibonacci char device. rc = %i", | |
rc); | |
return rc; | |
} | |
fib_cdev = cdev_alloc(); | |
if (fib_cdev == NULL) { | |
printk(KERN_ALERT "Failed to alloc cdev"); | |
rc = -1; | |
goto failed_cdev; | |
} | |
cdev_init(fib_cdev, &fops); | |
rc = cdev_add(fib_cdev, fib_dev, 1); | |
if (rc < 0) { | |
printk(KERN_ALERT "Failed to add cdev"); | |
rc = -2; | |
goto failed_cdev; | |
} | |
fib_class = class_create(THIS_MODULE, DEV_FIBONACCI_NAME); | |
if (!fib_class) { | |
printk(KERN_ALERT "Failed to create device class"); | |
rc = -3; | |
goto failed_class_create; | |
} | |
if (!device_create(fib_class, NULL, fib_dev, NULL, DEV_FIBONACCI_NAME)) { | |
printk(KERN_ALERT "Failed to create device"); | |
rc = -4; | |
goto failed_device_create; | |
} | |
return rc; | |
failed_device_create: | |
class_destroy(fib_class); | |
failed_class_create: | |
cdev_del(fib_cdev); | |
failed_cdev: | |
unregister_chrdev_region(fib_dev, 1); | |
return rc; | |
} | |
static void __exit exit_dev(void) | |
{ | |
mutex_destroy(&fib_mutex); | |
device_destroy(fib_class, fib_dev); | |
class_destroy(fib_class); | |
cdev_del(fib_cdev); | |
unregister_chrdev_region(fib_dev, 1); | |
} | |
module_init(init_dev); | |
module_exit(exit_dev); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment