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). 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.

Many functions also have variables (often named result or rv) containing such a value; this is especially common in the 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:

DoLoop #

The DoLoop pattern is used in the network stack to construct simple state machines. It is used for cases in which processing is basically single-threaded and could be written in a single function, if that function could block waiting for input. Generally, initiation of a state machine is triggered by some method invocation by a class consumer, and that state machine is driven (possibly across asynchronous IO initiated by the class) until the operation requested by the method invocation completes, at which point the state variable is set to STATE_NONE and the consumer notified.

Cases which do not fit into this single-threaded, single consumer operation model are generally adapted in some way to fit the model, either by multiple state machines (e.g. independent state machines for reading and writing, if each can be initiated while the other is outstanding) or by storing information across consumer invocations and returns that can be used to restart the state machine in the proper state.

Any class using this pattern will contain an enum listing all states of that machine, and define a function, DoLoop(), to drive that state machine. If a class has multiple state machines (as above) it will have multiple methods (e.g. DoReadLoop() and DoWriteLoop()) to drive those different machines.

The characteristics of the DoLoop pattern are:

Public class methods generally have very little processing, primarily wrapping DoLoop(). For DoLoop() entry this involves setting the next_state_ variable, and possibly making copies of arguments into class members. For DoLoop() exit, it involves inspecting the return and passing it back to the caller, and in the asynchronous case, saving any passed completion callback for executing by a future subsidiary IO completion (see above example).

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.

For examples of this idiom, see