歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
Linux教程網 >> Linux綜合 >> Linux內核 >> Linux內核驅動入門之阻塞操作實驗:glob

Linux內核驅動入門之阻塞操作實驗:glob

日期:2017/3/1 9:40:33   编辑:Linux內核

首先,先來了解一下設備的阻塞與非阻塞操作以及實現阻塞操作的方法:

1.設備的阻塞與非阻塞操作:

阻塞操作是指,在執行設備操作時,若不能獲得資源,則進程被掛起直到滿足可操作的條件再進行操作。非阻塞操作是指,當進程不能進行設備操作時,並不掛起,它或者放棄,或者不停地查詢,直到可以進行操作為止。

2.實現阻塞操作的方法:

在linux驅動程序中,可以使用等待隊列(wait queue)來實現阻塞訪問。

一,glob字符設備驅動程序的編寫,把文件名命名為glob.c,源代碼如下:


#include <linux/module.h>

#include <linux/init.h>

#include <linux/fs.h>

#include <asm/uaccess.h>

#include <linux/wait.h> //有關等待隊列的頭文件

#include <linux/semaphore.h> //有關信號量的頭文件

#include <linux/sched.h>

MODULE_LICENSE("GPL");

#define MAJOR_NUM 1400

#define DEVICE_NAME "glob"

static int glob_var = 0;

static struct semaphore sem; //定義信號量

static wait_queue_head_t outq; //定義一個等待隊列頭

static int flag = 0;

//*******************定義read方法****************************

static ssize_t glob_read(struct file *filp, char *buf, ssize_t len, loff_t *off)

{

//等待數據可獲得

//wait_event_interruptible的返回一個整數值,非零值表示休眠被某個信號中斷

//wait_event_interruptible中第一個參數是等待隊列頭,第二個參數是一個布爾表達式,在條件為真之前,進程會保持休眠

if (wait_event_interruptible(outq, flag != 0))

{

return - ERESTARTSYS;

}

//down_interruptible 函數返回非零值,表示操作被中斷,調用者擁有信號量失敗

if (down_interruptible(&sem))

{

return - ERESTARTSYS;

}

flag = 0;

//將內核空間中的數據移動到用戶空間

if (copy_to_user(buf, &glob_var, sizeof(int)))

{

up(&sem); //移動數據的操作不完全成功也需要釋放信號量

return - EFAULT;

}

up(&sem);//移動數據成功,釋放信號量

return sizeof(int);

}

//************************定義write方法******************************

//glob_write函數中,flip是文件指針,buf是指向用戶空間的緩沖區,len表示請求傳輸數據的長度,

//off指向一個長偏移量類型對象的指針,這個對象指明用戶在文件中進行存儲操作的位置

static ssize_t glob_write(struct file *filp, const char *buf, ssize_t len,loff_t *off)

{

if (down_interruptible(&sem))

{

return - ERESTARTSYS;

}

//將用戶空間的數據移動到內核空間

if (copy_from_user(&glob_var, buf, sizeof(int)))

{

up(&sem); //移動數據不完全成功也需要釋放信號量

return - EFAULT;

}

up(&sem); //移動數據成功,釋放信號量

flag = 1;

//通知數據可獲得

wake_up_interruptible(&outq); //喚醒休眠進程

return sizeof(int);

}

//************初始化file_operations結構體*************

struct file_operations glob_fops =

{

.owner = THIS_MODULE,

.read = glob_read,

.write = glob_write,

};

//*******模塊初始化函數*********

static int __init glob_init(void)

{

int ret;

ret = register_chrdev(MAJOR_NUM, DEVICE_NAME, &glob_fops);

if (ret)

{

printk("glob register failure");

}

else

{

printk("glob register success");

//init_MUTEX(&sem);

sema_init(&sem,1); //初始化一個互斥鎖,把信號量sem的值設置為1

init_waitqueue_head(&outq); //初始化等候隊列頭

}

return ret;

}

//************模塊卸載函數**************

static void __exit glob_exit(void)

{

unregister_chrdev(MAJOR_NUM, DEVICE_NAME);

printk("glob unregister success!\n");

}

module_init(glob_init);

module_exit(glob_exit);

二,Makefile文件的編寫,源代碼如下:

12345

obj-m:=glob.o

default:

$(MAKE) -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules

clean:

$(MAKE) -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean

怎樣在 Ubuntu 上安裝 Linux 3.11 內核 http://www.linuxidc.com/Linux/2013-09/89674.htm

Ubuntu 13.10 (Saucy Salamander) 內核已升級至 Linux Kernel 3.10 RC5 http://www.linuxidc.com/Linux/2013-06/86110.htm

Linux Kernel 3.4.62 LTS 現已經提供下載 http://www.linuxidc.com/Linux/2013-09/90368.htm

如何在Ubuntu 13.10上安裝Linux內核 3.12 http://www.linuxidc.com/Linux/2013-11/92930.htm

三,編譯模塊:

把上面的glob.c和Makefile兩個文件放在同一個文件夾下,我這裡的文件夾是“glob阻塞操作實驗”,然後進入文件夾,打開終端,登錄root,輸入指令make,便開始進行模塊的編譯了,遇到編譯錯誤,多百度,積累經驗。

更多詳情見請繼續閱讀下一頁的精彩內容: http://www.linuxidc.com/Linux/2014-08/106012p2.htm

Copyright © Linux教程網 All Rights Reserved