2015-04-21 106 views
4

我正在爲操作系統類寫一個「困」的設備驅動程序。linux wake_up_interruptible()沒有效果

它的工作方式是,用戶通過read()/write()訪問設備。 當用戶寫入設備時,如下所示:write(fd, &wait, size),設備進入睡眠狀態的時間量爲wait的秒數。如果等待時間到期,則驅動程序的寫入方法返回0,程序結束。但是,如果用戶在進程在等待隊列中休眠時從驅動程序中讀取數據,則驅動程序的寫入方法會立即返回睡眠進程在超時自行發生之前需要等待的秒數。

另一個問題是創建了10個設備實例,並且10個設備中的每個設備都必須是相互獨立的。因此,對設備1的讀取必須僅喚醒設備1上的睡眠過程。

已提供了許多代碼,並且我負責主要爲驅動程序編寫read()write()方法。

我試圖解決保持設備彼此獨立的問題的方式是包含兩個大小爲10的全局靜態數組。其中一個類型爲wait_head_queue_t,類型爲Int(布爾標誌)。當我通過open()打開設備時,這兩個陣列都會初始化一次。問題是,當我撥打wake_up_interruptible()時,什麼都沒有發生,並且程序在超時時終止。這是我寫的方法:

ssize_t sleepy_write(struct file *filp, const char __user *buf, size_t count, loff_t *f_pos){ 
struct sleepy_dev *dev = (struct sleepy_dev *)filp->private_data; 

ssize_t retval = 0; 
int mem_to_be_copied = 0; 

if (mutex_lock_killable(&dev->sleepy_mutex)) 
{ 
    return -EINTR; 
} 

// check size 
if(count != 4) // user must provide 4 byte Int 
{ 
    return EINVAL; // = 22 
} 
// else if the user provided valid sized input... 
else 
{ 
     if((mem_to_be_copied = copy_from_user(&long_buff[0], buf, count))) 
     { 
     return -EFAULT; 
     } 

     // check for negative wait time entered by user 
     if(long_buff[0] > -1)// "long_buff[]"is global,for now only holds 1 value 
     { 
     proc_read_flags[MINOR(dev->cdev.dev)] = 0; //****** flag array 
     retval = wait_event_interruptible_timeout(wqs[MINOR(dev->cdev.dev)], proc_read_flags[MINOR(dev->cdev.dev)] == 1, long_buff[0] * HZ)/HZ; 
     proc_read_flags[MINOR(dev->cdev.dev)] = 0; // MINOR numbers for each 
            // device correspond to array indices 
             // devices 0 - 9 
             // "wqs" is array of wait queues 
     } 
     else 
     { 
     printk(KERN_INFO "user entered negative value for sleep time\n"); 
     } 
} 

mutex_unlock(&dev->sleepy_mutex); 
return retval;} 

不同於在這個話題的例子很多,我切換旗回零馬上打電話給wait_event_interruptible_timeout()之前,因爲標誌值似乎後續程序的運行之間進行徘徊。下面是我的閱讀方法的代碼:

ssize_t sleepy_read(struct file *filp, char __user *buf, size_t count, 
     loff_t *f_pos){ 

struct sleepy_dev *dev = (struct sleepy_dev *)filp->private_data; 
ssize_t retval = 0; 

if (mutex_lock_killable(&dev->sleepy_mutex)) 
    return -EINTR; 

// switch the flag 
proc_read_flags[MINOR(dev->cdev.dev)] = 1; // again device minor numbers 
              // correspond to array indices 

// TODO: this is not waking up the process in write! 
// wake up the queue 
wake_up_interruptible(&wqs[MINOR(dev->cdev.dev)]); 

mutex_unlock(&dev->sleepy_mutex); 

return retval;} 

我想測試程序的方法是有兩個main.c中的,一個用於寫入設備和一個從設備讀取,我只是./a.out他們在我的ubuntu安裝在虛擬框中單獨的控制檯。另一件事,就是現在設置的方式,無論是寫還是讀a.outs直到超時發生。我爲代碼的參差不齊的格式表示歉意。我不確定在這裏發生了什麼,所以任何幫助將不勝感激!謝謝!

+2

你有沒有證實wake_up_interruptible(WQS [MINOR(dev亡> cdev.dev)])達到您的超時時間間隔之前調用? – jjb

+0

jjm,你是對的,wake_up_interruptible直到超時後才被調用。 – user1708898

回答

2

您的寫入方法持有sleepy_mutex while wait event。所以讀取方法等待mutex_lock_killable(&dev->sleepy_mutex),而互斥體被作者解鎖。它僅在寫入超時超時時發生,並且寫入方法返回。這是你觀察到的行爲。

通常,wait_event *在任何關鍵部分之外執行。

int check_cond() 
{ 
    int res; 
    spin_lock(&lock); 
    res = <cond>; 
    spin_unlock(&lock); 
    return res; 
} 
... 
    wait_event_interruptible(&wq, check_cond()); 

不幸的是,某種wait_event - 家庭宏不能:可以通過使用這樣的宏_lock -suffixed變體,或簡單地纏繞與自旋鎖獲得/釋放對COND參數例如宏的實現使用時,應該用互斥體保護條件檢查。在這種情況下,您可以使用帶有手動條件檢查代碼的wait_woken()函數。或者在條件檢查周圍不需要互斥鎖或解鎖來重寫代碼。

爲了實現「reader wake writer,如果它是睡眠」功能,您可以採用該答案的代碼https://stackoverflow.com/a/29765695/3440745

作家代碼:

//Declare local variable at the beginning of the function 
    int cflag; 
    ... 
    // Outside of any critical section(after mutex_unlock()) 
    cflag = proc_read_flags[MINOR(dev->cdev.dev)]; 
    wait_event_interruptible_timeout(&wqs[MINOR(dev->cdev.dev)], 
     proc_read_flags[MINOR(dev->cdev.dev)] != cflag, long_buff[0]*HZ); 

讀者代碼:

// Mutex holding protects this flag's increment from concurrent one. 
    proc_read_flags[MINOR(dev->cdev.dev)]++; 
    wake_up_interruptible_all(&wqs[MINOR(dev->cdev.dev)]);