Node.jsの処理フロー
Node.jsでは、「libev」と「libeio」を組み合わせて使用しています。
下記のようなファイル読み込み処理を実行すると以下のような処理フローになります。
var path = require('path'), fs = require('fs'), filepath = path.join(__dirname, 'a.txt'), fd = fs.openSync(filepath, 'r'); fs.read(fd, 1024, 0, 'utf-8', function(err, str, bytesRead) { console.log(str); });
0. Node.js起動時にeio_init()でnode::EIOWantPoll()をlibeioに登録する。 libeioは、pollして欲しいタイミングになると、 node::EIOWantPoll()を呼び出すようになる。 1. node_file.ccのRead()が実行される。 2. libeioのeio_submit()が実行され、req_queueに格納される。 req_queueには、eio_req構造体が保存される。eio_read()の場合、 {TYPE=EIO_READ, FINISH=After(), DATA->cb=callback()}が設定される。 After()は、node_file.ccの関数で、 libeioでeio_poll()が呼びだされた際にmainスレッド(イベントループ)で実行される。 After()の中で、DATA->cbに設定されたcallback()が呼ばれる。 callback()には、javascriptのfs.read()の最後のパラメータとして 設定された関数が設定される。今回の場合は、 function(err, str, bytesRead) { console.log(str); } 3. EIOスレッドで、eio_execute()が実行され、read(2)が実行される。 5. read(2)の結果を、req->resultに設定し、res_queueに格納する。 6. EIOスレッドで、want_poll()が呼び出される。 7. 先程、eio_init()で設定した、node::EIOWantPoll()が呼び出され、 ev_async_send()により、イベントループへ通知される。 8. イベントループで、node::WantPollNotifier()が呼ばれ、eio_poll()が実行される。 9. イベントループで先程のAfter()が実行され、req->resultの結果が読み出される。 10. 最後にcallback()が実行される。