tag:blogger.com,1999:blog-350249582025-03-05T22:54:14.658+11:00Thinking Asynchronously in C++chrishttp://www.blogger.com/profile/09159109667366328919[email protected]Blogger23125tag:blogger.com,1999:blog-35024958.post-62742873606918224592010-04-14T13:30:00.004+10:002010-04-14T13:35:27.508+10:00System error support in C++0x - part 5<p>[ <a href="http://blog.think-async.com/2010/04/system-error-support-in-c0x-part-1.html">part 1</a>, <a href="http://blog.think-async.com/2010/04/system-error-support-in-c0x-part-2.html">part 2</a>, <a href="http://blog.think-async.com/2010/04/system-error-support-in-c0x-part-3.html">part 3</a>, <a href="http://blog.think-async.com/2010/04/system-error-support-in-c0x-part-4.html">part 4</a> ]<br /></p><h3>Creating your own error conditions</h3><p>User-extensibility in the <tt><system_error></tt> facility is not limited to error codes: <tt>error_condition</tt> permits the same customisation.<br /></p><h4>Why create custom error conditions?</h4><p>To answer this question, let's revisit the distinction between <tt>error_code</tt> and <tt>error_condition</tt>:<br /></p><ul><li><tt>class error_code</tt> - represents a specific error value returned by an operation (such as a system call).<br /><li><tt>class error_condition</tt> - something that you want to test for and, potentially, react to in your code.<br /></ul><p>This suggests some use cases for custom error conditions:<br /></p><ul><li><b>Abstraction of OS-specific errors.</b><p>Let's say you're writing a portable wrapper around <tt>getaddrinfo()</tt>. Two interesting error conditions are the tentative "the name does not resolve at this time, try again later", and the authoritative "the name does not resolve". The <tt>getaddrinfo()</tt> function reports these errors as follows:</p><ul><li>On POSIX platforms, the errors are <tt>EAI_AGAIN</tt> and <tt>EAI_NONAME</tt>, respectively. The error values are in a distinct "namespace" to <tt>errno</tt> values. This means you will have to implement a new <tt>error_category</tt> to capture the errors.<li>On Windows, the errors are <tt>WSAEAI_AGAIN</tt> and <tt>WSAEAI_NONAME</tt>. Although the names are similar to the POSIX errors, they share the <tt>GetLastError</tt> "namespace". Consequently, you may want to reuse <tt>std::system_category()</tt> to capture and represent <tt>getaddrinfo()</tt> errors on this platform.</ul><p>To avoid discarding information, you want to preserve the original OS-specific error code while providing two error conditions (called <tt>name_not_found_try_again</tt> and <tt>name_not_found</tt>, say) that API users can test against.<br /><li><b>Giving context-specific meaning to generic error codes.</b><p>Most POSIX system calls use <tt>errno</tt> to report errors. Rather than define new errors for each function, the same errors are reused and you may have to look at the corresponding <tt>man</tt> page to determine the meaning. If you implement your own abstractions on top of these system calls, this context is lost to the user.</p><p>For example, say you want to implement a simple database where each entry is stored in a separate flat file. When you try to read an entry, the database calls <tt>open()</tt> to access the file. This function sets <tt>errno</tt> to <tt>ENOENT</tt> if the file does not exist.</p><p>As the database's storage mechanism is abstracted from the user, it could be surprising to ask them to test for <tt>no_such_file_or_directory</tt>. Instead, you can create your own context-specific error condition, <tt>no_such_entry</tt>, which is equivalent to <tt>ENOENT</tt>.<br /><li><b>Testing for a set of related errors.</b><p>As your codebase grows, you might find the same set of errors are checked again and again. Perhaps you need to respond to low system resources:</p><ul><li><tt>not_enough_memory</tt><li><tt>resource_unavailable_try_again</tt><li><tt>too_many_files_open</tt><li><tt>too_many_files_open_in_system</tt><li>...</ul><p>in several places, but the subsequent action differs at each point of use. This shows that there is a more general condition, "the system resources are low", that you want to test for and react to in your code.</p><p>A custom error condition, <tt>low_system_resources</tt>, can be defined so that its equivalence is based on a combination of other error conditions. This allows you to write each test as:<br /></p><pre>if (ec == low_system_resources)<br /> ...<br /></pre><p>and so eliminate the repetition of individual tests.<br /></ul><p>The definition of custom error conditions is similar to the method for <tt>error_code</tt>s, as you will see in the steps below.<br /></p><h4>Step 1: define the error values</h4><p>You need to create an <tt>enum</tt> for the error values, similar to <tt>std::errc</tt>:<br /></p><pre>enum class api_error<br />{<br /> low_system_resources = 1,<br /> ...<br /> name_not_found,<br /> ...<br /> no_such_entry<br />};<br /></pre><p>The actual values you use are not important, but you must ensure that they are distinct and non-zero.<br /></p><h4>Step 2: define an <tt>error_category</tt> class</h4><p>An <tt>error_condition</tt> object consists of both an error value and a category. To create a new category, you must derive a class from <tt>error_category</tt>:<br /></p><pre>class api_category_impl<br /> : public std::error_category<br />{<br />public:<br /> virtual const char* name() const;<br /> virtual std::string message(int ev) const;<br /> virtual bool equivalent(<br /> const std::error_code& code,<br /> int condition) const;<br />};<br /></pre><h4>Step 3: give the category a human-readable name</h4><p>The <tt>error_category::name()</tt> virtual function must return a string identifying the category:<br /></p><pre>const char* api_category_impl::name() const<br />{<br /> return "api";<br />}<br /></pre><h4>Step 4: convert error conditions to strings</h4><p><p>The <tt>error_category::message()</tt> function converts an error value into a string that describes the error:<br /></p><pre>std::string api_category_impl::message(int ev) const<br />{<br /> switch (ev)<br /> {<br /> case api_error::low_system_resources:<br /> return "Low system resources";<br /> ...<br /> }<br />}<br /></pre><p>However, depending on your use case, it may be unlikely that you'll ever call <tt>error_condition::message()</tt>. In that case, you can take a shortcut and simply write:<br /></p><pre>std::string api_category_impl::message(int ev) const<br />{<br /> return "api error";<br />}<br /></pre><h4>Step 5: implement error equivalence</h4><p>The <tt>error_category::equivalent()</tt> virtual function is used to define equivalence between error codes and conditions. In fact, there are two overloads of the <tt>error_category::equivalent()</tt> function. The first:<br /></p><pre>virtual bool equivalent(int code,<br /> const error_condition& condition) const;<br /></pre><p>is used to establish equivalence between <tt>error_code</tt>s in the current category with arbitrary <tt>error_condition</tt>s. The second overload:<br /></p><pre>virtual bool equivalent(<br /> const error_code& code,<br /> int condition) const;<br /></pre><p>defines equivalence between <tt>error_condition</tt>s in the current category with <tt>error_code</tt>s from any category. Since you are creating custom error conditions, it is the second overload that you must override.<br /></p>Defining equivalence is simple: return <tt>true</tt> if you want an <tt>error_code</tt> to be equivalent to your condition, otherwise return <tt>false</tt>.<br /></p><p>If your intent is to abstract OS-specific errors, you might implement <tt>error_category::equivalent()</tt> like this:<br /></p><pre>bool api_category_impl::equivalent(<br /> const std::error_code& code,<br /> int condition) const<br />{<br /> switch (condition)<br /> {<br /> ...<br /> case api_error::name_not_found:<br />#if defined(_WIN32)<br /> return code == std::error_code(<br /> WSAEAI_NONAME, system_category());<br />#else<br /> return code = std::error_code(<br /> EAI_NONAME, getaddrinfo_category());<br />#endif<br /> ...<br /> default:<br /> return false;<br /> }<br />}<br /></pre><p>(Obviously <tt>getaddrinfo_category()</tt> needs to be defined somewhere too.)<br /></p><p>The tests can be as complex as you like, and can even reuse other <tt>error_condition</tt> constants. You may want to do this if you're creating a context-specific error condition, or testing for a set of related errors:<br /></p><pre>bool api_category_impl::equivalent(<br /> const std::error_code& code,<br /> int condition) const<br />{<br /> switch (condition)<br /> {<br /> case api_error::low_system_resources:<br /> return code == std::errc::not_enough_memory<br /> || code == std::errc::resource_unavailable_try_again<br /> || code == std::errc::too_many_files_open<br /> || code == std::errc::too_many_files_open_in_system;<br /> ...<br /> case api_error::no_such_entry:<br /> return code == std::errc::no_such_file_or_directory;<br /> default:<br /> return false;<br /> }<br />}<br /></pre><h4>Step 6: uniquely identify the category</h4><p>You should provide a function to return a reference to a category object:<br /></p><pre>const std::error_category& api_category();<br /></pre><p>such that it always returns a reference to the same object. As with custom error codes, you can use a global:<br /></p><pre>api_category_impl api_category_instance;<br /><br />const std::error_category& api_category()<br />{<br /> return api_category_instance;<br />}<br /></pre><p>or you can make use of C++0x's thread-safe static variables:<br /></p><pre>const std::error_category& api_category()<br />{<br /> static api_category_impl instance;<br /> return instance;<br />}<br /></pre><h4>Step 7: construct an <tt>error_condition</tt> from the <tt>enum</tt></h4><p>The <tt><system_error></tt> implementation requires a function called <tt>make_error_condition()</tt> to associate an error value with a category:<br /></p><pre>std::error_condition make_error_condition(api_error e)<br />{<br /> return std::error_condition(<br /> static_cast<int>(e),<br /> api_category());<br />}<br /></pre><p>For completeness, you should also provide the equivalent function for construction of an <tt>error_code</tt>. I'll leave that as an exercise for the reader.<br /></p><h4>Step 8: register for implicit conversion to <tt>error_condition</tt></h4><p>Finally, for the <tt>api_error</tt> enumerators to be usable as <tt>error_condition</tt> constants, enable the conversion constructor using the <tt>is_error_condition_enum</tt> type trait:<br /></p><pre>namespace std<br />{<br /> template <><br /> struct is_error_condition_enum<api_error><br /> : public true_type {};<br />}<br /></pre><h4>Using the error conditions</h4><p>The <tt>api_error</tt> enumerators can now be used as <tt>error_condition</tt> constants, just as you may use those defined in <tt>std::errc</tt>:<br /></p><pre>std::error_code ec;<br />load_resource("http://some/url", ec);<br />if (ec == api_error::low_system_resources)<br /> ...<br /></pre><p>As I've said several times before, the original error code is retained and no information is lost. It doesn't matter whether that error code came from the operating system or from an HTTP library with its own error category. Your custom error conditions can work equally well with either.<br /><p>Next, in what will probably be the final instalment, I'll discuss how to design APIs that use the <tt><system_error></tt> facility.</p>chrishttp://www.blogger.com/profile/09159109667366328919[email protected]448tag:blogger.com,1999:blog-35024958.post-54033986959897584732010-04-12T17:18:00.002+10:002010-04-12T17:19:51.905+10:00System error support in C++0x - part 4<p>[ <a href="http://blog.think-async.com/2010/04/system-error-support-in-c0x-part-1.html">part 1</a>, <a href="http://blog.think-async.com/2010/04/system-error-support-in-c0x-part-2.html">part 2</a>, <a href="http://blog.think-async.com/2010/04/system-error-support-in-c0x-part-3.html">part 3</a> ]<br /></p><h3>Creating your own error codes</h3><p>As I stated in <a href="http://blog.think-async.com/2010/04/system-error-support-in-c0x-part-1.html">part 1</a>, one of the principles behind the <tt><system_error></tt> facility is user-extensibility. This means that you can use the mechanism just described to define your own error codes.<br /></p><p>In this section, I'll outline what you need to do. As a basis for a worked example, I will assume you're writing an HTTP library and need errors that correspond to the HTTP response codes.<br /></p><h4>Step 1: define the error values</h4><p>You first need to define the set of error values. If you're using C++0x, you can use an <tt>enum class</tt>, similar to <tt>std::errc</tt>:<br /></p><pre>enum class http_error<br />{<br /> continue_request = 100,<br /> switching_protocols = 101,<br /> ok = 200,<br /> ...<br /> gateway_timeout = 504,<br /> version_not_supported = 505<br />};<br /></pre><p>The errors are assigned values according to the HTTP response codes. The importance of this will become obvious when it comes to using the error codes. Whatever values you choose, errors should have non-zero values. As you may recall, the <tt><system_error></tt> facility uses a convention where zero means success.<br /></p><p>You can use regular (that is, C++03-compatible) <tt>enum</tt>s by dropping the <tt>class</tt> keyword:<br /></p><pre>enum http_error<br />{<br /> ...<br />};<br /></pre><p><b>Note:</b> C++0x's <tt>enum class</tt> differs from <tt>enum</tt> in that the former encloses enumerator names in the class scope. To access an enumerator you must prefix the class name, as in <tt>http_error::ok</tt>. You can approximate this behaviour by wrapping the plain <tt>enum</tt> in a <tt>namespace</tt>:<br /></p><pre>namespace http_error<br />{<br /> enum http_error_t<br /> {<br /> ...<br /> };<br />}<br /></pre><p>For the remainder of this example I will assume the use of <tt>enum class</tt>. Applying the <tt>namespace</tt>-wrapping approach is left as an exercise for the reader.<br /></p><h4>Step 2: define an <tt>error_category</tt> class</h4><p>An <tt>error_code</tt> object consists of both an error value and a category. The error category determines whether a value of <tt>100</tt> means <tt>http_error::continue_request</tt>, <tt>std::errc::network_down</tt> (<tt>ENETDOWN</tt> on Linux), or something else entirely.<br /></p><p>To create a new category, you must derive a class from <tt>error_category</tt>:<br /></p><pre>class http_category_impl<br /> : public std::error_category<br />{<br />public:<br /> virtual const char* name() const;<br /> virtual std::string message(int ev) const;<br />};<br /></pre><p>For the moment, this class will implement only <tt>error_category</tt>'s pure virtual functions.<br /></p><h4>Step 3: give the category a human-readable name</h4><p>The <tt>error_category::name()</tt> virtual function must return a string identifying the category:<br /></p><pre>const char* http_category_impl::name() const<br />{<br /> return "http";<br />}<br /></pre><p>This name does not need to be universally unique, as it is really only used when writing an error code to a <tt>std::ostream</tt>. However, it would certainly be desirable to make it unique within a given program.<br /></p><h4>Step 4: convert error codes to strings</h4><p><p>The <tt>error_category::message()</tt> function converts an error value into a string that describes the error:<br /></p><pre>std::string http_category_impl::message(int ev) const<br />{<br /> switch (ev)<br /> {<br /> case http_error::continue_request:<br /> return "Continue";<br /> case http_error::switching_protocols:<br /> return "Switching protocols";<br /> case http_error::ok:<br /> return "OK";<br /> ...<br /> case http_error::gateway_timeout:<br /> return "Gateway time-out";<br /> case http_error::version_not_supported:<br /> return "HTTP version not supported";<br /> default:<br /> return "Unknown HTTP error";<br /> }<br />}<br /></pre><p>When you call the <tt>error_code::message()</tt> member function, the <tt>error_code</tt> in turn calls the above virtual function to obtain the error message.<br /></p><p>It's important to remember that these error messages must stand alone; they may be written (to a log file, say) at a point in the program when no additional context is available. If you are wrapping an existing API that uses error messages with "inserts", you'll have to create your own messages. For example, if an HTTP API uses the message string <tt>"HTTP version %d.%d not supported"</tt>, the equivalent stand-alone message would be <tt>"HTTP version not supported"</tt>.<br /></p><p>The <tt><system_error></tt> facility provides no assistance when it comes to localisation of these messages. It is likely that the messages emitted by your standard library's error categories will be based on the current locale. If localisation is a requirement in your program, I recommend using the same approach. (<b>Some history:</b> The LWG was aware of the need for localisation, but there was no design before the group that satisfactorily reconciled localisation with user-extensibility. Rather than engage in some design-by-committee, the LWG opted to say nothing in the standard about localisation of the error messages.)<br /></p><h4>Step 5: uniquely identify the category</h4><p>The identity of an <tt>error_category</tt>-derived object is determined by its address. This means that when you write:<br /></p><pre>const std::error_category& cat1 = ...;<br />const std::error_category& cat2 = ...;<br />if (cat1 == cat2)<br /> ...<br /></pre><p>the <tt>if</tt> condition is evaluated as if you had written:<br /></p><pre>if (&cat1 == &cat2)<br /> ...<br /></pre><p>Following the example set by the standard library, you should provide a function to return a reference to a category object:<br /></p><pre>const std::error_category& http_category();<br /></pre><p><br />This function must always return a reference to the same object. One way to do that is to define a global object in a source file and return a reference to that:<br /></p><pre>http_category_impl http_category_instance;<br /><br />const std::error_category& http_category()<br />{<br /> return http_category_instance;<br />}<br /></pre><p>However, using a global does introduce issues to do with order of initialisation across modules. An alternative approach is to use a locally scoped static variable:<br /></p><pre>const std::error_category& http_category()<br />{<br /> static http_category_impl instance;<br /> return instance;<br />}<br /></pre><p>In this case, the category object is initialised on first use. C++0x also guarantees that the initialisation is thread-safe. (C++03 makes no such guarantee.)<br /></p><p><b>History:</b> In the early design stages, we considered using an integer or string to identify an <tt>error_code</tt>'s category. The main issue with that approach was ensuring uniqueness in conjunction with user extensibility. If a category was identified by integer or string, what was to stop collisions between two unrelated libraries? Using object identity leverages the linker in preventing different categories from having the same identity. Furthermore, storing a pointer to a base class allows us to make <tt>error_code</tt>s polymorphic while keeping them as copyable value types.<br /></p><h4>Step 6: construct an <tt>error_code</tt> from the <tt>enum</tt></h4><p>As I showed in <a href="http://blog.think-async.com/2010/04/system-error-support-in-c0x-part-3.html">part 3</a>, the <tt><system_error></tt> implementation requires a function called <tt>make_error_code()</tt> to associate an error value with a category. For the HTTP errors, you would write this function as follows:<br /></p><pre>std::error_code make_error_code(http_error e)<br />{<br /> return std::error_code(<br /> static_cast<int>(e),<br /> http_category());<br />}<br /></pre><p>For completeness, you should also provide the equivalent function for construction of an <tt>error_condition</tt>:<br /></p><pre>std::error_condition make_error_condition(http_error e)<br />{<br /> return std::error_condition(<br /> static_cast<int>(e),<br /> http_category());<br />}<br /></pre><p>Since the <tt><system_error></tt> implementation finds these functions using <a href="http://en.wikipedia.org/wiki/Argument_dependent_name_lookup">argument-dependent lookup</a>, you should put them in the same namespace as the <tt>http_error</tt> type.<br /></p><h4>Step 7: register for implicit conversion to <tt>error_code</tt></h4><p>For the <tt>http_error</tt> enumerators to be usable as <tt>error_code</tt> constants, enable the conversion constructor using the <tt>is_error_code_enum</tt> type trait:<br /></p><pre>namespace std<br />{<br /> template <><br /> struct is_error_code_enum<http_error><br /> : public true_type {};<br />}<br /></pre><h4>Step 8 (optional): assign default error conditions</h4><p>Some of the errors you define may have a similar meaning to the standard's <tt>errc</tt> error conditions. For example, the HTTP response code <tt>403 Forbidden</tt> means basically the same thing as <tt>std::errc::permission_denied</tt>.<br /></p><p>The <tt>error_category::default_error_condition()</tt> virtual function lets you define an <tt>error_condition</tt> that is <i>equivalent</i> to a given error code. (See <a href="http://blog.think-async.com/2010/04/system-error-support-in-c0x-part-2.html">part 2</a> for the definition of equivalence.) For the HTTP errors, you can write:<br /></p><pre>class http_category_impl<br /> : std::error_category<br />{<br />public:<br /> ...<br /> virtual std::error_condition<br /> default_error_condition(int ev) const;<br />};<br />...<br />std::error_condition<br /> http_category_impl::default_error_condition(<br /> int ev) const<br />{<br /> switch (ev)<br /> {<br /> case http_error::forbidden:<br /> return std::errc::permission_denied;<br /> default:<br /> return std::error_condition(ev, *this);<br /> }<br />}<br /></pre><p>If you choose not to override this virtual function, an <tt>error_code</tt>'s default <tt>error_condition</tt> is one with the same error value and category. This is the behaviour of the <tt>default:</tt> case shown above.<br /></p><h4>Using the error codes</h4><p>You can now use the <tt>http_error</tt> enumerators as <tt>error_code</tt> constants, both when setting an error:<br /></p><pre>void server_side_http_handler(<br /> ...,<br /> std::error_code& ec)<br />{<br /> ...<br /> ec = http_error::ok;<br />}<br /></pre><p>and when testing for one:<br /></p><pre>std::error_code ec;<br />load_resource("http://some/url", ec);<br />if (ec == http_error::ok)<br /> ...<br /></pre><p>Since the error values are based on the HTTP response codes, we can also set an <tt>error_code</tt> directly from the response:<br /></p><pre>std::string load_resource(<br /> const std::string& url,<br /> std::error_code& ec)<br />{<br /> // send request ...<br /><br /> // receive response ...<br /><br /> int response_code;<br /> parse_response(..., &response_code);<br /> ec.assign(response_code, http_category());<br /><br /> // ...<br />}<br /></pre><p>You can also use this technique when wrapping the errors produced by an existing library.<br /></p><p>Finally, if you defined an equivalence relationship in step 8, you can write:<br /></p><pre>std::error_code ec;<br />data = load_resource("http://some/url", ec);<br />if (ec == std::errc::permission_denied)<br /> ...<br /></pre><p>without needing to know the exact source of the error condition. As explained in <a href="http://blog.think-async.com/2010/04/system-error-support-in-c0x-part-2.html">part 2</a>, the original error code (e.g. <tt>http_error::forbidden</tt>) is retained so that no information is lost.<br /></p><p>In the next part, I'll show how to create and use custom <tt>error_condition</tt>s.</p>chrishttp://www.blogger.com/profile/09159109667366328919[email protected]182tag:blogger.com,1999:blog-35024958.post-36816849562432001532010-04-09T08:00:00.004+10:002010-04-09T08:26:50.907+10:00System error support in C++0x - part 3<p>[ <a href="http://blog.think-async.com/2010/04/system-error-support-in-c0x-part-1.html">part 1</a>, <a href="http://blog.think-async.com/2010/04/system-error-support-in-c0x-part-2.html">part 2</a> ]<br /></p><h3>Enumerators as class constants</h3><p>As we have seen, the <tt><system_error></tt> header defines <tt>enum class errc</tt>:<br /></p><pre>enum class errc<br />{<br /> address_family_not_supported,<br /> address_in_use,<br /> ...<br /> value_too_large,<br /> wrong_protocol_type,<br />};<br /></pre><p>the enumerators of which are placeholders for <tt>error_condition</tt> constants:<br /></p><pre>std::error_code ec;<br />create_directory("/some/path", ec);<br />if (ec == std::errc::file_exists)<br /> ...<br /></pre><p>Obviously, this is because there's an implicit conversion from <tt>errc</tt> to <tt>error_condition</tt> using a single-argument constructor. Simple. Right?<br /></p><h4>It's not quite that simple</h4><p>There's a few reasons why there's a bit more to it than that:<br /></p><ul><li>The enumerator provides an error value, but to construct an <tt>error_condition</tt> we need to know the category too. The <tt><system_error></tt> facility uses categories to support multiple error sources, and a category is an attribute of both <tt>error_code</tt> and <tt>error_condition</tt>.<br /><li>The facility should be user-extensible. That is, users (as well as future extensions to the standard library) need to be able to define their own placeholders.<br /><li>The facility should support placeholders for either <tt>error_code</tt> or <tt>error_condition</tt>. Although <tt>enum class errc</tt> provides placeholders for <tt>error_condition</tt> constants, other use cases may require constants of type <tt>error_code</tt>.<br /><li>Finally, it should allow explicit conversion from an enumerator to <tt>error_code</tt> or <tt>error_condition</tt>. Portable programs may need to create error codes that are derived from the <tt>std::errc::*</tt> enumerators.<br /></ul><p>So, while it's true that the line:<br /></p><pre>if (ec == std::errc::file_exists)<br /></pre><p>implicitly converts from <tt>errc</tt> to <tt>error_condition</tt>, there are a few more steps involved.<br /></p><h4>Step 1: determine whether the <tt>enum</tt> is an error code or condition</h4><p>Two type traits are used to register <tt>enum</tt> types with the <tt><system_error></tt> facility:<br /></p><pre>template <class T><br />struct is_error_code_enum<br /> : public false_type {};<br /><br />template <class T><br />struct is_error_condition_enum<br /> : public false_type {};<br /></pre><p>If a type is registered using <tt>is_error_code_enum<></tt> then it may be implicitly converted to an <tt>error_code</tt>. Similarly, if a type is registered using <tt>is_error_condition_enum<></tt>, it can be implicitly converted to <tt>error_condition</tt>. By default, types are registered for neither conversion (hence the use of <tt>false_type</tt> above), but <tt>enum class errc</tt> is registered as follows:<br /></p><pre>template <><br />struct is_error_condition_enum<errc><br /> : true_type {};<br /></pre><p>The implicit conversion is accomplished by conditionally enabled conversion constructors. This is probably implemented using <a href="http://en.wikipedia.org/wiki/Substitution_failure_is_not_an_error">SFINAE</a>, but for simplicity you need only think of it as:<br /></p><pre>class error_condition<br />{<br /> ...<br /> // Only available if registered<br /> // using is_error_condition_enum<>.<br /> template <class ErrorConditionEnum><br /> error_condition(ErrorConditionEnum e);<br /> ...<br />};<br /><br />class error_code<br />{<br /> ...<br /> // Only available if registered<br /> // using is_error_code_enum<>.<br /> template <class ErrorCodeEnum><br /> error_code(ErrorCodeEnum e);<br /> ...<br />};<br /></pre><p>Therefore, when we write:<br /></p><pre>if (ec == std::errc::file_exists)<br /></pre><p>the compiler has to choose between these two overloads:<br /></p><pre>bool operator==(<br /> const error_code& a,<br /> const error_code& b);<br /><br />bool operator==(<br /> const error_code& a,<br /> const error_condition& b);<br /></pre><p>It chooses the latter because the <tt>error_condition</tt> conversion constructor is available, but the <tt>error_code</tt> one is not.<br /></p><h4>Step 2: associate the value with an error category</h4><p>An <tt>error_condition</tt> object contains two attributes: value and category. Now that we're in the constructor, these need to be initialised correctly.<br /></p><p>This is accomplished by having the constructor call the function <tt>make_error_condition()</tt>. To enable user-extensibility, this function is located using <a href="http://en.wikipedia.org/wiki/Argument_dependent_name_lookup">argument-dependent lookup</a>. Of course, since <tt>errc</tt> is in <tt>namespace std</tt>, its <tt>make_error_condition()</tt> is found there too.<br /><p>The implementation of <tt>make_error_condition()</tt> is simply:<br /></p><pre>error_condition make_error_condition(errc e)<br />{<br /> return error_condition(<br /> static_cast<int>(e),<br /> generic_category());<br />}<br /></pre><p>As you can see, this function uses the two-argument <tt>error_condition</tt> constructor to explicitly specify both the error value and category.<br /></p><p>If we were in the <tt>error_code</tt> conversion constructor (for an appropriately registered <tt>enum</tt> type), the function called would be <tt>make_error_code()</tt>. In other respects, the construction of <tt>error_code</tt> and <tt>error_condition</tt> is the same.<br /></p><p><h4>Explicit conversion to <tt>error_code</tt> or <tt>error_condition</tt></h4><p>Although <tt>error_code</tt> is primarily intended for use with OS-specific errors, portable code may want to construct an <tt>error_code</tt> from an <tt>errc</tt> enumerator. For this reason, both <tt>make_error_code(errc)</tt> and <tt>make_error_condition(errc)</tt> are provided. Portable code can use these as follows:<br /></p><pre>void do_foo(std::error_code& ec)<br />{<br />#if defined(_WIN32)<br /> // Windows implementation ...<br />#elif defined(linux)<br /> // Linux implementation ...<br />#else<br /> // do_foo not supported on this platform<br /> ec = make_error_code(std::errc::not_supported);<br />#endif<br />}<br /></pre><h4>Some history</h4><p>The original <tt><system_error></tt> proposal defined <tt>error_code</tt> constants as objects:<br /></p><pre>extern error_code address_family_not_supported;<br />extern error_code address_in_use;<br />...<br />extern error_code value_too_large;<br />extern error_code wrong_protocol_type;<br /></pre><p>The LWG was concerned about the size overhead of so many global objects, and an alternative approach was requested. We researched the possibility of using <tt>constexpr</tt>, but that was ultimately found to be incompatible with some other aspects of the <tt><system_error></tt> facility. This left conversion from <tt>enum</tt> as the best available design.<br /></p><p>Next, I'll start showing how you can extend the facility to add your own error codes and conditions.</p>chrishttp://www.blogger.com/profile/09159109667366328919[email protected]50tag:blogger.com,1999:blog-35024958.post-1333724067101263402010-04-08T07:13:00.002+10:002010-04-08T07:16:42.625+10:00System error support in C++0x - part 2<p>[ <a href="http://blog.think-async.com/2010/04/system-error-support-in-c0x-part-1.html">part 1</a> ]<br /></p><h3><tt>error_code</tt> vs <tt>error_condition</tt></h3><p>Of the 1000+ pages of C++0x draft, the casual reader is bound to notice one thing: <tt>error_code</tt> and <tt>error_condition</tt> look virtually identical! What's going on? Is it a copy/paste error?<br /></p><h4>It's what you do with it that counts</h4><p>Let's review the descriptions I gave in part 1:<br /></p><ul><li><tt>class error_code</tt> - represents a specific error value returned by an operation (such as a system call).<br /><li><tt>class error_condition</tt> - something that you want to test for and, potentially, react to in your code.<br /></ul><p>The classes are distinct types because they're intended for different uses. As an example, consider a hypothetical function called <tt>create_directory()</tt>:<br /></p><pre>void create_directory(<br /> const std::string& pathname,<br /> std::error_code& ec);<br /></pre><p>which you call like this:<br /></p><pre>std::error_code ec;<br />create_directory("/some/path", ec);<br /></pre><p>The operation can fail for a variety of reasons, such as:<br /></p><ul><li>Insufficient permission.<br /><li>The directory already exists.<br /><li>The path is too long.<br /><li>The parent path doesn't exist.<br /></ul><p>Whatever the reason for failure, after <tt>create_directory()</tt> returns, the <tt>error_code</tt> object <tt>ec</tt> will contain the OS-specific error code. On the other hand, if the call was successful then <tt>ec</tt> contains a zero value. This follows the tradition (used by <tt>errno</tt> and <tt>GetLastError()</tt>) of having 0 indicate success and non-zero indicate failure.<br /></p><p>If you're only interested in whether the operation succeeded or failed, you can use the fact that <tt>error_code</tt> is convertible-to-<tt>bool</tt>:<br /></p><pre>std::error_code ec;<br />create_directory("/some/path", ec);<br />if (!ec)<br />{<br /> // Success.<br />}<br />else<br />{<br /> // Failure.<br />}<br /></pre><p>However, let's say you're interested in checking for the "directory already exists" error. If that's the error then our hypothetical caller can continue running. Let's have a crack at it:<br /></p><pre>std::error_code ec;<br />create_directory("/some/path", ec);<br />if (ec.value() == EEXIST) <font color="#ff0000">// No!</font><br /> ...<br /></pre><p>This code is wrong. You might get away with it on POSIX platforms, but don't forget that <tt>ec</tt> will contain the OS-specific error. On Windows, the error is likely to be <tt>ERROR_ALREADY_EXISTS</tt>. (Worse, the code doesn't check the error code's category, but we'll cover that later.)<br /></p><p><b>Rule of thumb:</b> If you're calling <tt>error_code::value()</tt> then you're doing it wrong.<br /></p><p>So here you have an OS-specific error <i>code</i> (<tt>EEXIST</tt> or <tt>ERROR_ALREADY_EXISTS</tt>) that you want to check against an error <i>condition</i> ("directory already exists"). Yep, that's right, you need an <tt>error_condition</tt>.<br /></p><h4>Comparing <tt>error_code</tt>s and <tt>error_condition</tt>s</h4><p>Here is what happens when you compare <tt>error_code</tt> and <tt>error_condition</tt> objects (i.e. when you use <tt>operator==</tt> or <tt>operator!=</tt>):<br /></p><ul><li><tt>error_code</tt> against <tt>error_code</tt> - checks for exact match.<br /><li><tt>error_condition</tt> against <tt>error_condition</tt> - checks for exact match.<br /><li><tt>error_code</tt> against <tt>error_condition</tt> - checks for <i>equivalence</i>.<br /></ul><p>I hope that it's now obvious that you should be comparing your OS-specific error code <tt>ec</tt> against an <tt>error_condition</tt> object that represents "directory already exists". C++0x provides one for exactly that: <tt>std::errc::file_exists</tt>. This means you should write:<br /></p><pre>std::error_code ec;<br />create_directory("/some/path", ec);<br />if (ec == std::errc::file_exists)<br /> ...<br /></pre><p>This works because the library implementor has defined the equivalence between the error codes <tt>EEXIST</tt> or <tt>ERROR_ALREADY_EXISTS</tt> and the error condition <tt>std::errc::file_exists</tt>. In a future instalment I'll show how you can add your own error codes and conditions with the appropriate equivalence definitions.<br /></p><p>(Note that, to be precise, <tt>std::errc::file_exists</tt> is an enumerator of <tt>enum class errc</tt>. For now you should think of the <tt>std::errc::*</tt> enumerators as placeholders for <tt>error_condition</tt> constants. In a later part I'll explain how that works.)<br /></p><h4>How to know what conditions you can test for</h4><p>Some of the new library functions in C++0x have "Error conditions" clauses. These clauses list the <tt>error_condition</tt> constants and the conditions under which equivalent error codes will be generated.<br /></p><h4>A bit of history</h4><p>The original <tt>error_code</tt> class was proposed for TR2 as a helper component for the filesystem and networking libraries. In that design, an <tt>error_code</tt> constant is implemented so that it matches the OS-specific error, where possible. When a match is not possible, or where there are multiple matches, the library implementation translates from the OS-specific error to the standard <tt>error_code</tt>, after performing the underlying operation.<br /></p><p>In email-based design discussions I learnt the value of preserving the original error code. Subsequently, a <tt>generic_error</tt> class was prototyped but did not satisfy. A satisfactory solution was found in renaming <tt>generic_error</tt> to <tt>error_condition</tt>. In my experience, naming is one of the Hardest Problems in Computer Science, and a good name will get you most of the way there.<br /></p><p>Next up, a look at the mechanism that makes <tt>enum class errc</tt> work as <tt>error_condition</tt> placeholders.</p>chrishttp://www.blogger.com/profile/09159109667366328919[email protected]137tag:blogger.com,1999:blog-35024958.post-89727748624708907132010-04-07T14:45:00.005+10:002010-04-07T14:57:05.137+10:00System error support in C++0x - part 1<p>Among the many new library features in C++0x is a little header called <tt><system_error></tt>. It provides a selection of utilities for managing, well, system errors. The principal components defined in the header are:<br /></p><ul><li><tt>class error_category</tt><br /><li><tt>class error_code</tt><br /><li><tt>class error_condition</tt><br /><li><tt>class system_error</tt><br /><li><tt>enum class errc</tt><br /></ul><p>I had a hand in the design of this facility, so in this series of posts I will try to capture the rationale, history, and intended uses of the various components.<br /></p><h3>Where to get it</h3><p>A complete implementation, and one that supports C++03, is included in <a href="http://www.boost.org">Boost</a>. I'd guess that, at this point in time, it is probably the best tested implementation in terms of portability. Of course, you have to spell things starting with <tt>boost::system::</tt> rather than <tt>std::</tt>.<br /></p><p>An implementation is included with <a href="http://gcc.gnu.org">GCC</a> 4.4 and later. However, you must compile your program with the <tt>-std=c++0x</tt> option in order to use it.<br /></p><p>Finally, <a href="http://www.microsoft.com/visualstudio/2010/overview.mspx">Microsoft Visual Studio 2010</a> will ship with an implementation of the classes. The main limitation is that the <tt>system_category()</tt> does not represent Win32 errors as was intended. More on what that means later.<br /></p></p>(Note that these are just the implementations that I am aware of. There may be others.)<br /></p><br /><h3>Overview</h3><p>Here are the types and classes defined by <tt><system_error></tt>, in a nutshell:<br /></p><ul><li><tt>class error_category</tt> - intended as a base class, an <tt>error_category</tt> is used to define sources of errors or categories of error codes and conditions.<br /><li><tt>class error_code</tt> - represents a specific error value returned by an operation (such as a system call).<br /><li><tt>class error_condition</tt> - something that you want to test for and, potentially, react to in your code.<br /><li><tt>class system_error</tt> - an exception used to wrap <tt>error_code</tt>s when an error is to be reported via <tt>throw</tt>/<tt>catch</tt>.<br /><li><tt>enum class errc</tt> - a set of generic error condition values, derived from POSIX.<br /><li><tt>is_error_code_enum<></tt>, <tt>is_error_condition_enum<></tt>, <tt>make_error_code</tt>, <tt>make_error_condition</tt> - a mechanism for converting <tt>enum class</tt> error values into <tt>error_code</tt>s or <tt>error_condition</tt>s.<br /><li><tt>generic_category()</tt> - returns a category object used to classify the <tt>errc</tt>-based error codes and conditions.<br /><li><tt>system_category()</tt> - returns a category object used for error codes that originate from the operating system.<br /></ul><h3>Principles</h3><p>This section lists some of the guiding principles I had in mind in designing the facility. (I cannot speak for the others involved.) As with most software projects, some were goals at the outset and some were picked up along the way.<br /></p><h4>Not all errors are exceptional</h4><p>Simply put, exceptions are not always the right way to handle errors. (In some circles this is a controversial statement, although I really don't understand why.)<br /></p><p>In network programming, for example, there are commonly encountered errors such as:<br /></p><ul><li>You were unable to connect to a remote IP address.<br /><li>Your connection dropped out.<br /><li>You tried to open an IPv6 socket but no IPv6 network interfaces are available.<br /></ul><p>Sure, these <i>might</i> be exceptional conditions, but equally they may be handled as part of normal control flow. If you reasonably expect it to happen, it's not exceptional. Respectively:<br /></p><ul><li>The IP address is one of a list of addresses corresponding to a host name. You want to try connecting to the next address in the list.<br /><li>The network is unreliable. You want to try to reestablish the connection and only give up after N failures.<br /><li>Your program can drop back to using an IPv4 socket.<br /></ul><p>Another requirement, in the case of Asio, was a way to pass the result of an asynchronous operation to its completion handler. In this case, I want the operation's error code to be an argument to the handler callback. (An alternative approach is to provide a means to rethrow an exception inside the handler, such as .NET's <tt>BeginXYZ</tt>/<tt>EndXYZ</tt> asynchronous pattern. In my opinion, that design adds complexity and makes the API more error-prone.)<br /></p><p>Last, but not least, some domains will be unable or unwilling to use exceptions due to code size and performance constraints.<br /></p><p>In short: be pragmatic, not dogmatic. Use whatever error mechanism suits best in terms of clarity, correctness, constraints, and, yes, even personal taste. Often the right place to make the decision between exception and error code is at the point of use. That means a system error facility should support both.<br /></p><h4>Errors come from multiple sources</h4><p>The C++03 standard recognises <tt>errno</tt> as a source of error codes. This is used by the <tt>stdio</tt> functions, some <tt>math</tt> functions, and so forth.<br /></p><p>On POSIX platforms, many system operations do use <tt>errno</tt> to propagate errors. POSIX defines additional <tt>errno</tt> error codes to cover these cases.<br /></p><p>Windows, on the other hand, does not make use of <tt>errno</tt> beyond the standard C library. Windows API calls typically report their errors via <tt>GetLastError</tt>.<br /><p>When one considers network programming, the <tt>getaddrinfo</tt> family of functions uses its own set of error codes (<tt>EAI_...</tt>) on POSIX, but shares the <tt>GetLastError()</tt> "namespace" on Windows. Programs that integrate other libraries (for SSL, regular expressions, or whatever) will encounter other categories of error code.<br /></p><p>Programs should be able to manage these error codes in a consistent manner. I'm especially concerned with enabling composition of operations to create higher-level abstractions. Combining system calls, <tt>getaddrinfo</tt>, SSL and regular expressions into one API should not force the user of that API to deal with an explosion of error code types. The addition of a new error source to the implementation of that API should not change the interface.<br /></p><h4>Be user-extensible</h4><p>Users of the standard library need to be able to add their own error sources. This ability may just be used to integrate a third-party library, but is also tied in with the desire to create higher-level abstractions. When developing a protocol implementation such as HTTP, I want to be able to add a set of error codes corresponding to the errors defined in the RFC.<br /></p><h4>Preserve the original error code</h4><p>This was not one of my original goals: my thinking was that the standard would provide a set of well-known error codes. If a system operation returned an error, it was the responsibility of the library to translate the error into a well-known code (if such a mapping made sense).<br /></p><p>Fortunately, someone showed me the error of my ways. Translating an error code discards information: the error returned by the underlying system call is lost. This may not be a big deal in terms of program control flow, but it matters a lot for program supportability. There is no doubt that programmers will use a standardised error code object for logging and tracing, and the original error may be vital in diagnosing problems.<br /></p><p>This final principle segues nicely into my topic for part 2: <tt>error_code</tt> vs <tt>error_condition</tt>. Stay tuned.</p>chrishttp://www.blogger.com/profile/09159109667366328919[email protected]207tag:blogger.com,1999:blog-35024958.post-55439304007723914762010-04-06T16:24:00.004+10:002010-04-06T16:38:10.769+10:00Bind illustrated<p>Asynchronous operations in Asio all expect a function object argument, the completion handler, which they invoke when the asynchronous operation completes. The signature of the handler depends on the type of operation. For example, a handler posted using <tt>io_service::post()</tt> must have the signature:<br /></p><pre>void handler();<br /></pre><p>while an asynchronous wait operation expects:<br /></p><pre>void handler(error_code ec);<br /></pre><p>and asynchronous read/write operations want:<br /></p><pre>void handler(error_code ec, size_t length);<br /></pre><p>Non-trivial applications will need to pass some context to the completion handler, such as a <tt>this</tt> pointer. One way to do this is to use a function object adapter like <tt>boost::bind</tt>, <tt>std::tr1::bind</tt> or (as of C++0x) <tt>std::bind</tt>.<br /></p><p>Unfortunately, for many C++ programmers, <tt>bind</tt> represents a little bit of magic. This is not helped by the impenetrable compiler errors that confront you when you use it incorrectly. And, in my experience, the underlying concept (where some function arguments are bound up-front, while others are delayed until the point of call) can present quite a steep learning curve.<br /></p><p>I have put together some diagrams to help explain how bind works. For clarity, I have taken a few liberties with C++ syntax (e.g. omitting the parameter types on the function call operator) and (over-)simplified <tt>bind</tt>'s implementation. Finally, the examples are limited to those likely to be useful with Asio. Comments and suggestions welcome.<br /></p><hr><p><tt>bind</tt> can be used to adapt a user-supplied function expecting one argument into a function object that takes zero arguments. The bound value (<tt>123</tt> in this example) is stored in a function object and is automatically passed to the user-supplied function as required:<br /></p><a href="http://think-async.com/blog/bind-illustrated/bind-plain-function-one-var-zero-args.png"><img width="420" src="http://think-async.com/blog/bind-illustrated/bind-plain-function-one-var-zero-args.png"></a><br /></p><p>[ click images for full size ]<br /></p><p>Binding an argument can be used to turn a class member function into a zero-argument function object. As you know, non-static member functions have an implicit <tt>this</tt> parameter. This means that an appropriate pointer needs to be bound into the function object:<br /></p><a href="http://think-async.com/blog/bind-illustrated/bind-member-function-one-var-zero-args.png"><img width="420" src="http://think-async.com/blog/bind-illustrated/bind-member-function-one-var-zero-args.png"></a><br /></p><p>Alternatively, the implicit <tt>this</tt> can be made explicit by adapting a member function into a function object taking one argument:<br /></p><a href="http://think-async.com/blog/bind-illustrated/bind-member-function-zero-vars-one-arg.png"><img width="420" src="http://think-async.com/blog/bind-illustrated/bind-member-function-zero-vars-one-arg.png"></a><br /><p>Function objects will often use both bound arguments and arguments supplied at the point of use. This can be done using member functions:<br /></p><a href="http://think-async.com/blog/bind-illustrated/bind-member-function-one-var-one-arg.png"><img width="420" src="http://think-async.com/blog/bind-illustrated/bind-member-function-one-var-one-arg.png"></a><br /><p>or non-member functions:<br /></p><a href="http://think-async.com/blog/bind-illustrated/bind-plain-function-one-var-two-args.png"><img width="420" src="http://think-async.com/blog/bind-illustrated/bind-plain-function-one-var-two-args.png"></a><br /><p>Sometimes the function object's point of use will supply arguments which are not required to call the target function. <tt>bind</tt> will automatically discard these surplus arguments:<br /></p><a href="http://think-async.com/blog/bind-illustrated/bind-plain-function-one-var-two-args-second-ignored.png"><img width="420" src="http://think-async.com/blog/bind-illustrated/bind-plain-function-one-var-two-args-second-ignored.png"></a><br /><p>The surplus argument(s) need not be the at the end of the function object signature:<br /></p><a href="http://think-async.com/blog/bind-illustrated/bind-plain-function-one-var-two-args-first-ignored.png"><img width="420" src="http://think-async.com/blog/bind-illustrated/bind-plain-function-one-var-two-args-first-ignored.png"></a><br /><p>Finally, <tt>bind</tt> allows you to the reorder arguments to adapt the target function to the necessary function object signature:<br /></p><a href="http://think-async.com/blog/bind-illustrated/bind-plain-function-one-var-two-args-reordered.png"><img width="420" src="http://think-async.com/blog/bind-illustrated/bind-plain-function-one-var-two-args-reordered.png"></a>chrishttp://www.blogger.com/profile/09159109667366328919[email protected]195tag:blogger.com,1999:blog-35024958.post-50832509281713683102010-04-05T22:07:00.002+10:002010-04-05T22:14:27.357+10:00Timeouts by analogy<p>Most networking-enabled applications have to deal with timeouts. Read or write operations may continue indefinitely, and programs need a way to determine when to tear down connections, resend requests, or take whatever other measures are necessary.<br /></p><p>Asio includes the <tt>deadline_timer</tt> class for managing timeouts. This class aims to provide a minimal interface for scheduling events. Of course, minimalism gives little in the way of design guidance, so some users struggle in finding an elegant way to incorporate timers and timeouts into their programs.<br /></p><p>From the minimalist perspective of Asio, there's no one true right way to do it. (Perhaps there's no better proof of that than my design preferences having changed over the years.) Yet that answer doesn't get programs written, so in this post I will try to present a simple mental model for managing timers.<br /></p><h3>Parking meters</h3><img src="http://think-async.com/blog/timeouts-by-analogy/parking-meter.jpg" align="right"/><p>High-traffic, commercial areas near where I live have limited on-street parking. The street parking that is available is metered. It's the usual drill:<br /></p><ul><br /><li>Park your vehicle.</li><br /><li>Feed some coins into the parking meter (or, as is more likely these days, swipe your credit card or send an SMS).</li><br /><li>Go do whatever you came to do.</li><br /><li>Make sure you return to your vehicle before the meter expires.</li><br /></ul><p>If you don't get back in time, you'd better hope your vehicle hasn't had a visit from the parking inspector. A visit means a ticket under the wipers and a nasty fine due.<br /></p><p>Parking meters are a good analogy for reasoning about timeouts because it's easy to identify the two actors:<br /></p><ul><br /><li>The driver of the vehicle.</li><br /><li>The parking inspector.</li><br /></ul><p>The driver performs the following steps:<br /></p><ol><br /><li>Feeds the meter.</li><br /><li>Leaves the vehicle to run some errands.</li><br /><li>Returns to the vehicle.</li><br /><li>If no ticket has been issued, repeats from step 1.</li><br /><li>If a fine has been issued, goes home.</li><br /></ol><p>The parking inspector's job is simple:<br /></p><ol><br /><li>Checks whether the meter has expired.</li><br /><li>If the meter has expired, writes up a ticket.</li><br /><li>If the meter has not expired, notes how much time is remaining.</li><br /><li>Goes off for a walk until the remaining time has elapsed.</li><br /></ol><h3>Using the analogy to inform program design</h3><p>Hopefully you've already guessed how these actors map to networked applications:<br /></p><ul><br /><li>The driver represents your protocol handling code.</li><br /><li>The parking inspector corresponds to your timeout management logic.</li><br /></ul><p>Let's take a look at how this works in a very simple use case.<br /></p><pre>// The "driver" actor.<br />void session::handle_read(error_code ec, size_t length)<br />{<br /> // On entering this function we have returned to the vehicle.<br /><br /> if (!ec)<br /> {<br /> // Phew, no ticket. Feed the meter.<br /> my_timer.expires_from_now(seconds(5));<br /><br /> // Process incoming data.<br /> // ...<br /><br /> // Run some more errands.<br /> my_socket.async_read_some(buffer(my_buffer),<br /> bind(&session::handle_read, this, _1, _2));<br /> }<br /> else<br /> {<br /> // We got a ticket. Go home.<br /> }<br />}<br /><br />// The "parking inspector" actor.<br />void session::handle_timeout(error_code ec)<br />{<br /> // On entering this function we are checking the meter.<br /><br /> // Has the meter expired?<br /> if (my_timer.expires_from_now() < seconds(0))<br /> {<br /> // Write up a ticket.<br /> my_socket.close();<br /> }<br /> else<br /> {<br /> // Note remaining time and go for a walk.<br /> my_timer.async_wait(<br /> bind(&session::handle_timeout, this, _1));<br /> }<br />}<br /></pre><p>It's important to remember that the driver may need to run multiple errands each time they leave the vehicle. In protocol terms, you might have a fixed-length header followed by a variable-length body. You only want to "feed the meter" once you have received a complete message:<br /></p><pre>// First part of the "driver" actor.<br />void session::handle_read_header(error_code ec)<br />{<br /> // We're not back at the vehicle yet.<br /><br /> if (!ec)<br /> {<br /> // Process header.<br /> // ...<br /><br /> // Run some more errands.<br /> async_read(my_socket, buffer(my_body),<br /> bind(&session::handle_read_body, this, _1));<br /> }<br />}<br /><br />// Second part of the "driver" actor.<br />void session::handle_read_body(error_code ec)<br />{<br /> // On entering this function we have returned to the vehicle.<br /><br /> if (!ec)<br /> {<br /> // Phew, no ticket. Feed the meter.<br /> my_timer.expires_from_now(seconds(5));<br /><br /> // Process complete message.<br /> // ...<br /><br /> // Run some more errands.<br /> async_read(my_socket, buffer(my_header),<br /> bind(&session::handle_read_header, this, _1));<br /> }<br /> else<br /> {<br /> // We got a ticket. Go home.<br /> }<br />}<br /></pre><p>There are many variations on this theme. For example, you may feed the meter between consecutive errands, varying the amount of money inserted (i.e. setting different length timeouts) depending on which errand comes next. In protocol terms, that might mean allowing up to 30 seconds between messages, but only a further 5 seconds is permitted once the message header has been received.<br /></p><p>As I indicated earlier, there's no single right way to manage timeouts. In fact, there are many different facets to this problem that are probably worth exploring in their own right. However, I think that the approach shown here is probably suited to most applications and I would recommend it as a starting point when designing your timeout handling.</p>chrishttp://www.blogger.com/profile/09159109667366328919[email protected]348tag:blogger.com,1999:blog-35024958.post-29705202109169736692010-03-31T11:40:00.012+11:002010-03-31T15:06:14.797+11:00A potted guide to stackless coroutines<p>Keen-eyed Asio users may have noticed that Boost 1.42 includes a new example, <a href="http://www.boost.org/doc/libs/1_42_0/doc/html/boost_asio/examples.html#boost_asio.examples.http_server_4">HTTP Server 4</a>, that shows how to use stackless coroutines in conjunction with asynchronous operations. This follows on from the coroutines I explored in the <a href="http://blog.think-async.com/2009/07/wife-says-i-cant-believe-it-works.html">previous</a> <a href="http://blog.think-async.com/2009/08/secret-sauce-revealed.html">three</a> <a href="http://blog.think-async.com/2009/08/composed-operations-coroutines-and-code.html">posts</a>, but with a few improvements. In particular:<br /></p><ul><li>the pesky <tt>entry</tt> pseudo-keyword is gone; and<br /><li>a new <tt>fork</tt> pseudo-keyword has been added.<br /></ul><p>The result bears a passing resemblance to C#'s <tt>yield</tt> and friends. This post aims to document my stackless coroutine API, but before launching into a long and wordy explanation, here's a little picture to liven things up:<br /></p><a href="http://think-async.com/blog/potted-guide-to-stackless-coroutines/coro_echo.png"><img width="450" src="http://think-async.com/blog/potted-guide-to-stackless-coroutines/coro_echo.png" /></a><p>[ Click image for full size. This image was generated from this <a href="http://think-async.com/blog/potted-guide-to-stackless-coroutines/coro_echo.cpp">source code</a> using <a href="http://asio.cvs.sourceforge.net/viewvc/asio/asioviz/">asioviz</a>. ]<br /></p><h3>class coroutine</h3><p>Every coroutine needs to store its current state somewhere. For that we have a class called <tt>coroutine</tt>:<br /></p><pre>class coroutine<br />{<br />public:<br /> coroutine();<br /> bool is_child() const;<br /> bool is_parent() const;<br /> bool is_complete() const;<br />};<br /></pre><p>Coroutines are copy-constructible and assignable, and the space overhead is a single <tt>int</tt>. They can be used as a base class:<br /></p><pre>class session : coroutine<br />{<br /> ...<br />};<br /></pre><p>or as a data member:<br /></p><pre>class session<br />{<br /> ...<br /> coroutine coro_;<br />};<br /></pre><p>or even bound in as a function argument using <tt>bind()</tt> (see <a href="http://blog.think-async.com/2009/08/composed-operations-coroutines-and-code.html">previous post</a>). It doesn't really matter as long as you maintain a copy of the object for as long as you want to keep the coroutine alive.<br /></p><h3>reenter</h3><p>The <tt>reenter</tt> macro is used to define the body of a coroutine. It takes a single argument: a pointer or reference to a coroutine object. For example, if the base class is a <tt>coroutine</tt> object you may write:<br /></p><pre>reenter (this)<br />{<br /> ... coroutine body ...<br />}<br /></pre><p>and if a data member or other variable you can write:<br /></p><pre>reenter (coro_)<br />{<br /> ... coroutine body ...<br />}<br /></pre><p>When <tt>reenter</tt> is executed at runtime, control jumps to the location of the last <tt>yield</tt> or <tt>fork</tt>.<br /></p><p>The coroutine body may also be a single statement. This lets you save a few keystrokes by writing things like:<br /></p><pre>reenter (this) for (;;)<br />{<br /> ...<br />}<br /></pre><p><b>Limitation:</b> The <tt>reenter</tt> macro is implemented using a switch. This means that you must take care when using local variables within the coroutine body. The local variable is not allowed in a position where reentering the coroutine could bypass the variable definition.<br /></p><h3>yield <i>statement</i></h3><p>This form of the <tt>yield</tt> keyword is often used with asynchronous operations:<br /></p><pre>yield socket_->async_read_some(buffer(*buffer_), *this);<br /></pre><p>This divides into four logical steps:<br /></p><ol><li><tt>yield</tt> saves the current state of the coroutine.<br /><li>The statement initiates the asynchronous operation.<br /><li>The resume point is defined immediately following the statement.<br /><li>Control is transferred to the end of the coroutine body.<br /></ol><p>When the asynchronous operation completes, the function object is invoked and <tt>reenter</tt> causes control to transfer to the resume point. It is important to remember to carry the coroutine state forward with the asynchronous operation. In the above snippet, the current class is a function object object with a <tt>coroutine</tt> object as base class or data member.<br /></p><p>The statement may also be a compound statement, and this permits us to define local variables with limited scope:<br /></p><pre>yield<br />{<br /> mutable_buffers_1 b = buffer(*buffer_);<br /> socket_->async_read_some(b, *this);<br />}<br /></pre><h3>yield return <i>expression</i> ;</h3><p>This form of <tt>yield</tt> is often used in generators or coroutine-based parsers. For example, the function object:<br /></p><pre>struct interleave : coroutine<br />{<br /> istream& is1;<br /> istream& is2;<br /> char operator()(char c)<br /> {<br /> reenter (this) for (;;)<br /> {<br /> yield return is1.get();<br /> yield return is2.get();<br /> }<br /> }<br />};<br /></pre><p>defines a trivial coroutine that interleaves the characters from two input streams.<br /></p><p>This type of <tt>yield</tt> divides into three logical steps:<br /></p><ol><li><tt>yield</tt> saves the current state of the coroutine.<br /><li>The resume point is defined immediately following the semicolon.<br /><li>The value of the expression is returned from the function.<br /></ol><h3>yield ;</h3><p>This form of <tt>yield</tt> is equivalent to the following steps:<br /></p><ol><li><tt>yield</tt> saves the current state of the coroutine.<br /><li>The resume point is defined immediately following the semicolon.<br /><li>Control is transferred to the end of the coroutine body.<br /></ol><p>This form might be applied when coroutines are used for cooperative threading and scheduling is explicitly managed. For example:<br /></p><pre>struct task : coroutine<br />{<br /> ...<br /> void operator()()<br /> {<br /> reenter (this)<br /> {<br /> while (... not finished ...)<br /> {<br /> ... do something ...<br /> yield;<br /> ... do some more ...<br /> yield;<br /> }<br /> }<br /> }<br /> ...<br />};<br />...<br />task t1, t2;<br />for (;;)<br />{<br /> t1();<br /> t2();<br />}<br /></pre><h3>yield break ;</h3><p>The final form of <tt>yield</tt> is adopted from C# and is used to explicitly terminate the coroutine. This form is comprised of two steps:<br /></p><ol><li><tt>yield</tt> sets the coroutine state to indicate termination.<br /><li>Control is transferred to the end of the coroutine body.<br /></ol>Once terminated, calls to <tt>is_complete()</tt> return true and the coroutine cannot be reentered.<br /></p><p>Note that a coroutine may also be implicitly terminated if the coroutine body is exited without a <tt>yield</tt>, e.g. by <tt>return</tt>, <tt>throw</tt> or by running to the end of the body.<br /></p><h3> fork <i>statement</i> ;</h3><p>The <tt>fork</tt> pseudo-keyword is used when "forking" a coroutine, i.e. splitting it into two (or more) copies. One use of <tt>fork</tt> is in a server, where a new coroutine is created to handle each client connection:<br /></p><pre>reenter (this)<br />{<br /> do<br /> {<br /> socket_.reset(new tcp::socket(io_service_));<br /> yield acceptor->async_accept(*socket_, *this);<br /> fork server(*this)();<br /> } while (is_parent());<br /> ... client-specific handling follows ...<br />}<br /></pre><p>The logical steps involved in a <tt>fork</tt> are:<br /></p><ol><li><tt>fork</tt> saves the current state of the coroutine.<br /><li>The statement creates a copy of the coroutine and either executes it immediately or schedules it for later execution.<br /><li>The resume point is defined immediately following the semicolon.<br /><li>For the "parent", control immediately continues from the next line.<br /></ol><p>The functions <tt>is_parent()</tt> and <tt>is_child()</tt> can be used to differentiate between parent and child. You would use these functions to alter subsequent control flow.<br /></p><p>Note that <tt>fork</tt> doesn't do the actual forking by itself. It is your responsibility to write the statement so that it creates a clone of the coroutine and calls it. The clone can be called immediately, as above, or scheduled for delayed execution using something like <tt>io_service::post()</tt>.<br /></p>chrishttp://www.blogger.com/profile/09159109667366328919[email protected]304tag:blogger.com,1999:blog-35024958.post-83467945371439654942009-08-12T20:02:00.007+10:002009-08-13T11:25:34.559+10:00Composed operations, coroutines and code makeover<p>In the previous <a href="http://blog.think-async.com/2009/07/wife-says-i-cant-believe-it-works.html">two</a> <a href="http://blog.think-async.com/2009/08/secret-sauce-revealed.html">posts</a>, I showed some nifty macros for doing clean and simple stackless coroutines with asio. Hold on to your hats, because in this post we'll see what these coroutines can really do for your asio programs.<br /></p><p>A <a href="http://www.boost.org/doc/libs/1_39_0/doc/html/boost_asio/overview/rationale.html">design goal</a> of asio is to provide a basis for further levels of abstraction. One of the ways to develop abstractions on top of asio is to create what I like to call <i>composed operations</i>. These are simply operations that are made up of calls to other lower-level operations. Asio already includes some composed operations to address common network programming problems: <tt>async_read</tt> and <tt>async_write</tt> to deal with short reads and writes; and <tt>async_read_until</tt> to perform delimited reads.<br /></p><p>As an example, let's say we want to write a composed operation that echoes all data received on a socket until an error occurs. The way I have done this in the past (and the way composed operations like <tt>async_read_until</tt> are written) is to implement the operation as a set of function objects:<br /></p><pre>template <typename Handler><br />struct echo_read_handler<br />{<br /> tcp::socket& socket;<br /> mutable_buffer working_buffer;<br /> Handler handler;<br /> void operator()(error_code ec, size_t length);<br />}<br /><br />template <typename Handler><br />struct echo_write_handler<br />{<br /> tcp::socket& socket;<br /> mutable_buffer working_buffer;<br /> Handler handler;<br /> void operator()(error_code ec, size_t length);<br />};<br /><br />template <typename Handler><br />void echo_read_handler::operator()(<br /> error_code ec, size_t length)<br />{<br /> if (!ec)<br /> {<br /> echo_write_handler write_handler =<br /> { socket, working_buffer, handler };<br /><br /> async_write(socket,<br /> buffer(working_buffer, length),<br /> write_handler);<br /> }<br /> else<br /> handler(ec);<br />}<br /><br />template <typename Handler><br />void echo_write_handler::operator()(<br /> error_code ec, size_t /*length*/)<br />{<br /> if (!ec)<br /> {<br /> echo_read_handler read_handler =<br /> { socket, working_buffer, handler };<br /><br /> socket.async_read_some(<br /> buffer(working_buffer),<br /> read_handler);<br /> }<br /> else<br /> handler(ec);<br />}<br /></pre><p>and a convenience function which acts as the public interface for the abstraction:<br /></p><pre>template <typename Handler><br />void async_echo(<br /> tcp::socket& socket,<br /> mutable_buffer working_buffer,<br /> Handler handler)<br />{<br /> echo_read_handler read_handler =<br /> { socket, working_buffer, handler };<br /><br /> socket.async_read_some(<br /> buffer(working_buffer),<br /> read_handler);<br />}<br /></pre><p>Not very encouraging if you want to write your own abstractions, is it? Now imagine you've been asked to develop a composed operation to send an email using SMTP. That would involve about a dozen lower level operations, so even I probably wouldn't bother if I had to use a function object approach.<br /></p><h3>Coroutines to the rescue</h3><p>In the previous two posts we already saw how to combine stackless coroutines with asio's asynchronous operations, simply by prepending the <tt>yield</tt> "keyword". I'm sure you know where this is going... We can also use a coroutine to implement a composed operation.<br /></p><p>Let's rewrite <tt>async_echo</tt> as a coroutine:<br /></p><pre>template <typename Handler><br />struct echo_coro<br />{<br /> tcp::socket& socket;<br /> mutable_buffer working_buffer;<br /> Handler handler;<br /> coroutine coro;<br /> void operator()(<br /> error_code ec = error_code(),<br /> size_t length = 0)<br /> {<br /> reenter (coro)<br /> {<br /> entry:<br /> while (!ec)<br /> {<br /> yield socket.async_read_some(<br /> buffer(working_buffer), *this);<br /><br /> if (ec) break;<br /><br /> yield async_write(socket,<br /> buffer(working_buffer, length), *this);<br /> }<br /><br /> handler(ec);<br /> }<br /> }<br />};<br /><br />template <typename Handler><br />void async_echo(<br /> tcp::socket& socket,<br /> mutable_buffer working_buffer,<br /> Handler handler)<br />{<br /> echo_coro coro = { socket, working_buffer, handler };<br /> coro();<br />}<br /></pre><p>The code is much shorter and clearer than the function object version. For an SMTP email operation the savings would be so much more, but I'll leave that as an exercise for the reader.<br /></p><p>Now you might think this next point is obvious, but I'm going to say it anyway and put it in bold because it's important:<br /></p><blockquote><b>The fact that the composed operation is implemented as a coroutine is <i>entirely transparent</i> to the caller</b>.<br /></blockquote><p>What does this mean? It means:<br /></p><ul><li>You can write your composed operations as coroutines, or not, as you choose.<br /><li>You can combine those composed operations still further using coroutines (or not).<br /></ul><p>And so on and so on, up through as many layers of abstraction as you think you can reasonably fit into your program.<br /></p><h3>An alternative approach</h3><p>One aspect of the implementation above still bothers me a little: repetition. Specifically, the repetition of the operation's template parameter list and the arguments (<tt>socket</tt>, <tt>working_buffer</tt> and <tt>handler</tt>) when defining the coroutine's function object.<br /></p><p>Here's an alternative design that implements the composed operation in a single function:<br /></p><pre>template <typename Handler><br />void async_echo(<br /> tcp::socket& socket,<br /> mutable_buffer working_buffer,<br /> Handler handler,<br /> // coroutine state:<br /> coroutine coro = coroutine(),<br /> error_code ec = error_code(),<br /> size_t length = 0)<br />{<br /> reenter (coro)<br /> {<br /> entry:<br /> while (!ec)<br /> {<br /> yield socket.async_read_some(<br /> buffer(working_buffer),<br /> bind(&async_echo<Handler>,<br /> ref(socket), working_buffer,<br /> box(handler), coro, _1, _2));<br /><br /> if (ec) break;<br /><br /> yield async_write(socket,<br /> buffer(working_buffer, length),<br /> bind(&async_echo<Handler>,<br /> ref(socket), working_buffer,<br /> box(handler), coro, _1, _2));<br /> }<br /><br /> handler(ec);<br /> }<br />}<br /></pre><p>(N.B. <tt>box()</tt> wraps the <tt>handler</tt> with another function object to prevent evaluation of the handler as a <a href="http://www.boost.org/doc/libs/1_39_0/libs/bind/bind.html#nested_binds">nested bind expression</a>.)<br /></p><p>Of course, we've just traded one type of repetition for another: the bind expressions to create the completion handlers. At this point, I think it's a matter of taste which approach you use.<br /></p><h3>Lambdas == code liposuction</h3><p>It's left to C++0x lambdas to make the coroutine-in-one-function approach the clear winner in brevity, and perhaps not in the way you first expect. Combined with <tt>auto</tt>, you can use lambdas as local functions to eliminate repeated code:<br /></p><pre>template <typename Handler><br />void async_echo(<br /> tcp::socket& socket,<br /> mutable_buffer working_buffer,<br /> Handler handler,<br /> // coroutine state:<br /> coroutine coro = coroutine(),<br /> error_code ec = error_code(),<br /> size_t length = 0)<br />{<br /> auto resume = [&]()<br /> {<br /> return bind(&async_echo<Handler>,<br /> ref(socket), working_buffer,<br /> box(handler), coro, _1, _2));<br /> };<br /><br /> reenter (coro)<br /> {<br /> entry:<br /> while (!ec)<br /> {<br /> yield socket.async_read_some(<br /> buffer(working_buffer),<br /> resume());<br /><br /> if (ec) break;<br /><br /> yield async_write(socket,<br /> buffer(working_buffer, length),<br /> resume());<br /> }<br /><br /> handler(ec);<br /> }<br />}<br /></pre><p>What we end up with is a composed operation in one function, a concise coroutine to specify the asynchronous control flow, and a single definition of how to reenter the coroutine.<br /></p><p>Phew. I think we're done.</p>chrishttp://www.blogger.com/profile/09159109667366328919[email protected]47tag:blogger.com,1999:blog-35024958.post-5976208108287125082009-08-10T22:52:00.003+10:002009-08-10T23:42:57.865+10:00Secret sauce revealed<p>In my <a href="http://blog.think-async.com/2009/07/wife-says-i-cant-believe-it-works.html">previous post</a>, I showed a little program using stackless coroutines with asio. Obviously there's no <tt>yield</tt> keyword in C++, so without further ado here's the preprocessor magic that makes it possible:<br /></p><pre>class coroutine<br />{<br />public:<br /> coroutine() : value_(0) {}<br />private:<br /> friend class coroutine_ref;<br /> int value_;<br />};<br /><br />class coroutine_ref<br />{<br />public:<br /> coroutine_ref(coroutine& c) : value_(c.value_) {}<br /> coroutine_ref(coroutine* c) : value_(c->value_) {}<br /> operator int() const { return value_; }<br /> int operator=(int v) { return value_ = v; }<br />private:<br /> int& value_;<br />};<br /><br />#define reenter(c) \<br /> switch (coroutine_ref _coro_value = c)<br /><br />#define entry \<br /> extern void you_forgot_to_add_the_entry_label(); \<br /> bail_out_of_coroutine: break; \<br /> case 0<br /><br />#define yield \<br /> if ((_coro_value = __LINE__) == 0) \<br /> { \<br /> case __LINE__: ; \<br /> (void)&you_forgot_to_add_the_entry_label; \<br /> } \<br /> else \<br /> for (bool _coro_bool = false;; \<br /> _coro_bool = !_coro_bool) \<br /> if (_coro_bool) \<br /> goto bail_out_of_coroutine; \<br /> else<br /></pre><p>Unlike the preprocessor-based coroutines presented <a href="http://www.chiark.greenend.org.uk/~sgtatham/coroutines.html">here</a>, the above macros let you yield from a coroutine without having to return from a function. Instead, the <tt>yield</tt> simply breaks you out of the <tt>reenter</tt> block. That trick is what allows us to write a server in one function.<br /></p><p>Yes, yes, I know. An echo server in a single function is a bit of a gimmick. The following snippet may give a better idea of how the coroutines can be used:<br /></p><pre>class session : coroutine<br />{<br />public:<br /> session(tcp::acceptor& acceptor)<br /> : acceptor_(acceptor),<br /> socket_(new tcp::socket(acceptor.get_io_service())),<br /> data_(new array<char, 1024>)<br /> {<br /> }<br /><br /> void operator()(<br /> error_code ec = error_code(),<br /> size_t length = 0)<br /> {<br /> reenter (this)<br /> {<br /> entry:<br /> for (;;)<br /> {<br /> yield acceptor_.async_accept(<br /> *socket_, *this);<br /><br /> while (!ec)<br /> {<br /> yield socket_->async_read_some(<br /> buffer(*data_), *this);<br /><br /> if (ec) break;<br /><br /> yield async_write(*socket_,<br /> buffer(*data_, length), *this);<br /> }<br /><br /> socket_->close();<br /> }<br /> }<br /> }<br /><br />private:<br /> tcp::acceptor& acceptor_;<br /> shared_ptr<tcp::socket> socket_;<br /> shared_ptr<array<char, 1024> > data_;<br />};<br /></pre><p>Compared to the usual <tt>boost::bind</tt>-based approach of doing callbacks, the control flow is all in one place and easy to follow.<br /></p><p>But wait, there's more... In the next post I'll reveal the real power you get when you combine stackless coroutines and asio.</p>chrishttp://www.blogger.com/profile/09159109667366328919[email protected]43tag:blogger.com,1999:blog-35024958.post-28543677049919083832009-07-29T23:04:00.007+10:002009-07-29T23:28:29.285+10:00Wife says: "I can't believe it works"<p>Just a teaser:<br /></p><pre>int main()<br />{<br /> try<br /> {<br /> using asio::ip::tcp;<br /> using namespace boost::lambda;<br /><br /> asio::io_service io_service;<br /> tcp::acceptor acceptor(io_service,<br /> tcp::endpoint(tcp::v4(), 54321));<br /><br /> const int max_clients = 100;<br /> coroutine coro[max_clients];<br /> std::auto_ptr<tcp::socket> socket[max_clients];<br /> asio::error_code ec[max_clients];<br /> std::size_t length[max_clients];<br /> boost::array<char, 1024> data[max_clients];<br /><br /> // Kick off all the coroutines.<br /> int n = -1;<br /> for (int i = 0; i < max_clients; ++i)<br /> {<br /> socket[i].reset(new tcp::socket(io_service));<br /> io_service.post(<br /> unlambda((<br /> var(n) = i<br /> )));<br /> }<br /><br /> for (; io_service.run_one() > 0; n = -1)<br /> {<br /> if (n != -1)<br /> {<br /> reenter (coro[n])<br /> {<br /> entry:<br /> for (;;)<br /> {<br /> // Wait for a client to connect.<br /> yield acceptor.async_accept(<br /> *socket[n],<br /> unlambda((<br /> var(n) = n,<br /> var(ec[n]) = _1<br /> )));<br /><br /> // Echo at will.<br /> while (!ec[n])<br /> {<br /> yield socket[n]->async_read_some(<br /> asio::buffer(data[n]),<br /> unlambda((<br /> var(n) = n,<br /> var(ec[n]) = _1,<br /> var(length[n]) = _2<br /> )));<br /><br /> if (!ec[n])<br /> {<br /> yield asio::async_write(<br /> *socket[n],<br /> asio::buffer(data[n], length[n]),<br /> unlambda((<br /> var(n) = n,<br /> var(ec[n]) = _1<br /> )));<br /> }<br /> }<br /><br /> // Clean up before accepting next client.<br /> socket[n]->close();<br /> }<br /> }<br /> }<br /> }<br /> }<br /> catch (std::exception& e)<br /> {<br /> std::cerr << "Exception: " << e.what() << "\n";<br /> }<br />}<br /></pre><p>One function. One fully asynchronous server. Bog standard C++.<br /></p>chrishttp://www.blogger.com/profile/09159109667366328919[email protected]26tag:blogger.com,1999:blog-35024958.post-28353954963997791812009-07-14T21:36:00.007+10:002009-07-14T23:01:41.738+10:00User-friendly compile errors for templates in C++0x<p>The C++0x features <tt>decltype</tt>, <tt>static_assert</tt> and the "new function declarator syntax" can be combined with our old friend <a href="http://en.wikipedia.org/wiki/SFINAE">SFINAE</a> to generate nicer template compile errors.<br /></p><p>As a simple example, consider a container class similar to <tt>std::set</tt>. Normally if you just declare a variable<br /></p><pre>set<my_type> s;<br /></pre><p>it will compile without error even if <tt>my_type</tt> has no <tt>operator<</tt>. You will only get an error when you try to call a set member function, such as <tt>insert()</tt>. Worse still, the errors tend to be quite verbose. (Too verbose for me to want to paste here, anyway.) It would be really nice to generate a short, readable error at the point of the original variable declaration. Let's see how we can do just that in C++0x.<br /></p><p>First, we need to write a compile-time test for <tt>operator<</tt>. This is where SFINAE, <tt>decltype</tt> and the new function declarator syntax come together. We write the test function:<br /></p><pre>auto less_than_test(const T* t)<br /> -> decltype(*t < *t, char(0));<br /></pre><p>and the fallback overload:<br /></p><pre>std::array<char, 2> less_than_test(...);<br /></pre><p>The trick here is that, according to the C++0x grammar, we have:<br /></p><pre><b>decltype</b> <b>(</b> <i>expression</i> <b>)</b><br /></pre><p>and <br /></p><pre><i>expression:</i><br /> <i>assignment-expression</i><br /> <i>expression</i> <b>,</b> <i>assignment-expression</i><br /></pre><p>This means that the first overload uses <tt>decltype</tt> to do two things: it makes the overload a viable candidate only if the expression <tt>*t < *t</tt> is valid; and it says the overload returns a <tt>char</tt>.<br /></p><p>Second, we can use <tt>sizeof</tt> to determine which of the overloads is selected for a given type <tt>T</tt>, and <tt>static_assert</tt> to generate a readable error:<br /></p><pre>template <typename T><br />class set<br />{<br />public:<br /> static_assert(<br /> sizeof(less_than_test((T*)0)) == 1,<br /> "type T must provide operator<");<br />};<br /></pre><p>The g++ 4.4 compiler then gives the following output on the original variable declaration:<br /></p><pre>test.cpp: In instantiation of set<my_type><br />test.cpp:21: instantiated from here<br />test.cpp:13: error: static assertion failed:<br /> "type T must provide operator<"<br /></pre><p>It works with function templates too. To add a check to Asio's <tt>async_read</tt> function's <tt>ReadHandler</tt> parameter, I could write the check as follows:<br /></p><pre>template <typename T><br />auto read_handler_test(T* t)<br /> -> decltype(<br /> (*t)(<br /> *(const error_code*)0,<br /> (const std::size_t)0),<br /> char(0));<br /><br />std::array<char, 2> read_handler_test(...);<br /><br />template <..., typename ReadHandler><br />void async_read(..., ReadHandler handler)<br />{<br /> static_assert(<br /> sizeof(read_handler_test(&handler)) == 1,<br /> "ReadHandler type requirements not met");<br /> ...<br />}<br /></pre><p>Perhaps with a touch of macro magic, checks of this sort could become quite easy to write.<br /></p><p>"Hang on, what about C++0x concepts?" I hear you ask. What are they? <tt>;-)</tt></p>chrishttp://www.blogger.com/profile/09159109667366328919[email protected]26tag:blogger.com,1999:blog-35024958.post-22345331188415637322008-10-06T23:58:00.010+11:002008-10-07T10:43:57.343+11:00Asynchronous Fork/Join using Asio<p>As most Asio users will no doubt be aware, multiple threads can call <tt>io_service::run()</tt> to set up a pool of threads from which the completion handlers will be executed. This can be used in conjunction with <tt>io_service::post()</tt> to <a href="https://tenermerx.com/Asio/Recipes#A_thread_pool_for_executing_arbi">execute arbitrary tasks in the thread pool</a>.</p><p>In some rare spare moments I have used this facility to dabble in parallel algorithms (mainly to do with sorting large data sets). However, I was not completely satisfied with its ease-of-use when it came to implementing the algorithms.</p><p>Recently I came across the new <a href="http://gee.cs.oswego.edu/dl/papers/fj.pdf">Fork/Join framework</a> that's going to be included in Java 7. I was particularly struck by the simplicity of the <tt>coinvoke()</tt> function, and was inspired to implement something similar on top of Asio. Of course, what with Asio and my preferred mode of thinking, I wanted to implement an asynchronous version.</p><h3>And the result...</h3><p>I created a function template that may be used to initiate two or more tasks to run in parallel:</p><pre>template <typename TaskCont0, ..., typename TaskContN,<br /> typename Task0, ..., typename TaskN, Cont><br />void coinvoke(asio::io_service& io_service,<br /> Task0 task0, ..., TaskN taskN, Cont cont);</pre><p>Each task must be a function object with a single argument, where the argument is the continuation function object for the task. The <tt>TaskContN</tt> template parameters explicitly specify the function signatures used for each of the task continuations. For example:</p><pre>coinvoke<void(int), void(int)>(task0, task1, cont);</pre><p>says that both tasks have a continuation with the signature <tt>void(int)</tt>. The combining continuation has a signature that is the concatenation of all of the task continuations' arguments. In the above example, that's <tt>void(int, int)</tt>.</p><p>The operation of <tt>coinvoke()</tt> works as follows (click image for full size view):</p><p><a href="http://tenermerx.com/Pub/Asio/AsyncForkJoin/coinvoke.png"><img width="425" src="http://tenermerx.com/Pub/Asio/AsyncForkJoin/coinvoke.png" /></a></p><p>You can get the implementation <a href="http://tenermerx.com/Pub/Asio/AsyncForkJoin/coinvoke.hpp">here</a>. Don't expect the source to be readable; it contains hairy uses of template metaprogramming and preprocessor magic.</p><h3>Why continuations?</h3><p>You might be wondering why each task passes its result to a continuation function rather than simply returning it. The answer to that is that a task need not be a single calcuation; it could instead be the start of a chain of asynchronous operations. This means that <tt>coinvoke()</tt> could be used to simplify management of parallel operations, such as writing data to multiple sockets, and not having the handler called until all operations have finished. I plan to explore those and other related ideas further in the near future, but for now let's just look at parallel algorithms.</p><h3>Fibonacci revisited</h3><p>The equivalent implementation of the Fibonacci example from the Java Fork/Join paper looks like:</p><pre>void combine_fib(<br /> int a, int b,<br /> function<void(int)> h)<br />{<br /> h(a + b);<br />}<br /><br />void calc_fib(<br /> asio::io_service& io_service,<br /> int n,<br /> function<void(int)> f)<br />{<br /> if (n <= threshold)<br /> {<br /> f(seq_fib(n));<br /> }<br /> else<br /> {<br /> coinvoke<void(int), void(int)>(io_service,<br /> bind(calc_fib, ref(io_service), n - 1, _1),<br /> bind(calc_fib, ref(io_service), n - 2, _1),<br /> bind(combine_fib, _1, _2, f));<br /> }<br />}</pre><h3>Can I have C++0x lambdas now, please?</h3><p>The need to define a separate <tt>combine_fib</tt> is not ideal, since a key part of the algorithm is off in another spot. Fortunately, C++0x's new monomorphic lambdas come to the rescue:</p><pre>void calc_fib(<br /> asio::io_service& io_service,<br /> int n,<br /> function<void(int)> f)<br />{<br /> if (n <= threshold)<br /> {<br /> f(seq_fib(n));<br /> }<br /> else<br /> {<br /> coinvoke<void(int), void(int)>(io_service,<br /> [&io_service, =n](function<void(int)> c)<br /> {<br /> calc_fib(io_service, n - 1, c),<br /> },<br /> [&io_service, =n](function<void(int)> c)<br /> {<br /> calc_fib(io_service, n - 2, c),<br /> },<br /> [=f](int a, int b)<br /> {<br /> f(a + b);<br /> });<br /> }<br />}</pre><h3>A useful example</h3><p>Since that has to come close to being the most convoluted way of calculating a Fibonacci value, here is an example where <tt>coinvoke()</tt> is used for a parallel merge sort:</p><pre>template <typename Iterator><br />void merge(<br /> Iterator begin,<br /> Iterator middle,<br /> Iterator end,<br /> function<void()> f)<br />{<br /> std::inplace_merge(begin, middle, end);<br /> f();<br />}<br /><br />template <typename Iterator><br />void sort(<br /> asio::io_service& io_service,<br /> Iterator begin,<br /> Iterator end,<br /> function<void()> f)<br />{<br /> std::size_t n = end - begin;<br /> if (n <= 16384)<br /> {<br /> std::sort(begin, end);<br /> io_service.post(f);<br /> }<br /> else<br /> {<br /> coinvoke<void(), void()>(io_service,<br /><br /> // First task sorts the initial half of the range.<br /> bind(&sort<Iterator>,<br /> ref(io_service),<br /> begin, begin + n / 2, _1),<br /><br /> // Second task sorts the latter half of the range.<br /> bind(&sort<Iterator>,<br /> ref(io_service),<br /> begin + n / 2, end, _1),<br /><br /> // Continuation function merges the two sorted ranges.<br /> bind(&merge<Iterator>,<br /> begin, begin + n / 2, end, f)<br /><br /> );<br /> }<br />}</pre><p>On my 8-core machine, this gives a little more than a threefold speedup in sorting large vectors.</p>chrishttp://www.blogger.com/profile/09159109667366328919[email protected]34tag:blogger.com,1999:blog-35024958.post-14708663747574457502008-06-27T11:49:00.002+10:002008-06-27T11:58:11.498+10:00Mention in Stroustrup Interview<a href="http://www.computerworld.com.au/index.php/id;408408016;pp;1;fp;16;fpid;1">The A-Z of Programming Languages: C++</a>, top of page 5:<br /><blockquote><br /><span style="font-style: italic;"><span style="font-weight: bold;">Do you feel that resources like the boost libraries will provide this functionality/accessibility for C++?</span></span><br /><br /><span style="font-style: italic;">Some of the boost libraries - especially the networking library - are a good beginning. The C++0x standard threads look a lot like boost threads. If at all possible, a C++ programmer should begin with an existing library (and/or tool), rather than building directly on fundamental language features and/or system threads.</span><br /></blockquote><br />Not by name, but hey! The rest of the interview is worth reading too. <tt>;)</tt>chrishttp://www.blogger.com/profile/09159109667366328919[email protected]12tag:blogger.com,1999:blog-35024958.post-23365618699551456432008-05-23T08:05:00.015+10:002008-06-02T12:55:43.133+10:00Boost.Asio vs Asio<p>Sometimes I am asked what the difference is between the (non-Boost) Asio and Boost.Asio packages I provide. Here is the definitive word on the subject, presented as a series of questions and answers.</p><h3>What are the differences in the source code?</h3><p>— Asio is in a namespace called <tt>asio::</tt>, whereas Boost.Asio puts everything under <tt>boost::asio::</tt>.</p><p>— The main Asio header file is called <tt>asio.hpp</tt>. The corresponding header in Boost.Asio is <tt>boost/asio.hpp</tt>. All other headers are similarly changed.</p><p>— Any macros used by or defined in Asio are prefixed with <tt>ASIO_</tt>. In Boost.Asio they are prefixed with <tt>BOOST_ASIO_</tt>.</p><p>— Asio includes a class for launching threads, <tt>asio::thread</tt>. Boost.Asio does not include this class, to avoid overlap with the Boost.Thread library</p><p>— Boost.Asio uses the Boost.System library to provide support for error codes (<tt>boost::system::error_code</tt> and <tt>boost::system::system_error</tt>). Asio includes these under its own namespace (<tt>asio::error_code</tt> and <tt>asio::system_error</tt>). The Boost.System version of these classes currently supports better extensibility for user-defined error codes.</p><p>— Asio is header-file-only and for most uses does not require linking against any Boost library. Boost.Asio always requires that you link against the Boost.System library, and also against Boost.Thread if you want to launch threads using <tt>boost::thread</tt>.</p><h3>Where do I get a release package?</h3><p>Asio is available for download from <a href="http://asio.sourceforge.net/">sourceforge</a>, in a package named <tt>asio-X.Y.Z.tar.gz</tt> (or <tt>.tar.bz2</tt> or <tt>.zip</tt>).</p><p>Boost.Asio is included in the Boost 1.35 distribution. It is also available as a separate package on sourceforge, named <tt>boost_asio_X_Y_Z.tar.gz</tt>. The latter is intended to be copied over the top of an existing Boost source code distribution.</p><h3>Where are the source code repositories?</h3><p>Asio uses a sourceforge-hosted CVS repository. Details of how to access it may be found <a href="http://sourceforge.net/cvs/?group_id=122478">here</a>. It may also be <a href="http://asio.cvs.sourceforge.net/">browsed via the web</a>.</p><p>Boost.Asio is checked into <a href="http://svn.boost.org/">Boost's subversion repository</a>.</p><h3>How do you maintain both versions?</h3><p>All development is done in the Asio CVS repository. I periodically convert the source into Boost format using a script called <a href="http://asio.cvs.sourceforge.net/asio/asio/boostify.pl?view=markup"><tt>boostify.pl</tt></a>, and merge the changes into the Boost subversion repository.</p><h3>Will Asio be discontinued now that Boost.Asio is included with Boost?</h3><p>No. There are projects using Asio and they will continue to be supported. I also prefer to use Asio over Boost.Asio in my own projects, for the convenience of header-file-only and shorter namespaces.<br /></p><h3>Should I use Asio or Boost.Asio?</h3><p>It depends. Here are some things to consider:<br /></p><p>— If you (like me) prefer the convenience of header-file-only libraries then I'd suggest using Asio over Boost.Asio.</p>— If you must use a version of Boost older than 1.35 then Boost.Asio is not included. You can use Boost.Asio by copying it over the top of your Boost distribution (see above), but not everyone is comfortable doing this. In that case, I would suggest using Asio over Boost.Asio.<p></p><p>— I will be creating new versions of both the Asio and Boost.Asio packages on a faster release cycle than that followed by Boost. If you want to use the latest features you can still use Boost.Asio as long as you are happy to copy it over the top of your Boost distribution. If you don't want to do this, use Asio rather than Boost.Asio.</p><h3>Can Asio and Boost.Asio coexist in the same program?</h3><p>Yes. Since they use different namespaces there should be no conflicts, although obviously the types themselves are not interchangeable. (In case you're wondering why you might want to do this, consider a situation where a program is using third party libraries that are also using Asio internally.)</p>chrishttp://www.blogger.com/profile/09159109667366328919[email protected]18tag:blogger.com,1999:blog-35024958.post-41777220573832425172008-03-30T22:09:00.003+11:002008-03-30T22:15:54.602+11:00739 days ago ...... asio was <a href="http://lists.boost.org/Archives/boost/2006/03/102287.php">accepted into Boost</a>. Today you can find it as part of a <a href="http://www.boost.org/users/news/version_1_35_0">Boost release</a>. Woohoo!chrishttp://www.blogger.com/profile/09159109667366328919[email protected]9tag:blogger.com,1999:blog-35024958.post-90912146692744614842007-08-08T23:00:00.000+10:002007-08-09T00:37:51.019+10:00Time TravelMany event-driven programs involve state changes that are triggered according to the system clock. You might be coding for:<ul><br /><li> A share market that opens at 10:00am and closes at 4:00pm.</li><br /><li> An off-peak phone billing rate that starts after 7:00pm.</li><br /><li> An interest calculation that is run on the last day of every month.</li><br /></ul>The <code>asio::deadline_timer</code> class lets you handle this easily. For example:<br /><pre>using namespace boost::posix_time;<br />typedef boost::date_time::c_local_adjustor<ptime> local_adj;<br /><br />...<br /><br />asio::deadline_timer timer(io_service);<br /><br />ptime open_time(second_clock::local_time().date(), hours(10));<br />timer.expires_at(local_adj::local_to_utc(open_time));<br />timer.async_wait(open_market);<br /></pre>There's a catch: to test that your timer events work correctly, you have to run your program at the right time of day. It usually isn't practical to sit around all day (or, worse, all year) waiting for the timers to expire.<br /><br /><h3>Time Traits</h3><br />You may have noticed that the <code>asio::deadline_timer</code> class is actually a typedef:<br /><pre>typedef basic_deadline_timer<boost::posix_time::ptime><br /> deadline_timer;</pre>where the basic_deadline_timer class template is declared as follows:<br /><pre>template <<br /> typename Time,<br /> typename TimeTraits<br /> = asio::time_traits<Time>,<br /> typename TimerService<br /> = deadline_timer_service<Time, TimeTraits> ><br />class basic_deadline_timer;<br /></pre>In the context of our problem, the most interesting template parameter is the second one: <code>TimeTraits</code>. An implementation of <code>TimeTraits</code> lets us customise the treatment of the template's <code>Time</code> parameter, and consequently the behaviour of the timer itself.<br /><br />A <code>TimeTraits</code> class must implement an interface that matches the following:<br /><pre>class TimeTraits<br />{<br />public:<br /> // The type used to represent an absolute time, i.e. the same<br /> // as the Time template parameter to basic_deadline_timer.<br /> typedef ... time_type;<br /><br /> // The type used to represent the difference between two<br /> // absolute times.<br /> typedef ... duration_type;<br /><br /> // Returns the current time.<br /> static time_type now();<br /><br /> // Returns a new absolute time resulting from adding the<br /> // duration d to the absolute time t.<br /> static time_type add(time_type t, duration_type d);<br /><br /> // Returns the duration resulting from subtracting t2 from t1.<br /> static duration_type subtract(time_type t1, time_type t2);<br /><br /> // Returns whether t1 is to be treated as less than t2.<br /> static bool less_than(time_type t1, time_type t2);<br /><br /> // Returns a "posix" duration corresponding to the duration d.<br /> static boost::posix_time::time_duration to_posix_duration(<br /> duration_type d);<br />};</pre>As you can see from the declaration of the <code>basic_deadline_timer</code> class template, Asio provides a default <code>TimeTraits</code> implementation called <code>asio::time_traits<></code>.<br /><br /><h3>Offsetting Now</h3><br />To test our timer events at any time of our choosing, we simply need to change the definition of "now" using a custom <code>TimeTraits</code> class.<br /><br />Since we want to use the same time types as the regular <code>deadline_timer</code> class, we'll start by reusing the default traits implementation:<br /><pre>class offset_time_traits<br /> : public asio::deadline_timer::traits_type<br />{<br />};</pre>The value returned by the <code>now()</code> function will be offset from the system clock by a specified duration:<br /><pre>class offset_time_traits<br /> : public asio::deadline_timer::traits_type<br />{<br /><br />private:<br /> <font color="red">static duration_type offset_;</font><br />};</pre>which is simply added to the system clock:<br /><pre>class offset_time_traits<br /> : public asio::deadline_timer::traits_type<br />{<br />public:<br /> <font color="red">static time_type now()<br /> {<br /> return add(asio::deadline_timer::traits_type::now(), offset_);<br /> }</font><br /><br />private:<br /> static duration_type offset_;<br />};</pre>Of course, we will also need to provide a way to set the offset, which can be done by setting an initial value for "now":<br /><pre>class offset_time_traits<br /> : public asio::deadline_timer::traits_type<br />{<br />public:<br /> static time_type now()<br /> {<br /> return add(asio::deadline_timer::traits_type::now(), offset_);<br /> }<br /><br /> <font color="red">static void set_now(time_type t)<br /> {<br /> offset_ =<br /> subtract(t, asio::deadline_timer::traits_type::now());<br /> }</font><br /><br />private:<br /> static duration_type offset_;<br />};</pre><br /><h3>Creating a Timer</h3><br />To use our custom traits type with the <code>basic_deadline_timer</code> template, we simply need to add the following typedef:<br /><pre>typedef asio::basic_deadline_timer<<br /> boost::posix_time::ptime, offset_time_traits> offset_timer;</pre>To see the offset timer in action, let's create a timer to fire precisely at the start of the coming new year. So we don't have to wait until then, we'll set "now" to be just ten seconds prior to midnight:<br /><pre>offset_time_traits::set_now(<br /> boost::posix_time::from_iso_string("20071231T235950"));<br /><br />offset_timer timer(io_service);<br />timer.expires_at(<br /> boost::posix_time::from_iso_string("20080101T000000"));<br />timer.async_wait(handle_timeout);<br /><br />io_service.run();</pre>When the program is run, it will take just ten seconds to complete.<br /><br /><h3>Jumping Through Time</h3><br />One feature not supported by the above solution is the ability to change the definition of "now" after the timers have been started. However, if your timer events are spread across a long period of time, then this is likely to be something you would want.<br /><br />Let's say that the next timer does not expire for several hours, but in an attempt to speed things up we call <code>set_now()</code> to move to just seconds before. The problem with the above traits class is that the existing asynchronous wait operation does not know about the change to "now", and so will continue to run for the remaining hours.<br /><br />Fortunately, Asio provides a way around this: by customising the <code>to_posix_duration()</code> function in our traits class.<br /><br />The <code>to_posix_duration()</code> function is normally used to convert from a user-defined duration type to a type that Asio knows about (namely <code>boost::posix_time::time_duration</code>). The key point here is that this converted duration value is used by Asio to determine how long to wait until the timer expires. Furthermore, it doesn't matter if this function returns a duration that is smaller (even substantially so) than the actual duration. The timer won't fire early, because Asio guarantees that it won't expire until the following condition holds true:<br /><pre>!TimeTraits::less_than(Time_Traits::now(), timer.expires_at())</pre>So, by adding the <code>to_posix_duration()</code> function to our traits class:<br /><pre>class offset_time_traits<br /> : public asio::deadline_timer::traits_type<br />{<br />public:<br /> static time_type now()<br /> {<br /> return add(asio::deadline_timer::traits_type::now(), offset_);<br /> }<br /><br /> static void set_now(time_type t)<br /> {<br /> offset_ =<br /> subtract(t, asio::deadline_timer::traits_type::now());<br /> }<br /><br /> <font color="red">static boost::posix_time::time_duration to_posix_duration(<br /> duration_type d)<br /> {<br /> return d < boost::posix_time::seconds(5)<br /> ? d : boost::posix_time::seconds(5);<br /> }</font><br /><br />private:<br /> static duration_type offset_;<br />};</pre>we can ensure that Asio detects changes to the offset within seconds.chrishttp://www.blogger.com/profile/09159109667366328919[email protected]14tag:blogger.com,1999:blog-35024958.post-72362291298372145962007-04-26T23:57:00.000+10:002007-04-27T00:42:27.772+10:00New home heating solutionFor quite some time I have wanted to take a really good look at improving Boost.Asio's scalability across multiple processors. Unfortunately, getting unlimited access to this sort of hardware has been somewhat problematic. What I really needed was a decent multiprocessor box at home :)<br /><br />The arrival of Intel's Clovertown quad core CPUs gave me the opportunity. The primary goal was to maximise parallelism while minimising the cost, and the lowest spec quad cores were cheap enough for me to justify spending the money. So, after months of thinking (and weeks of waiting for parts), last week I finally completed my home-built server.<br /><br />Here are the headline specs:<ul><br /><li> Two Intel Xeon E5310 quad core processors (1.6 GHz)<br /><br /><li> Tyan Tempest i5000XL motherboard<br /><br /><li> 2GB DDR2-667 fully buffered ECC DIMMs<br /><br /><li> OCZ GameXStream 700W power supply (OK, OK, it's a little overpowered, but it was in stock!)<br /><br /><li> Other stuff like case, hard disk, DVD drive, video card and wireless LAN card<br /><br /><li> Lots of fans to provide soothing ambient noise<br /><br /></ul>So far I have installed CentOS Linux 5 on it, but also plan to try Solaris 10 and FreeBSD. It seems pretty snappy.chrishttp://www.blogger.com/profile/09159109667366328919[email protected]13tag:blogger.com,1999:blog-35024958.post-9931900146425513462007-01-15T17:44:00.000+11:002007-01-15T19:09:35.539+11:00Unbuffered socket iostreamsBoost.Asio includes an iostreams-based interface to TCP sockets, <code>ip::tcp::iostream</code>, for simple use cases. However, like the file iostreams provided by the standard library, <code>ip::tcp::iostream</code> buffers input and output data. This can lead to problems if you forget to explicitly flush the stream. For example, consider the following code to perform an HTTP request:<br /><pre>ip::tcp::iostream stream("www.boost.org", "http");<br />stream << "GET / HTTP/1.0\r\n"<br /> << "Host: www.boost.org\r\n"<br /> << "\r\n";<br /><br />std::string response_line;<br />std::getline(stream, response_line);<br />...</pre>The code will be stuck on the <code>getline()</code> call waiting for the response, because the request will still be sitting <code>stream</code>'s output buffer. The correct code looks like this:<br /><pre>ip::tcp::iostream stream("www.boost.org", "http");<br />stream << "GET / HTTP/1.0\r\n"<br /> << "Host: www.boost.org\r\n"<br /> << "\r\n"<br /> <font color="red"><< std::flush</font>;</pre>The <code>std::flush</code> will cause the stream to send the entire contents of its output buffer at that point.<br /><br />Boost.Asio now supports an alternative solution: turn off the stream's output buffering. This is accomplished as follows:<br /><pre>ip::tcp::iostream stream("www.boost.org", "http");<br /><font color="red">stream.rdbuf()->pubsetbuf(0, 0);</font><br />stream << "GET / HTTP/1.0\r\n"<br /> << "Host: www.boost.org\r\n"<br /> << "\r\n";</pre>Now you can send and receive to your heart's content, without having to worry about whether your message is stuck in the output buffer, but be warned: an unbuffered stream is a lot less efficient in terms of system calls. Don't use this feature if you care about performance.chrishttp://www.blogger.com/profile/09159109667366328919[email protected]16tag:blogger.com,1999:blog-35024958.post-1196762045383729972006-11-10T09:33:00.000+11:002007-01-14T18:36:05.541+11:00Buffer debuggingSome standard library implementations, such as the one that ships with MSVC 8.0, provide a nifty feature called iterator debugging. What this means is that the validity of your iterators is checked at runtime. If you try to use an iterator that has been invalidated, you'll get an assertion. For example:<br /><pre>std::vector<int> v(1)<br />std::vector<int>::iterator i = v.begin();<br />v.clear(); // invalidates iterators<br />*i = 0; // assertion!</pre>Boost.Asio now takes advantage of this feature to add buffer debugging. Consider the following code:<br /><pre>void dont_do_this()<br />{<br /> std::string msg = "Hello, world!";<br /> asio::async_write(sock, asio::buffer(msg), my_handler);<br />}</pre>When you call an asynchronous read or write you need to ensure that the buffers for the operation are valid until the completion handler is called. In the above example, the buffer is the <code>std::string</code> variable <code>msg</code>. This variable is on the stack, and so it goes out of scope before the asynchronous operation completes. If you're lucky, your application will crash. Often you will get random failures.<br /><br />With the new buffer debug checking, however, Boost.Asio stores an iterator into the string until the asynchronous operation completes, and then dereferences it to check its validity. In the above example you get an assertion failure just before Boost.Asio tries to call the completion handler.<br /><br />This feature has only been tested with MSVC 8.0 so far, but it should work with any other implementation that supports iterator debugging. Obviously there's a performance cost to this checking, so it's only enabled in debug builds. You can also explicitly disable it by defining <code>BOOST_ASIO_DISABLE_BUFFER_DEBUGGING</code> (or <code>ASIO_DISABLE_BUFFER_DEBUGGING</code> if you're using standalone asio).chrishttp://www.blogger.com/profile/09159109667366328919[email protected]16tag:blogger.com,1999:blog-35024958.post-52697443507046787242006-10-07T00:46:00.000+10:002006-10-07T00:50:19.953+10:00FreeBSD supportAsio has now been tested successfully on FreeBSD 6.0, and should support FreeBSD 5.5 and later. FreeBSD 5.4 and earlier are not supported since, according to the man pages, getaddrinfo is not thread-safe.chrishttp://www.blogger.com/profile/09159109667366328919[email protected]14tag:blogger.com,1999:blog-35024958.post-1159275145328217172006-09-26T22:26:00.000+10:002006-09-26T22:52:25.336+10:00SSL password callbacksOn the weekend I made some changes to asio to support password callbacks for SSL. There is a new function on the <code>asio::ssl::context</code> class called <code>set_password_callback()</code>, which takes a function object with the following signature:<br /><pre>std::string password_callback(<br /> std::size_t max_length,<br /> ssl::context::password_purpose purpose);</pre>The callback must return the password as a string. The <code>max_length</code> argument indicates the maximum allowable length of the password, and if the returned string is longer it will be truncated. The <code>context::password_purpose</code> type is an enum with values <code>for_reading</code> and <code>for_writing</code>. In most cases you won't need to use the <code>max_length</code> or <code>purpose</code> arguments, and if you use <code>boost::bind()</code> to create the function object you can just leave them off. For example, the SSL server sample included with asio now has the following:<br /><pre>context_.set_password_callback(<br /> boost::bind(&server::get_password, this));<br /><br />...<br /><br />std::string get_password() const<br />{<br /> return "test";<br />}</pre>The final thing to note is that the password callback needs to be set before calling any <code>ssl::context</code> functions that load keys, such as <code>use_private_key_file()</code>.chrishttp://www.blogger.com/profile/09159109667366328919[email protected]32tag:blogger.com,1999:blog-35024958.post-1159240135560638692006-09-26T13:00:00.000+10:002006-09-26T13:08:55.570+10:00What's this all about?Greetings, reader. I have a blog. Now what? Well, the plan is to post ideas, tips and tricks, design thoughts, and anything else related to C++, Boost.Asio and programming that happens to take my interest.chrishttp://www.blogger.com/profile/09159109667366328919[email protected]25