Skip to content

Instantly share code, notes, and snippets.

@tawashichan
Last active December 17, 2019 19:34
Show Gist options
  • Save tawashichan/2ed3fe19d77b552647691a1f8a82a458 to your computer and use it in GitHub Desktop.
Save tawashichan/2ed3fe19d77b552647691a1f8a82a458 to your computer and use it in GitHub Desktop.
  • net tcplistner
    • bindすると
      • mioListnerを初期化する
      • Wacher::newが実行される。
        • mioのEventを監視するReactorが起動する。
          • Reactor::registerで、watcher::new経由で渡ってきたmioListenerを監視対象に登録している。
          • Reactorが起動すると別スレッドを起動してmain_loopに入る。
            • main_loop内部でpoller::pollを実行し、監視対象からEventが来ていないかを監視。
              • eventが来たらentriesからeventと紐づいたentryを取得し、eventの種類(読み込み、書き込み)に応じて対応するwakerをentryから取得、wakeを実行(この部分理解が曖昧)
    • incoming.nextすると
      • NextFutureが帰って来て、こいつをawaitすると、Incoming::poll_nextが実行される
        • NextFutureのpropertyにstreamとしてIncomingが入っているため。
        • Incoming::poll_next内部でTcpListener::acceptが実行される。
          • TcpListener::accept内部でWatcher::poll_read_withが実行される。
            • 引数の関数として、TcpListener::accept_stdが呼ばれるclosureが渡されている。
              • closureを実行し、streamを返せるか確認。
                • 返せるようであればPoll::Ready(res)を返す。これはResult<TcpStream,io::Error>である。
                • Blockするよエラー以外は一番上の階層まで伝播していき、mainがResult::Errを返す。
            • ここで、entryにwakerが登録されていなかったらwakerを登録する(この部分理解が曖昧)。
            • Readyを返せる状態でなければ最後にPendingを返し、Reactorのthreadがwaker::wakeするのを待つ。
  • block_onすると
    • 引数として渡したFutureがrunをするclosureに包まれてTask::set_currentに渡される。
      • set_curretでは、現在実行中のtaskに対して割り込みして、指定したtaskを実行するようにする。
        • CURRENTという現在実行中のtaskを格納するthread_local変数の中身を指定したtaskのものにして、taskが実行し終わった後で元々入っていたtaskに置き換える。
      • runでは、引数としてわたされたfutureのpollを行う。
        • arc_parkerをcontext経由で共有する。waker::wakeで呼ばれるのはarc_parker.unparkである。
        • Poll::Pendingが帰って来たらarc_parker.parkを実行し休止状態に入る(waker::wakeが実行されると再びpollする)
  • spawnすると
    • 引数として渡したFutureがasync_task::spawnに渡される。
      • async_task::spawnはscheculeclosureを受け取り、task.scheduleを実行するとschedule closureが実行される。
        • schedule closure内部ではexecutor::scheduleが実行される。
          • executor::scheduleでは、現在のthreadがworkerかどうか(wokerでない場合main thread扱い)で分岐する
            • worker threadの場合、workerのtask queue(Wokerという名前。ややこしい)にtaskを積む。
            • main threadの場合、POOLのqueueに積む。(POOLはlazyに包まれているため、初めてspawnした場合ここでPOOLが起動し、worker threadが起動する。)
          • 最後にPOOLのsleeperというcondvarのnotify_oneを実行。休止状態のworkerを一つ起こす。
      • task.scheduleを実行。
      • POOLが起動した後
        • cpuの数だけthreadが起動し、thread内部でProcessorを起動する。(workerのtaskを管理する変数)
          • worker threadはmain_loopを実行。
            • main_loop内部ではwork_stealing方式で実行可能なtaskを探索。
              • taskがあればそのままtasl.runを実行。
                • set_currentでtask.runを実行。task.runではtaskに紐づくfutureをpollする(ここの挙動がよくわかっていない)
                  • Pendingだとすぐrescheduleしているように見えるが...(実験したところそのような挙動はしない)
                  • wakerを使っているのかよくわからん...
              • ない場合、POOL.sleepersというcondvarをwaitし、休止状態に入る
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment