uv_loop_t — イベントループ

イベントループは、libuvの機能の中心となる部分です。入出力のポーリングと、さまざまな発生源からのイベントに応じたコールバックの実行スケジューリングを担当します。

データ型

type uv_loop_t

イベントループのデータ型。

enum uv_loop_option

追加のイベントループオプション。uv_loop_configure()を参照してください。

typedef enum {
    UV_LOOP_BLOCK_SIGNAL = 0,
    UV_METRICS_IDLE_TIME,
    UV_LOOP_USE_IO_URING_SQPOLL
} uv_loop_option;
enum uv_run_mode

uv_run()でイベントループを実行する際のモード。

typedef enum {
    UV_RUN_DEFAULT = 0,
    UV_RUN_ONCE,
    UV_RUN_NOWAIT
} uv_run_mode;
typedef void (*uv_walk_cb)(uv_handle_t *handle, void *arg)

uv_walk()に渡すコールバックの型定義です。

公開メンバー

void *uv_loop_t.data

利用者が定義する任意のデータのための領域です。libuvはこのフィールドを使わず、変更もしません。

API

int uv_loop_init(uv_loop_t *loop)

指定されたuv_loop_t構造体を初期化します。

int uv_loop_configure(uv_loop_t *loop, uv_loop_option option, ...)

バージョン1.0.2で追加。

追加のイベントループオプションを設定します。特に記載がなければ、通常はuv_run()を初めて呼び出す前に、この関数を呼び出すべきです。

成功した場合は0、失敗した場合はUV_E*のエラーコードを返します。UV_ENOSYSへの対応も用意してください。これは、そのプラットフォームでイベントループオプションがサポートされていないことを意味します。

サポートされるオプション:

  • UV_LOOP_BLOCK_SIGNAL: 新しいイベントをポーリングするときにシグナルをブロックします。uv_loop_configure()の第2引数はシグナル番号です。

    この操作は、サンプリングプロファイラーを使うときの不要な復帰を抑えるため、現時点ではSIGPROFシグナルに対してのみ実装されています。他のシグナルを要求すると、UV_EINVALで失敗します。

  • UV_METRICS_IDLE_TIME: イベントループがイベントプロバイダー内で費やすアイドル時間を積算します。

    このオプションはuv_metrics_idle_time()を使うために必要です。

  • UV_LOOP_USE_IO_URING_SQPOLL: 非同期ファイルシステム操作を処理するために、SQPOLLを使うio_uringインスタンスを有効にします。

バージョン1.39.0で変更: UV_METRICS_IDLE_TIMEオプションを追加。

バージョン1.49.0で変更: UV_LOOP_USE_IO_URING_SQPOLLオプションを追加。

int uv_loop_close(uv_loop_t *loop)

イベントループ内部のリソースをすべて解放します。イベントループの実行が終了し、開いているハンドルとリクエストをすべて閉じた後にのみ、この関数を呼び出してください。それ以外の場合はUV_EBUSYを返します。この関数が戻った後、利用者はイベントループに割り当てたメモリを解放できます。

uv_loop_t *uv_default_loop(void)

初期化済みの既定のイベントループを返します。メモリ割り当てに失敗した場合は、NULLを返すことがあります。

この関数は、アプリケーション全体で使うグローバルなイベントループを用意するための便利な手段にすぎません。既定のイベントループは、uv_loop_init()で初期化したイベントループと何も違いません。そのため、既定のイベントループもuv_loop_close()で閉じることができ、関連するリソースを解放するために閉じるべきです。

警告

この関数はスレッドセーフではありません。

int uv_run(uv_loop_t *loop, uv_run_mode mode)

この関数はイベントループを実行します。指定したモードによって動作が異なります:

  • UV_RUN_DEFAULT: アクティブで参照されているハンドルやリクエストがなくなるまで、イベントループを実行します。uv_stop()が呼び出され、アクティブなハンドルやリクエストがまだ残っている場合は、0以外を返します。それ以外の場合はすべて0を返します。

  • UV_RUN_ONCE: 入出力を1回ポーリングします。保留中のコールバックがなければ、この関数はブロックすることに注意してください。処理が完了した場合(アクティブなハンドルやリクエストが残っていない場合)は0を返し、今後もコールバックが見込まれる場合は0以外を返します(後でイベントループを再び実行すべきことを意味します)。

  • UV_RUN_NOWAIT: 入出力を1回ポーリングしますが、保留中のコールバックがなくてもブロックしません。処理が完了した場合(アクティブなハンドルやリクエストが残っていない場合)は0を返し、今後もコールバックが見込まれる場合は0以外を返します(後でイベントループを再び実行すべきことを意味します)。

uv_run()は再入可能ではありません。コールバック内から呼び出してはいけません。

int uv_loop_alive(const uv_loop_t *loop)

