Skip to content

Instantly share code, notes, and snippets.

@trevnorris
Last active July 27, 2024 09:30
Show Gist options
  • Save trevnorris/1f3066ccb0fed9037afa to your computer and use it in GitHub Desktop.
Save trevnorris/1f3066ccb0fed9037afa to your computer and use it in GitHub Desktop.
rough notes on the linux side of the libuv event loop
uv_run
- uv__update_time(): Update time with millisecond precision.
- uv__run_timers(): Loop through "heap" and run timers whose timeout > time.
- uv__run_pending(): Run all callbacks on the pending_queue. Remove each item
from the queue when run.
Note: uv__io_feed() is the only function to insert onto pending_queue.
Note: The following use uv__io_feed():
- uv_pipe_connect(), but only in the case of an error.
- uv__write_req_finish(), part of stream.c
- uv_tcp_connect(), but only in the case of an error.
- uv__udp_send_msg(), for all sent messages.
- uv__run_idle(): Generated by loop-watcher.c. Run all callbacks on the queue
of idle_handles. The queue is not cleared by running the handles. If there
are idle_handles then the timeout for uv__io_poll is set to 0. Meaning the
event loop will immediately proceed.
Notes: This queue is used by the uv_idle_{init,start,stop} API.
- uv__run_prepare(): Generated by loop-watcher.c. Run all callbacks on the
queue of prepare_handles. The queue is not cleared by running the handles.
Notes: This queue is used by the uv_prepare_{init,start,stop} API.
- Calculate timeout time for epoll_wait().
- uv__io_poll(..., timeout): Pass the timeout so if no poll events occur the
event loop will proceed so timers will run.
- Loop through `watcher_queue` (queue of all fd's that have an event that
need to be listened for, which is `pevents` [pending events]) and add the
associated event to the fd.
- Run epoll_wait with calculated timeout.
- If events occurred run attached callbacks and pass the event.
- Once timeout runs out return.
- uv__run_check(): Generated by loop-watcher.c. Run all callbacks on the queue
of check_handles. The queue is not cleared by running the handles.
Notes: This queue is only used by the uv_check_{init,start,stop} API.
- uv__run_closing_handles():
* Note: while the handle is in the UV_CLOSING state now, it's still possible
for it to be active in the sense that uv__is_active() returns true. A good
example is when the user calls uv_shutdown(), immediately followed by
uv_close(). The handle is considered active at this point because the
completion of the shutdown req is still pending.
- Go through the linked list of handles marked for closing and run
uv__finish_close().
- For UV_NAMED_PIPE, UV_TCP and UV_TTY run uv__stream_destroy() on the
handle.
- If there's connect_req (uv_connect_t) then unregister it on the event
loop the given stream is attached to using uv__req_unregister(), then
run the connect_req->cb() (uv_connect_cb) passing UV_ECANCELED.
- For every write request in write_queue (void*[2]) set error to
UV_ECANCELED.
- Pass stream to uv__write_callbacks().
- Loop through the linked list of write requests and unregister each
uv_write_t with uv__req_unregister() (meaning, remove it from the
write queue).
- Update the write_queue_size with uv__write_req_size(), which does a
linear scan of all bufs in the write req using uv__count_bufs() and
free the request data.
(Note the comment on uv__write_req_finish() about why it currently
works this way)
- Run req->cb (uv_write_cb) passing the request and error.
- If there's a shutdown_req (uv_shutdown_t) then unregister the req and
call the uv_shutdown_cb() with UV_ECANCELED.
- For UV_UDP run uv__udp_finish_close() on the handle.
- Set status to UV_ECANCELED.
- Run uv__udp_run_completed() passing the handle.
- Unregister each uv_udp_send_t in the write_completed_queue.
- Call the send_cb() (uv_udp_send_cb) passing the status.
- If write_queue is empty stop the watcher by running uv__io_stop()
- (TODO: look into "events", "pevents", basically everything in
uv__io_stop())
- Run uv__handle_unref() on all handles.
- If the handle is not active (!UV__HANDLE_ACTIVE) then decrement the
active_handles count on the loop.
- Remove handle from the handle_queue (void*[2] in UV_HANDLE_FIELDS)
- If has close_cb(), run and pass the closed handle.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment