libuv 0.10から1.0.0への移行ガイド¶
1.0.0の開発過程で、一部のAPIは大きく変わりました。このガイドでは、0.10のリリース後に行われた、特に重要な変更に対応する移行方法を説明します。
ループの初期化と終了¶
libuv 0.10以前では、ループを次の関数で作成していました: uv_loop_new。この関数は新しいループのメモリーを確保して初期化します。ループの破棄には次の関数を使っていました: uv_loop_delete。この関数はループを破棄し、メモリーを解放します。1.0以降、これらの関数は非推奨となり、ユーザーがメモリーを確保してからループを初期化する必要があります。
libuv 0.10
uv_loop_t* loop = uv_loop_new();
...
uv_loop_delete(loop);
libuv 1.0
uv_loop_t* loop = malloc(sizeof *loop);
uv_loop_init(loop);
...
uv_loop_close(loop);
free(loop);
注記
簡潔にするため、エラー処理は省略しています。次の関数の文書を確認してください: uv_loop_init()およびuv_loop_close()。
エラー処理¶
libuv 1.0では、エラー処理を大幅に見直しました。libuv 0.10では、一般に関数の戻り値とstatusパラメーターは成功時に0、失敗時に-1となり、ユーザーは次の関数を使っていました: uv_last_error。この関数で、正の数であるエラーコードを取得する必要がありました。
1.0では、関数の戻り値とstatusパラメーターに実際のエラーコードが入ります。成功時は0、エラー時は負の数です。
libuv 0.10
... assume 'server' is a TCP server which is already listening
r = uv_listen((uv_stream_t*) server, 511, NULL);
if (r == -1) {
uv_err_t err = uv_last_error(uv_default_loop());
/* err.code contains UV_EADDRINUSE */
}
libuv 1.0
... assume 'server' is a TCP server which is already listening
r = uv_listen((uv_stream_t*) server, 511, NULL);
if (r < 0) {
/* r contains UV_EADDRINUSE */
}
スレッドプールの変更¶
libuv 0.10では、Unixはデフォルトで4スレッドのスレッドプールを使い、Windowsは次のAPIを使っていました: QueueUserWorkItem。このAPIはWindows内部のスレッドプールを使い、そのデフォルトはプロセスごとに512スレッドです。
1.0では両者の実装を統一したため、WindowsもUnixと同じ実装を使うようになりました。スレッドプールのサイズは、次の環境変数をエクスポートして設定できます: UV_THREADPOOL_SIZE。次の文書を参照してください: スレッドプールの作業スケジューリング。
メモリー確保コールバックのAPI変更¶
libuv 0.10では、コールバックは、値を設定した次の型の構造体を返す必要がありました: uv_buf_t。値渡しで返します:
uv_buf_t alloc_cb(uv_handle_t* handle, size_t size) {
return uv_buf_init(malloc(size), size);
}
libuv 1.0では、バッファへのポインターがコールバックに渡され、ユーザーがその内容を設定する必要があります:
void alloc_cb(uv_handle_t* handle, size_t size, uv_buf_t* buf) {
buf->base = malloc(size);
buf->len = size;
}
IPv4とIPv6のAPIの統一¶
libuv 1.0では、IPv4とIPv6のAPIを統一しました。従来は次の2つの関数がありました: uv_tcp_bindとuv_tcp_bind6。現在は次の関数だけです: uv_tcp_bind()。
IPv4の関数は、次の構造体を値渡しで受け取っていました: struct sockaddr_in。IPv6の関数が受け取っていた型は、次のとおりです: struct sockaddr_in6。現在は、次の型を受け取ります: struct sockaddr*(ポインターである点に注意してください)。構造体はスタック上に確保できます。
libuv 0.10
struct sockaddr_in addr = uv_ip4_addr("0.0.0.0", 1234);
...
uv_tcp_bind(&server, addr)
libuv 1.0
struct sockaddr_in addr;
uv_ip4_addr("0.0.0.0", 1234, &addr)
...
uv_tcp_bind(&server, (const struct sockaddr*) &addr, 0);
IPv4とIPv6の構造体を作成する関数(uv_ip4_addr()およびuv_ip6_addr())も変わりました。必ず文書を確認してください。
- ..note::
この変更は、IPv4アドレスとIPv6アドレスを区別していたすべての関数に適用されます。
ストリームとUDPのデータ受信コールバックのAPI変更¶
ストリームとUDPのデータ受信コールバックは、現在、次の型のバッファへのポインターを受け取ります: uv_buf_t。構造体を値渡しで受け取る方式ではありません。
libuv 0.10
void on_read(uv_stream_t* handle,
ssize_t nread,
uv_buf_t buf) {
...
}
void recv_cb(uv_udp_t* handle,
ssize_t nread,
uv_buf_t buf,
struct sockaddr* addr,
unsigned flags) {
...
}
libuv 1.0
void on_read(uv_stream_t* handle,
ssize_t nread,
const uv_buf_t* buf) {
...
}
void recv_cb(uv_udp_t* handle,
ssize_t nread,
const uv_buf_t* buf,
const struct sockaddr* addr,
unsigned flags) {
...
}
パイプ経由のハンドル受信のAPI変更¶
libuv 0.10以前では、次の関数を使っていました: uv_read2_start。これはパイプ上のデータ読み取りを開始する関数であり、そのパイプ経由でハンドルを受信する場合もありました。この関数のコールバックは次の形でした:
void on_read(uv_pipe_t* pipe,
ssize_t nread,
uv_buf_t buf,
uv_handle_type pending) {
...
}
libuv 1.0では、uv_read2_startを削除しました。ユーザーは読み取りコールバック内で、次の関数を使い、保留中のハンドルがあるか確認する必要があります: uv_pipe_pending_count()およびuv_pipe_pending_type():
void on_read(uv_stream_t* handle,
ssize_t nread,
const uv_buf_t* buf) {
...
while (uv_pipe_pending_count((uv_pipe_t*) handle) != 0) {
pending = uv_pipe_pending_type((uv_pipe_t*) handle);
...
}
...
}
ハンドルからのファイルディスクリプターの取り出し¶
APIではサポートされていませんでしたが、たとえばTCPハンドルのファイルディスクリプターを取得するため、ユーザーがlibuvの内部にアクセスすることがよくありました。
fd = handle->io_watcher.fd;
現在は、次の関数で正式に公開しています: uv_fileno()。
uv_fs_readdirの改名とAPI変更¶
uv_fs_readdirは、libuv 0.10では、完了時に次のフィールドへ文字列のリストを返していました: req->ptr。1.0では、この関数を次の名前へ変更しました: uv_fs_scandir()。これは実際の実装が次の関数を使っているためです: scandir(3)。
また、文字列のリスト全体を確保する代わりに、ユーザーは次の関数で結果を1件ずつ取得できます: uv_fs_scandir_next()。この関数ではスレッドプールへ処理を往復させる必要がありません。libuvが次の項目のリストを保持しているためです: dents。このリストは、次の関数が返したものです: scandir(3)。