linux内核讯号量自实现
介绍
大约就是down和up两个函数
一个加锁linux内核信号量,一个解锁
这儿主要用于进程同步
核心api
set_current_state
schedule
wake_up_process
linux源码实现
在linux内核源码里对于讯号量资源操作,主要是通过载流子锁
结构体大约如下:
struct sem
{
int rc;
sipnlock lock;
struct task_struct* queue_list;
}
实现原理
task_struct这个结构体储存了进程context,须要变成数组方式,便捷睡眠时储存linux内核信号量,以及唤起时使用
大约流程如下:
down里加入进程到等待链,之后调用set_current_state和schedule睡眠
up里取出等待链中的进程,再调用wake_up_process唤起
自实现
结构定义
struct task_queue
{
//process task
struct task_struct* task;
//next process task
struct task_queue* next;
};
struct mysem
{
int value;
//mutex lock pointer
struct mutex* sem_mutex;
//head task queue
struct task_queue* task_queue_head;
//tail task queue
struct task_queue* task_queue_tail;
};
这儿用了首尾两个等待链linuxvi,便捷操作
…
down实现
SYSCALL_DEFINE1(down, struct mysem __user* ,sem)
{
if(sem == NULL)
{
printk("sem is nulln");
return -1;
}
//Judge whether the sem_mutex is NULL
if(sem->sem_mutex == NULL)
{
//define the sem_mutex
DEFINE_MUTEX(sem_mutex);
//to assign memory for the sem_mutex
sem->sem_mutex = kmalloc(sizeof(struct mutex), GFP_KERNEL);
if(sem->sem_mutex)
{
//set sem_mutex to sem->sem_mutex
*(sem->sem_mutex) = sem_mutex;
//resources--
sem->value--;
return 0;
}
else
{
printk("kmalloc sem_mutex failedn");
return -1;
}
}
//lock
mutex_lock(sem->sem_mutex);
//loop judging
while(sem->value task_queue_head == NULL)
{
//to assign memory for the task_queue_head
sem->task_queue_head = kmalloc(sizeof(struct task_queue), GFP_KERNEL);
if(sem->task_queue_head == NULL)
{
printk("kmalloc ln errorn");
mutex_unlock(sem->sem_mutex);
return -1;
}
//set current to task_list->ts
sem->task_queue_head->task = current;
sem->task_queue_head->next = NULL;
//set task_queue_head to task_queue_tail
sem->task_queue_tail = sem->task_queue_head;
}
else
{
//to assign memory for the sem->task_queue_tail->next
sem->task_queue_tail->next = kmalloc(sizeof(struct task_queue), GFP_KERNEL);
if(sem->task_queue_tail->next == NULL)
{
printk("kmalloc ln errorn");
mutex_unlock(sem->sem_mutex);
return -1;
}
//set current to sem->task_queue_tail->next->task
sem->task_queue_tail->next->task = current;
sem->task_queue_tail->next->next = NULL;
}
//set state
set_current_state(TASK_INTERRUPTIBLE);
//unlock
mutex_unlock(sem->sem_mutex);
schedule();
//lock
mutex_lock(sem->sem_mutex);
}
//resource--
sem->value--;
//unlock
mutex_unlock(sem->sem_mutex);
return 0;
}
up实现
SYSCALL_DEFINE1(up, struct mysem __user* ,sem)
{
struct task_queue* temp = NULL;
if(sem == NULL)
{
printk("sem is nulln");
return -1;
}
//lock
mutex_lock(sem->sem_mutex);
temp = sem->task_queue_head;
//resources--
sem->value++;
//Judge whether the head node is not NULL
if(temp != NULL)
{
//set the header node to the next
sem->task_queue_head = sem->task_queue_head->next;
//Judge whether the head node is NULL
if(sem->task_queue_head == NULL)
{
//set the tail node to NULL
sem->task_queue_tail = NULL;
}
//wake_up head node
wake_up_process(temp->task);
//free
kfree(temp);
}
//unlock
mutex_unlock(sem->sem_mutex);
return 0;
}
ps:我这没有用载流子锁红联linux论坛,而是用的互斥,似乎都差不多,互斥便捷些,遇见并发无脑互斥就对了。
本文原创地址://q13zd.cn/dhulghsygjs.html编辑:刘遄,审核员:暂无