介绍
大概就是down和up两个函数
一个加锁,一个解锁
这里主要用于进程同步
核心api
set_current_state
schedule
wake_up_process
linux源码实现
在linux内核源码里对于信号量资源操作,主要是通过自旋锁
结构体大概如下:
struct sem
{
int rc;
sipnlock lock;
struct task_struct* queue_list;
}
实现原理
task_struct这个结构体存储了进程context,需要弄成链表形式,方便睡眠时存储,以及唤醒时使用
大概流程如下:
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;
};
这里用了首尾两个等待链,方便操作
…
down实现
SYSCALL_DEFINE1(down, struct mysem __user* ,sem)
{
if(sem == NULL)
{
printk("sem is null\n");
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 failed\n");
return -1;
}
}
//lock
mutex_lock(sem->sem_mutex);
//loop judging
while(sem->value <= 0)
{
//Judge whether the task_queue_head is NULL
if(sem->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 error\n");
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 error\n");
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 null\n");
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: 我这没有用自旋锁,而是用的互斥,其实都差不多,互斥方便些,遇到并发无脑互斥就对了。