タイマーイベントを扱うことで、ある処理の中で時間経過を待ったり、イベント通知関数を使用することで時間経過後に非同期に処理を行わせたりすることができます。
この章ではそれぞれのやり方を紹介します。
EFI_BOOT_SERVICESのCreateEvent()とSetTimer()とWaitForEvent()で時間経過を待つことができます(リスト4.1)。なお、WaitForEvent()は前著(パート1)で紹介したので説明は省略します。
サンプルのディレクトリは"040_evt_timer_blocking"です。
[*1] "tick"とはシステムで扱う時間の単位で、語源は時計の"チクタク"。例えば1ms毎のタイマー割り込みで時間を管理しているシステムならtickは1ms。UEFIの場合どうなのかはまだ分かってないです。ごめんなさい。
使用例はリスト4.2の通りです。
1: #include "efi.h" 2: #include "common.h" 3: 4: void efi_main(void *ImageHandle __attribute__ ((unused)), 5: struct EFI_SYSTEM_TABLE *SystemTable) 6: { 7: unsigned long long status; 8: void *tevent; 9: void *wait_list[1]; 10: unsigned long long idx; 11: 12: efi_init(SystemTable); 13: ST->ConOut->ClearScreen(ST->ConOut); 14: 15: /* タイマーイベントを作成し、teventへ格納 */ 16: status = ST->BootServices->CreateEvent(EVT_TIMER, 0, NULL, NULL, 17: &tevent); 18: assert(status, L"CreateEvent"); 19: 20: /* WaitForEvent()へ渡す為にイベントリストを作成 */ 21: wait_list[0] = tevent; 22: 23: while (TRUE) { 24: /* teventへ1秒のトリガー時間を設定 */ 25: status = ST->BootServices->SetTimer(tevent, TimerRelative, 26: 10000000); 27: assert(status, L"SetTimer"); 28: 29: /* イベント発生を待つ */ 30: status = ST->BootServices->WaitForEvent(1, wait_list, &idx); 31: assert(status, L"WaitForEvent"); 32: 33: /* 画面へ"wait."を出力 */ 34: puts(L"wait."); 35: } 36: }
リスト4.2では、SetTimer()でトリガー時間を設定し、WaitForEvent()でイベント発生を待つ事で、1秒毎に"wait."が画面出力されます。
実行例は図4.1の通りです。
CreateEvent()では、イベント発生時に指定した関数を呼び出すように設定できます。
サンプルのディレクトリは"041_evt_timer_nonblocking"です。
前節のCreateEvent()定義の説明箇所のみを再掲しますリスト4.3。
使用例をリスト4.4に示します。
1: #include "efi.h" 2: #include "common.h" 3: 4: void timer_callback(void *event __attribute__ ((unused)), 5: void *context __attribute__ ((unused))) 6: { 7: puts(L"wait."); 8: } 9: 10: void efi_main(void *ImageHandle __attribute__ ((unused)), 11: struct EFI_SYSTEM_TABLE *SystemTable) 12: { 13: unsigned long long status; 14: void *tevent; 15: 16: efi_init(SystemTable); 17: ST->ConOut->ClearScreen(ST->ConOut); 18: 19: /* タイマーイベントを作成し、teventへ格納 */ 20: status = ST->BootServices->CreateEvent(EVT_TIMER | EVT_NOTIFY_SIGNAL, 21: TPL_CALLBACK, timer_callback, 22: NULL, &tevent); 23: assert(status, L"CreateEvent"); 24: 25: /* teventへ1秒の周期トリガー時間を設定 */ 26: status = ST->BootServices->SetTimer(tevent, TimerPeriodic, 27: 10000000); 28: assert(status, L"SetTimer"); 29: 30: while (TRUE); 31: }
リスト4.4では、SetTimer()へ周期タイマー(TimerPeriodic)を設定してみました。1秒周期でtimer_callback()が呼び出されます。
実行例は図4.2の通りです。