歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
您现在的位置: Linux教程網 >> UnixLinux >  >> Linux綜合 >> Linux內核

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

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

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