linux内核信号量自实现

介绍

大概就是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: 我这没有用自旋锁,而是用的互斥,其实都差不多,互斥方便些,遇到并发无脑互斥就对了。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值