Last active
March 17, 2023 14:20
-
-
Save joelagnel/458dad7e82160eb6265835dd0dacd70e to your computer and use it in GitHub Desktop.
This file contains 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/init.h> | |
#include <linux/module.h> | |
#include <linux/kernel.h> | |
#include <linux/mutex.h> | |
#include <linux/slab.h> | |
#include <linux/kthread.h> | |
#include <linux/delay.h> | |
#include <linux/moduleparam.h> | |
#include <linux/list.h> | |
MODULE_LICENSE("GPL"); | |
MODULE_DESCRIPTION("A kernel module to test mutex first-come, first-served behavior"); | |
static int num_threads = 3; | |
static int num_iterations = 5; | |
static int thread_delay_ms = 10; | |
module_param(num_threads, int, 0); | |
MODULE_PARM_DESC(num_threads, "Number of threads to create (default: 3)"); | |
module_param(num_iterations, int, 0); | |
MODULE_PARM_DESC(num_iterations, "Number of iterations per thread (default: 5)"); | |
module_param(thread_delay_ms, int, 0); | |
MODULE_PARM_DESC(thread_delay_ms, "Delay between thread iterations in milliseconds (default: 10)"); | |
static struct task_struct **threads; | |
static DEFINE_MUTEX(shared_resource_mutex); | |
static int shared_resource_counter = 0; | |
struct mutex_queue_node { | |
int id; | |
struct list_head list; | |
}; | |
static LIST_HEAD(mutex_queue); | |
static int thread_fn(void *data) | |
{ | |
int id = *(int *)data; | |
int i; | |
struct mutex_queue_node *node = NULL; | |
printk(KERN_INFO "Thread %d starting...\n", id); | |
for (i = 0; i < num_iterations; i++) { | |
mutex_lock(&shared_resource_mutex); | |
node = kmalloc(sizeof(*node), GFP_KERNEL); | |
if (!node) { | |
mutex_unlock(&shared_resource_mutex); | |
printk(KERN_ERR "Failed to allocate memory for mutex queue node\n"); | |
return -ENOMEM; | |
} | |
node->id = id; | |
printk(KERN_INFO "Thread %d acquired the mutex\n", id); | |
if (!list_empty(&mutex_queue)) { | |
struct mutex_queue_node *last_node = list_entry(mutex_queue.prev, struct mutex_queue_node, list); | |
if (last_node->id != id) { | |
printk(KERN_ERR "Thread %d acquired mutex out of order\n", id); | |
BUG_ON(1); | |
} | |
} | |
/* Add node to the end of the queue */ | |
list_add_tail(&node->list, &mutex_queue); | |
/* Access the shared resource */ | |
shared_resource_counter++; | |
printk(KERN_INFO "Thread %d incremented the shared resource counter to %d\n", | |
id, shared_resource_counter); | |
/* Remove node from the front of the queue */ | |
node = list_entry(mutex_queue.next, struct mutex_queue_node, list); | |
list_del(&node->list); | |
kfree(node); | |
printk(KERN_INFO "Thread %d released the mutex\n", id); | |
mutex_unlock(&shared_resource_mutex); | |
msleep(thread_delay_ms); | |
} | |
printk(KERN_INFO "Thread %d exiting...\n", id); | |
return 0; | |
} | |
int *thread_ids; | |
static int __init mutex_test_init(void) | |
{ | |
int i; | |
printk(KERN_INFO "Mutex test module loaded\n"); | |
if (num_threads < 1 || num_threads > 1000) { | |
printk(KERN_ERR "Invalid number of threads: %d (should be between 1 and 1000)\n", num_threads); | |
return -EINVAL; | |
} | |
thread_ids = kmalloc(num_threads * sizeof(int), GFP_KERNEL); | |
if (!thread_ids) { | |
printk(KERN_ERR "Failed to allocate memory for thread IDs\n"); | |
return -ENOMEM; | |
} | |
threads = kmalloc(num_threads * sizeof(struct task_struct *), GFP_KERNEL); | |
if (!threads) { | |
printk(KERN_ERR "Failed to allocate memory for threads\n"); | |
kfree(thread_ids); | |
return -ENOMEM; | |
} | |
for (i = 0; i < num_threads; i++) { | |
thread_ids[i] = i; | |
threads[i] = kthread_run(thread_fn, &thread_ids[i], "mutex-test-%d", i); | |
if (IS_ERR(threads[i])) { | |
printk(KERN_ERR "Failed to create thread %d\n", i); | |
kfree(thread_ids); | |
kfree(threads); | |
return PTR_ERR(threads[i]); | |
} | |
} | |
return 0; | |
} | |
static void __exit mutex_test_exit(void) | |
{ | |
int i; | |
printk(KERN_INFO "Mutex test module unloaded\n"); | |
for (i = 0; i < num_threads; i++) { | |
if (threads[i]) { | |
kthread_stop(threads[i]); | |
} | |
} | |
if (threads) { | |
kfree(threads); | |
} | |
if (thread_ids) { | |
kfree(thread_ids); | |
} | |
} | |
module_init(mutex_test_init); | |
module_exit(mutex_test_exit); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment