Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(187)

Unified Diff: net/docs/code-patterns.md

Issue 1320933003: Writeup summary of common netstack coding patterns. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Incorporated many comments. Created 5 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « no previous file | net/net.gypi » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: net/docs/code-patterns.md
diff --git a/net/docs/code-patterns.md b/net/docs/code-patterns.md
new file mode 100644
index 0000000000000000000000000000000000000000..51c54a84f7496453acba5c83518cdada08896a57
--- /dev/null
+++ b/net/docs/code-patterns.md
@@ -0,0 +1,138 @@
+# Chrome Network Stack Common Coding Patterns
+
+## Combined error and byte count into a single value
+
+At many places in the network stack, functions return a value that, if
+positive, indicate a count of bytes that the the function read or
+wrote, and if negative, indicates a network stack error code (see
+[net_error_list.h](https://chromium.googlesource.com/chromium/src/+/master/net/base/net_error_list.h#1)).
+Zero indicates either net::OK or zero bytes read (usually EOF)
+depending on the context. This pattern is generally specified by
+an |int| return type.
+
Ryan Sleevi 2015/08/31 22:17:43 Worth discussing the net::CompletionCallback that
Randy Smith (Not in Mondays) 2015/09/02 02:32:28 I detest net::CompletionCallback and consider it a
Ryan Sleevi 2015/09/02 19:14:56 Maybe, but I'm happy to save that discussion for a
+Many functions also have variables (often named |result|) containing
+such value; this is especially common in the [DoLoop](#DoLoop) pattern
+described below.
+
+## Sync/Async Return
+
+Many network stack routines may return synchronously or
+asynchronously. These functions generally return an int as described
+above. There are three cases:
+
+* If the value is positive or zero, that indicates a synchronous
+ successful return, with a zero return value possibly indicating zero
+ bytes/EOF and possibly indicating net::OK, depending on context.
+* If the value is negative and != net::ERR_IO_PENDING, it is an error
+ code specifying a synchronous failing return.
+* If the return value is the special value net::ERR_IO_PENDING, it
+ indicates that the routine will complete asynchronously. An IOBuffer
+ provided will be retained by the called entity until completion, to
+ be written into or read from as required. Other buffers must be kept
Ryan Sleevi 2015/08/31 22:17:43 s/buffers/pointers/ (or objects)
Randy Smith (Not in Mondays) 2015/09/02 02:32:29 Done.
+ alive manually until asynchronous completion is signaled.
+ If a callback was provided, that callback will be called upon
+ completion with the return value; if a callback is not provided, it
+ usually means that some known callback mechanism will be employed.
+
+## DoLoop
+
+The pattern usually used to construct state machines in the Chrome
+network stack is the DoLoop function. Any class that must drive a
+state machine will contain an enum listing all states of that machine,
+and define a function, |DoLoop|, to drive that state
+machine. Sometimes a single class may have multiple state machines,
+driven by multiple methods (e.g. DoFooLoop and DoBarLoop), and
+sometimes a larger state machine may be broken into smaller state
+machines, e.g. |DoHandshakeLoop|.
+
+The characteristics of the DoLoop pattern are:
+
+* Each state has a corresponding function which is called by DoLoop
Ryan Sleevi 2015/08/31 22:17:43 STYLE PEDANTRY: Google style is three spaces, not
Randy Smith (Not in Mondays) 2015/09/02 02:32:28 Huh. The markdown documentation that I found said
+ for handling when the state machine is in that state. Generally the
+ states are named STATE_<state name> (upper case separated by
+ underscores), and the routine is named Do<StateName> (CamelCase).
+ Those functions both take and return values that are either
+ net::Errors or the above combined error and byte count value.
+* There are often pairs of related states, such as STATE_SEND_HEADERS
+ and STATE_SEND_HEADERS_COMPLETE. The routine associated with the
Ryan Sleevi 2015/08/31 22:17:43 pedantry: You introduced another double space :P [
Randy Smith (Not in Mondays) 2015/09/02 02:32:29 I *did* warn you :-}. Done.
+ second state handles completion processing (e.g. success vs. error)
+ and determining the next state to transition to (e.g. back to
+ STATE_SEND_HEADERS if the headers haven't actually all been sent).
Ryan Sleevi 2015/08/31 22:17:43 I would suggest rewording this; we don't do FOO/FO
Randy Smith (Not in Mondays) 2015/09/02 02:32:28 SGTM; this is exactly the kind of thing I'm relyin
+* Each state handling function has two basic responsibilities in
+ addition to state specific handling: Setting the data member
+ (named |next_state_| or something similar)
+ to specify the next state, and returning a net::Error (or combined
+ error and byte count, as above).
+* DoLoop loops, saving next_state_ to a local variable and resetting
+ it to STATE_NONE, and then calling the appropriate state handling
+ based the original value of next_state_.
Ryan Sleevi 2015/08/31 22:17:43 Suggestion: Add a sentence explaining why * On
Randy Smith (Not in Mondays) 2015/09/02 02:32:28 Thanks for the explanation; done.
+* If the return value from the state handling function is
+ net::ERR_IO_PENDING, that indicates that the function has arranged
+ for DoLoop() to be called at some point in the future, when further
+ progress can be made on the state transitions. The next_state_ variable
+ will have been set to the value proper for handling that incoming
+ call. In this case, DoLoop() will exit.
+* A class state machine is generally invoked in response to a consumer
+ calling one of its methods. While the operation that method
+ requested is occuring, the state machine stays actively, possibly
+ over multiple asynchronous operations and state transitions. When
+ that operation is complete, the state machine transitions to
+ STATE_NONE (by a DoLoop callee not setting next_state_) or
+ STATE_DONE (by explicitly setting next_state_ to STATE_DONE
+ indicating that the operation is complete *and* the state machine is
+ not amenable to further driving). At this point the consumer is
+ notified of the completion of the operation (by synchronous return
+ or asynchronous callback).
+
+ Note that this implies that when DoLoop() returns, one of two
+ things will be true:
+
+ * The return value will be net::ERR_IO_PENDING, indicating that the
+ caller should take no action and instead wait for asynchronous
+ notification.
+ * The state of the machine will be either STATE_DONE or STATE_NONE,
+ indicating that the operation that first initiated the DoLoop() has
+ completed.
+
+* DoLoop is called from two places: a) methods exposed to the consumer
+ for specific operations (e.g. |ReadHeaders|), and b) IO completion
+ callbacks called asynchronously by spawned IO operations.
+
+ In the first case, the return value from DoLoop is returned directly
+ to the caller; if the operation completed synchronously, that will
+ contain the operation result, and if it completed asynchronously, it
+ will be net::ERR_IO_PENDING.
+
+ In the second case, the IO completion callback will examine the
+ return value from DoLoop(). If it is net::ERR_IO_PENDING, no
+ further action will be taken, and the IO completion callback will be
+ called again at some future point. If it is not
+ net::ERR_IO_PENDING, that is a signal that the operation has
+ completed, and the IO completion callback will call the appropriate
+ consumer callback to notify the consumer that the operation has
+ completed. Note that it is important that this callback be done
+ from the IO completion callback and not DoLoop or a DoLoop callee,
+ both to support the sync/async error return (DoLoop and its callees
+ don't konw the difference) and to avoid consumer callbacks deleting
Ryan Sleevi 2015/08/31 22:17:43 typo: know
Randy Smith (Not in Mondays) 2015/09/02 02:32:28 Done.
+ the object out from under DoLoop().
+
+Public class methods should have as little processing as possible,
+often simply making copies of arguments into data members, setting the
+next_state_ variable to indicate the section of the state diagram to
+process, and calling DoLoop().
+
+This idiom allows synchronous and asynchronous logic to be written in
+the same fashion; it's all just state transition handling. For mostly
+linear state diagrams, the handling code can be very easy to
+comprehend, as such code is usually written linearly (in different
+handling functions) in the order it's executed. If there can be
+multiple different events that complete outstanding IO, the framework
+doesn't handle that explicitly; the state handling code for the
+receiving state must explicitly distinguish between those events and
+do the appropriate state transition.
+
+For examples of this idiom, see
+
+* [HttpStreamParser::DoLoop](https://code.google.com/p/chromium/codesearch#chromium/src/net/http/http_stream_parser.cc&q=HttpStreamParser::DoLoop&sq=package:chromium).
+* [HttpNetworkTransaction::DoLoop](https://code.google.com/p/chromium/codesearch#chromium/src/net/http/http_network_transaction.cc&q=HttpNetworkTransaction::DoLoop&sq=package:chromium)
+
« no previous file with comments | « no previous file | net/net.gypi » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698