linux内核讯号量自实现

介绍

大约就是down和up两个函数

一个加锁linux内核信号量,一个解锁

这儿主要用于进程同步

核心api

set_current_state

schedule

wake_up_process

linux源码实现

linux内核信号量_linux的信号量_linux内核越高越好吗

在linux内核源码里对于讯号量资源操作,主要是通过载流子锁

结构体大约如下:

struct sem
{
	int rc;
	sipnlock lock;
	struct task_struct* queue_list;
}

实现原理

linux内核越高越好吗_linux内核信号量_linux的信号量

task_struct这个结构体储存了进程context,须要变成数组方式,便捷睡眠时储存linux内核信号量,以及唤起时使用

大约流程如下:

down里加入进程到等待链,之后调用set_current_state和schedule睡眠

up里取出等待链中的进程,再调用wake_up_process唤起

linux内核越高越好吗_linux的信号量_linux内核信号量

自实现

结构定义

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编辑:刘遄,审核员:暂无