イベントループに、参照されているアクティブなハンドル、アクティブなリクエスト、または終了処理中のハンドルがある場合は、0以外を返します。

void uv_stop(uv_loop_t *loop)

イベントループを停止し、uv_run()ができるだけ早く終了するようにします。ただし、終了するのは早くても次のイベントループの反復です。この関数を入出力待ちでブロックする前に呼び出した場合、その反復ではイベントループは入出力待ちでブロックしません。

size_t uv_loop_size(void)

uv_loop_t構造体のサイズを返します。構造体のレイアウトを把握せずに済ませたいFFIバインディングの作成者に役立ちます。

int uv_backend_fd(const uv_loop_t *loop)

バックエンドのファイル記述子を取得します。サポートされるのは、kqueue、epoll、event portsのみです。

この関数をuv_run(loop, UV_RUN_NOWAIT)と組み合わせると、あるスレッドでポーリングし、別のスレッドでイベントループのコールバックを実行できます。例はtest/test-embed.cを参照してください。

注記

kqueueのファイル記述子を別のkqueueのポーリング集合に組み込む方法は、すべてのプラットフォームで動作するわけではありません。ファイル記述子の追加はエラーにはなりませんが、イベントは一切発生しません。

int uv_backend_timeout(const uv_loop_t *loop)

ポーリングのタイムアウトを取得します。戻り値の単位はミリ秒で、タイムアウトがない場合は-1です。

uint64_t uv_now(const uv_loop_t *loop)

現在のタイムスタンプをミリ秒で返します。このタイムスタンプは、イベントループのティックの開始時にキャッシュされます。詳しい説明と理由についてはuv_update_time()を参照してください。

タイムスタンプは、任意の時点を起点として単調に増加します。起点について何かを仮定してはいけません。そのような仮定は期待どおりにはなりません。

注記

ミリ秒より細かい精度が必要な場合はuv_hrtime()を使ってください。

void uv_update_time(uv_loop_t *loop)

イベントループが認識する「現在時刻」を更新します。libuvは、時刻に関するシステムコールの回数を減らすため、イベントループのティックの開始時に現在時刻をキャッシュします。

通常、イベントループを長時間ブロックするコールバックがない限り、この関数を呼び出す必要はありません。ここでの「長時間」は多少主観的ですが、おそらく1ミリ秒以上の程度を指します。

void uv_walk(uv_loop_t *loop, uv_walk_cb walk_cb, void *arg)

ハンドルの一覧を走査し、walk_cbに指定されたargを渡して実行します。

int uv_loop_fork(uv_loop_t *loop)

バージョン1.12.0で追加。

fork(2)システムコールの後、子プロセスで必要になるカーネルの状態を再初期化します。

既に開始されていた監視処理は、子プロセスでも開始された状態のまま継続します。

親プロセスで作成し、子プロセスで引き続き使う予定のイベントループすべてに対して、既定のイベントループも含め、この関数を明示的に呼び出す必要があります(親プロセスで使い続けない場合も同様です)。子プロセスでは、uv_run()や、そのイベントループを使う他のAPI関数を呼び出す前に、必ずこの関数を呼び出してください。そうしないと動作が未定義となり、親と子の両方へのイベントの重複配信や、子プロセスの異常終了が起きる可能性があります。

可能であれば、親プロセスで作成したイベントループを再利用するよりも、子プロセスで新しいイベントループを作成することが望まれます。forkの後に子プロセスで新しく作成したイベントループには、この関数を使うべきではありません。

この関数はWindowsでは実装されておらず、UV_ENOSYSを返します。

注意

この関数は実験的なものです。不具合を含む可能性があり、変更または削除されることもあります。APIとABIの安定性は保証されません。

注記

Mac OS Xでは、親プロセスのいずれかのイベントループでディレクトリのFSイベントハンドルを使っていた場合、子プロセスでは最も効率的なFSEvent実装を使えなくなります。代わりに、子プロセスでのディレクトリのFSイベントハンドルは、ファイルの場合や他のkqueueベースのシステムで使われるものと同じ実装にフォールバックします。

注意

AIXとSunOSでは、fork時に親プロセスで既に開始されていたFSイベントハンドルは、子プロセスにイベントを配信しません。これらのハンドルを閉じてから、再び開始する必要があります。他のすべてのプラットフォームでは、追加の操作をしなくても通常どおり動作し続けます。

注意

以前にuv_backend_fd()が返した値は、すべて無効になります。正しいバックエンドのファイル記述子を取得するには、その関数を再び呼び出す必要があります。

void *uv_loop_get_data(const uv_loop_t *loop)

戻り値はloop->dataです。

バージョン1.19.0で追加。

void uv_loop_set_data(uv_loop_t *loop, void *data)

loop->dataをdataに設定します。

バージョン1.19.0で追加。