Linux裝置驅動程式設計之阻塞與非阻塞(轉)

BSDLite發表於2007-08-16
Linux裝置驅動程式設計之阻塞與非阻塞(轉)[@more@]  阻塞操作是指,在執行裝置操作時,若不能獲得資源,則程式掛起直到滿足可操作的條件再進行操作。非阻塞操作的程式在不能進行裝置操作時,並不掛起。被掛起的程式進入sleep狀態,被從排程器的執行佇列移走,直到等待的條件被滿足。

  在Linux驅動程式中,我們可以使用等待佇列(wait queue)來實現阻塞操作。wait queue很早就作為一個基本的功能單位出現在Linux核心裡了,它以佇列為基礎資料結構,與程式排程機制緊密結合,能夠用於實現核心的非同步事件通知機制。等待佇列可以用來同步對系統資源的訪問,上節中所講述Linux訊號量在核心中也是由等待佇列來實現的。

  下面我們重新定義裝置"globalvar",它可以被多個程式開啟,但是每次只有當一個程式寫入了一個資料之後本程式或其它程式才可以讀取該資料,否則一直阻塞。
CODE:
#include
#include
#include
#include
#include
#include
MODULE_LICENSE("GPL");

#define MAJOR_NUM 254

static ssize_t globalvar_read(struct file *, char *, size_t, loff_t*);
static ssize_t globalvar_write(struct file *, const char *, size_t, loff_t*);

struct file_operations globalvar_fops =
{
 read: globalvar_read, write: globalvar_write,
};

static int global_var = 0;
static struct semaphore sem;
static wait_queue_head_t outq;
static int flag = 0;

static int __init globalvar_init(void)
{
 int ret;
 ret = register_chrdev(MAJOR_NUM, "globalvar", &globalvar_fops);
 if (ret)
 {
  printk("globalvar register failure");
 }
 else
 {
  printk("globalvar register success");
  init_MUTEX(&sem);
  init_waitqueue_head(&outq);
 }
 return ret;
}

static void __exit globalvar_exit(void)
{
 int ret;
 ret = unregister_chrdev(MAJOR_NUM, "globalvar");
 if (ret)
 {
  printk("globalvar unregister failure");
 }
 else
 {
  printk("globalvar unregister success");
 }
}

static ssize_t globalvar_read(struct file *filp, char *buf, size_t len, loff_t *off)
{
 //等待資料可獲得
 if (wait_event_interruptible(outq, flag != 0))
 {
  return - ERESTARTSYS;
 }

 if (down_interruptible(&sem))
 {
  return - ERESTARTSYS;
 }

 flag = 0;
 if (copy_to_user(buf, &global_var, sizeof(int)))
 {
  up(&sem);
  return - EFAULT;
 }
 up(&sem);
 return sizeof(int);
}

static ssize_t globalvar_write(struct file *filp, const char *buf, size_t len,loff_t *off)
{
 if (down_interruptible(&sem))
 {
  return - ERESTARTSYS;
 }
 if (copy_from_user(&global_var, buf, sizeof(int)))
 {
  up(&sem);
  return - EFAULT;
 }
 up(&sem);
 flag = 1;
 //通知資料可獲得
 wake_up_interruptible(&outq);
 return sizeof(int);
}

module_init(globalvar_init);
module_exit(globalvar_exit);

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/10617542/viewspace-962133/,如需轉載,請註明出處,否則將追究法律責任。

Linux裝置驅動程式設計之阻塞與非阻塞(轉)
請登入後發表評論 登入
全部評論

相關文章