-
Notifications
You must be signed in to change notification settings - Fork 30.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
http2: minor C++ cleanups #16461
http2: minor C++ cleanups #16461
Changes from all commits
aeed4a1
41aaacb
0c90c9c
3ddd151
c8a00fd
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -193,7 +193,8 @@ inline ssize_t Nghttp2Session::OnStreamReadFD(nghttp2_session* session, | |
uv_fs_t read_req; | ||
|
||
if (length > 0) { | ||
numchars = uv_fs_read(handle->loop_, | ||
// TODO(addaleax): Never use synchronous I/O on the main thread. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. re: the todo.... just keep in mind that nghttp2 requires that the data be provided synchronously here... There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hm – from the nghttp2 header:
It even comes with instructions, so that sounds like it’s definitely supported? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. yes and no. I was being a bit simplistic.
This can be further complicated using the NO_COPY flag, which causes another callback to be called telling our code to send our buffers without the need to memcpy, but there are some complications with that also. So, yes, it's certainly possible, and likely desirable, just non-trivial. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. A bit more background... nghttp2 calls this method while it is attempting to serialize a DATA frame for transmission. Calls to this method are synchronous when ng's send or send_mem function is called. Essentially, nghttp2 goes through it's queue of pending frames and serializes each. When it comes to this method, it will synchronously call it over and over until it receives either a DEFER, an error, or an EOF response. If it receives a DEFER, it takes that stream temporarily out of it's send queue. Calling session_resume_data inserts it back into the queue, so that the next time send or mem_send is called, serialization of the DATA frame can be attempted again. |
||
numchars = uv_fs_read(handle->event_loop(), | ||
&read_req, | ||
fd, &data, 1, | ||
offset, nullptr); | ||
|
@@ -541,11 +542,9 @@ inline void Nghttp2Session::SendPendingData() { | |
// Initialize the Nghttp2Session handle by creating and | ||
// assigning the Nghttp2Session instance and associated | ||
// uv_loop_t. | ||
inline int Nghttp2Session::Init(uv_loop_t* loop, | ||
const nghttp2_session_type type, | ||
nghttp2_option* options, | ||
nghttp2_mem* mem) { | ||
loop_ = loop; | ||
inline int Nghttp2Session::Init(const nghttp2_session_type type, | ||
nghttp2_option* options, | ||
nghttp2_mem* mem) { | ||
session_type_ = type; | ||
DEBUG_HTTP2("Nghttp2Session %s: initializing session\n", TypeName()); | ||
destroying_ = false; | ||
|
@@ -581,41 +580,25 @@ inline int Nghttp2Session::Init(uv_loop_t* loop, | |
nghttp2_option_del(opts); | ||
} | ||
|
||
// For every node::Http2Session instance, there is a uv_prep_t handle | ||
// whose callback is triggered on every tick of the event loop. When | ||
// run, nghttp2 is prompted to send any queued data it may have stored. | ||
uv_prepare_init(loop_, &prep_); | ||
uv_prepare_start(&prep_, [](uv_prepare_t* t) { | ||
Nghttp2Session* session = ContainerOf(&Nghttp2Session::prep_, t); | ||
session->SendPendingData(); | ||
}); | ||
return ret; | ||
} | ||
|
||
inline void Nghttp2Session::MarkDestroying() { | ||
destroying_ = true; | ||
} | ||
|
||
inline int Nghttp2Session::Free() { | ||
#if defined(DEBUG) && DEBUG | ||
CHECK(session_ != nullptr); | ||
#endif | ||
inline Nghttp2Session::~Nghttp2Session() { | ||
Close(); | ||
} | ||
|
||
inline void Nghttp2Session::Close() { | ||
if (IsClosed()) | ||
return; | ||
DEBUG_HTTP2("Nghttp2Session %s: freeing session\n", TypeName()); | ||
// Stop the loop | ||
CHECK_EQ(uv_prepare_stop(&prep_), 0); | ||
auto PrepClose = [](uv_handle_t* handle) { | ||
Nghttp2Session* session = | ||
ContainerOf(&Nghttp2Session::prep_, | ||
reinterpret_cast<uv_prepare_t*>(handle)); | ||
session->OnFreeSession(); | ||
}; | ||
uv_close(reinterpret_cast<uv_handle_t*>(&prep_), PrepClose); | ||
nghttp2_session_terminate_session(session_, NGHTTP2_NO_ERROR); | ||
nghttp2_session_del(session_); | ||
session_ = nullptr; | ||
loop_ = nullptr; | ||
DEBUG_HTTP2("Nghttp2Session %s: session freed\n", TypeName()); | ||
return 1; | ||
} | ||
|
||
// Write data received from the socket to the underlying nghttp2_session. | ||
|
@@ -813,7 +796,6 @@ inline int Nghttp2Stream::SubmitFile(int fd, | |
DEBUG_HTTP2("Nghttp2Stream %d: submitting file\n", id_); | ||
getTrailers_ = options & STREAM_OPTION_GET_TRAILERS; | ||
nghttp2_data_provider prov; | ||
prov.source.ptr = this; | ||
prov.source.fd = fd; | ||
prov.read_callback = Nghttp2Session::OnStreamReadFD; | ||
|
||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
btw, definitely not for this PR, but down the road... I plan to refactor this so that there is one uv_prepare_t for N session instances, and loop through each on every uv_prepare_t tick... rather than registering one uv_prepare_t for each session. Will need to benchmark that tho...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍 – I can leave a
TODO
if you want.I’ve also wondered if it might worth hopping onto the same underlying mechanism that
setImmediate
uses…There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nah, don't need a todo.
I've considered that also but haven't looked into it yet.