時間、遅延、および操作の遅延

8906 ワード

HZとjiffies
カーネルはタイマ割り込みによって時間ストリームを追跡する.クロック割り込みは,HZの値に基づいてカーネルが決定するシステムタイマの周期的な間隔によって生じる.HZはアーキテクチャに関する定数であり、またはそのファイルに含まれるサブプラットフォームの関連ファイル.HZは、1秒ごとに何回クロックが中断されるかを定義するために使用される.例えばHZは1000であり,コードは毎秒1000回のクロック割り込みを生じる.グローバル変数jiffiesは、システムが起動してから生成されたビートの合計数を記録するために使用され、1ビートがどのくらいの時間を表すか、例えばHZ=200のようなHZサイズに関係し、1つのjiffiesが5 ms(1 s=1000 ms、1000 ms/200=5 ms)の時間に対応する.2つのノードを比較するマクロは、ヘッダファイルint time_after(unsigned long a, unsigned long b); b>aのとき真int time_before(unsigned long a, unsigned long b); bint time_after_eq(unsigned long a, unsigned long b); b>=aのとき真int time_before_eq(unsigned long a, unsigned long b); b<=aのとき真計算2つのjiffiesインスタンス間の差を返す:diff = (long)t2 - (long)t1;差分値をミリ秒値に変換する:msec = diff * 1000 / HZ;現在時刻の取得
取得時間の関数プロトタイプは次のとおりです.
#include 

struct timeval {
	time_t tv_sec; /* seconds */
	suseconds_t tv_usec; /* microseconds */
};
void do_gettimeofday(struct timeval *tv);

struct timespec {
	time_t tv_sec; // seconds 
	long tv_nsec; // and nanoseconds 
};
struct timespec current_kernel_time(void);

 
実行の遅延
長遅延#include signed long schedule_timeout(signed long timeout); timeoutはjiffiesで表す遅延時間であり、正常値は0を返す.schedule_timeoutは、使用前に現在のプロセスステータスを設定する必要があります.set_current_state(TASK_INTERRUPTIBLE); schedule_timeout(2*HZ); /* 2 */第1行呼び出しset_current_stateは現在のプロセスステータスを設定しており、スケジューラはタイムアウトで期限切れであり、そのステータスはTASK_である.このプロセスはRUNNING時に実行されます.ユーザスペースによって中断されたくない場合は、プロセスステータスをTASK_に設定できます.UNINTERRUPTIBLE.
短い遅延数十ミリ秒レベルの遅延を処理する必要がある場合は、次の関数を使用して処理できます.#include void ndelay(unsigned long nsecs);遅延ナノ秒void udelay(unsigned long usecs);遅延マイクロ秒void mdelay(unsigned long msecs);遅延ミリ秒注意:この3つの遅延関数はいずれも忙しい待機関数なので、遅延中に他のタスクを実行できません.ミリ秒レベル(またはそれ以上)の遅延を実現するもう一つの方法は、ヘッダファイル,具体的には以下の通りである:void msleep(unsigned int millisecs);休眠ミリ秒void ssleep(unsigned int seconds);休眠秒unsigned long msleep_interruptible(unsigned int millisecs);休眠ミリ秒,中断は起動可能
ワークキュー
ワークキューにstruct workqueue_があります.structのタイプです.この構造はで.使用する前に、次の2つの関数を使用してワークキューを作成する必要があります.struct workqueue_struct *create_wrokqueue(const char *name); struct workqueue_struct *create_singlethread_workqueue(const char *name);各ワークキューには、キューにコミットされた関数を実行する1つ以上の専用プロセス(「カーネルスレッド」)があります.createを使用するとworkqueueの場合、カーネルはシステム内の各プロセッサに専用のスレッドを作成します.多くの場合、多くのスレッドは性能にある程度の殺傷力を有する可能性がある.したがって、単一のワークスレッドが十分に使用できる場合はcreate_を使用する必要があります.singlethread_workqueueワークキューを作成します.
ワークキューにタスクをコミットするには、work_を入力する必要があります.struct構造は、次のマクロによってコンパイル時に完了します.DECLARE_WORK(name, void (*function)(void *), void *data);では、nameは宣言する構造名であり、functionはワークキューから呼び出される関数であり、dataはその関数に渡される値です.実行時にワークを構築する必要がある場合はstruct構造、以下のマクロを使用:INIT_WORK(struct work_struct *work, void (*function)(void *), void *data); PREPARE_WORK(struct work_struct *work, void (*function)(void *), void *data); INIT_WORKはより徹底的な構造初期化作業を完成した.この構造を初めて構築する場合は、このマクロを使用します.ワークの場合struct構造はワークキューにコミットされていますが、構造を変更する必要がある場合はPREPARE_を使用します.WORK.
ワークキューにジョブをコミットします.次の2つの関数の1つを使用できます.int queue_work(struct workqueue_struct *queue, struct work_struct *work); int queue_delayed_work(struct workqueue_struct *queue, struct work_struct *work, unsigned long delay);ワークを指定したqueueに追加します.queue_delayed_ワークは、指定されたjiffies(delayによって指定された)後に実行されます.ジョブがキューに正常に追加された場合、上記の関数は1を返します.返される値が0以外の値は、指定されたworkを表します.struct構造はすでに待機キューにあり、再参加できません.ワークキューの使用が終了したら、リソース使用を解放します:void destroy_workqueue(struct workqueue_struct *queue);共有キュー
多くの場合、デバイスドライバは独自のワークキューを必要としません.たまにキューにタスクをコミットする必要がある場合は、カーネルが提供する共有のデフォルトのワークキューを使用するより簡単で効率的な方法があります.しかし、使用するときは、他の人と作業キューを共有しているので、長期的にこのキューを占有するべきではありません.つまり、長時間休眠することはできません.また、プロセッサを取得するには、より長い時間がかかる場合があります.作業を追加する方法は、int schedule_work(struct work_struct *work);の遅延バージョン:int schedule_delayed_work(struct work_struct *work, unsigned long delay);簡単な文字デバイスコードを作成した上で、テストとして共有キューを追加します.ioctlによるジョブの追加schedule_のトリガーwork.サンプルコードは次のとおりです.
static struct work_struct work;

static void notification_work(struct work_struct *work)
{
	pr_info("%s
"
, __func__); } static long csdn_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) { /* ohters code */ switch (cmd) { case CSDN_IOC_GET: pr_info("CSDN_IOC_GET
"
); schedule_work(&work); break; /* ohters code */ } /* ohters code */ } static __init int csdn_init(void) { /* ohters code */ INIT_WORK(&work, notification_work); /* ohters code */ }

印刷結果は以下の通りです:[6164.910398]csdn_ioctl [ 6164.910399] CSDN_IOC_GET [ 6164.920519] notification_work