2017-11-05 24 views
0

読み書きを消費する実装の単純なcharドライバを書きたいと思っています。読み込みと書き込みのオフセット用のバッファと2つのグローバルポインタを保持しています。すべてのプロセスは排他的に読み取りまたは書き込みを行う必要があります。また、読み取りには少なくとも512バイトがあるまで待機する必要があります。演習のために、私はmutexの代わりにwait_event_interruptible_exclusiveとしたいと思います。私の読み書きは次の通りです:カーネルのミューテックスとwait_event_interruptible_exclusiveとの比較

static ssize_t 
my_read(struct file *file, char __user *buf, size_t lbuf, loff_t *ppos) 
{ 
    int nbytes; 
    wait_event_interruptible_exclusive(wq, atomic_read(&data_sz) >=512 && (atomic_xchg(&data_sz,-1) || 1));   
    nbytes = simple_read_from_buffer(buf, lbuf, &read_pos, my_buff, my_buff_size); 
    *ppos = read_pos; 
    atomic_set(&data_sz,write_pos-read_pos); 
    wake_up_interruptible(&wq); 
    return nbytes; 
} 

static ssize_t 
my_write(struct file *file, const char __user *buf, size_t lbuf, 
    loff_t *ppos) 
{ 
    int nbytes; 
    wait_event_interruptible_exclusive(wq, atomic_read(&data_sz) != -1 && (atomic_xchg(&data_sz,-1) || 1)); 

    nbytes = simple_write_to_buffer(my_buff, my_buff_size, &write_pos, buf, lbuf); 
    *ppos = write_pos; 

    atomic_set(&data_sz,write_pos-read_pos); 
    wake_up_interruptible(&wq); 
    return nbytes; 
} 

そういうのは大丈夫ですか? mutexのあらゆる使用法をそのようなものに置き換えることは可能ですか? また、バッファの私のオフセットはグローバルなので、読み書きのpposパラメータはドライバによって無視され、行*ppos=read_pos*ppos=write_posが必要かどうか疑問に思っていますか?

+0

「すべてのプロセスは排他的に読み取りまたは書き込みする必要があります」 - 排他性を保証するものではありません。たとえば、2人の読者の条件が同時にチェックされると、両方の読者は「atomic_read(&data_sz)> = 512」が真であると判読して読書に進むことができる。排他性がなければ、 'write_pos'と' read_pos'へのアクセスに関する競争条件があります。 – Tsyvarev

+0

これは、atomic_read(&data_sz)> = 512 &&(atomic_xchg(&data_sz、-1)|| 1) 'であり、' atomic_read(&data_sz)> = 512'だけでなく、 = 512'とすると、data_szを-1に設定します – dafnahaktana

答えて

2

アトミック動作が実行されている間は不可分すべてのプロセスの観点から、(例えば&&動作と)組み合わせアトミックオペレーションのもう不可分を有していません。コードで

、同時に2本の読者はatomic_read(&data_sz) >=512が真であることがわかり、その後、(第2のリーダは-1data_szに等しいと、この操作を実行することになる)atomic_xchg(&data_sz,-1)を実行してもよいです。

状態の分断可能性については、スピンロックによる評価を保護することができます。その場合、原子変数は必要ありません。以下の例では、waitqueue自体が提供するスピンロックを使用しています。

loff_t read_pos = 0, write_pos = 0; 
size_t data_sz = 0; 

DECLARE_WAIT_QUEUE_HEAD(wq); 

static ssize_t 
my_read(struct file *file, char __user *buf, size_t lbuf, loff_t *ppos) 
{ 
    int nbytes; 
    spin_lock(&wq.lock); // Take the lock before checking condition 
    // Next call will drop the lock while waiting and reacquire it on wake up. 
    wait_event_interruptible_exclusive_locked(&wq, data_sz >= 512); 
    // TODO: Interruptible wait may wakeup premature; check its return value. 
    data_sz = -1; // Prevent other waiters to enter read/write section 
    spin_unlock(&wq.lock); 

    nbytes = simple_read_from_buffer(buf, lbuf, &read_pos, my_buff, my_buff_size); 
    *ppos = read_pos; 

    spin_lock(&wq.lock); // Take the lock before updating data_sz 
    data_sz = write_pos - read_pos; 
    // There is no 'wake_up_interruptible_locked', 
    // but "normal" wakeup works with interruptible waits too. 
    wake_up_locked(&wq); 
    spin_unlock(&wq.lock); 

    return nbytes; 
} 
関連する問題