私はデータ取得システム用のデバイスドライバを開発中です。定期的に同時に入出力データを提供するpciデバイスがあります。そして、linux modは、ファイル操作を通じて読み書きされる循環バッファ内のデータを管理します。外部イベントまで読み取り操作をブロックする正しい方法はありますか?
システムのデータスループットは比較的低く、750,000バイト/秒をわずかに受信し、わずか150,000バイト/秒を送信します。
テスト用にループ内のデータの書き込みと読み取りを行う小さなユーザースペースユーティリティがあります。ここで
は、ドライバコードのセクション(循環バッファに関連するすべてのコードは単純化のために省略されています。PCIデバイスの初期化が他の場所での世話をし、割り込みハンドラのための本当のエントリポイントをないpci_interuptれる)
です#include <linux/sched.h>
#include <linux/wait.h>
static DECLARE_WAIT_QUEUE_HEAD(wq_head);
static ssize_t read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos)
{
DECLARE_WAITQUEUE(wq, current);
if(count == 0)
return 0;
add_wait_queue(&wq_head, &wq);
do
{
set_current_state(TASK_INTERRUPTIBLE);
if(/*There is any data in the receive buffer*/)
{
/*Copy Data from the receive buffer into user space*/
break;
}
schedule();
} while(1);
set_current_state(TASK_RUNNING);
remove_wait_queue(&wq_head, &wq);
return count;
}
static ssize_t write(struct file *filp, const char __user *buf, size_t count, loff_t *f_pos) {
/* Copy data from userspace into the transmit buffer*/
}
/* This procedure get's called in real time roughly once every 5 milliseconds,
It writes 4k to the receiving buffer and reads 1k from the transmit buffer*/
static void pci_interrupt() {
/*Copy data from PCI dma buffer to receiving buffer*/
if(/*There is enough data in the transmit buffer to fill the PCI dma buffer*/) {
/*Copy from the transmit buffer to the PCI device*/
} else {
/*Copy zero's to the PCI device*/
printk(KERN_ALERT DEVICE_NAME ": Data Underflow. Writing 0's'");
}
wake_up_interruptible(&wq_head);
}
上記のコードは長時間有効ですが、12-18時間ごとにデータアンダーフローエラーが発生します。結果としてゼロが書き込まれます。
私の最初の考えは、ユーザー空間アプリケーションが本当にリアルタイムではないため、読み書き操作の間の時間遅延がときどき大きくなって失敗を引き起こすことです。しかし、私は読み書きのサイズをユーザ空間に変更しようとしましたが、エラーの頻度に影響を与えなかったユーザ空間アプリケーションの正しさを変えました。
上記の3つの方法では、競合状態のいくつかの形があると私は信じています。私は、どのようにLinuxのカーネル待ち行列が動作するかわかりません。
読み取りをブロックするための上記の方法にまともな代替方法がありますか、またはこの動作を引き起こす可能性がある間違いがあります。
システム情報:
Linuxのバージョン:Ubuntuの16.10
Linuxカーネル:のlinux-4.8.0-lowlatency
チップセット:インテルCeleronのN3150/N3160クアッドコア2.08 GHz帯のSoC
TL; DR:上記のコードでは、12〜18時間ごとにアンダーフローエラーが発生するため、コード内でIOまたは競合状態をブロックする良い方法があります。