]>
git.proxmox.com Git - ceph.git/blob - ceph/src/boost/libs/fiber/examples/adapt_nonblocking.cpp
1 // Copyright Nat Goodspeed 2015.
2 // Distributed under the Boost Software License, Version 1.0.
3 // (See accompanying file LICENSE_1_0.txt or copy at
4 // http://www.boost.org/LICENSE_1_0.txt)
6 #include <boost/fiber/all.hpp>
11 #include <algorithm> // std::min()
12 #include <errno.h> // EWOULDBLOCK
16 /*****************************************************************************
17 * example nonblocking API
18 *****************************************************************************/
20 class NonblockingAPI
{
24 // nonblocking operation: may return EWOULDBLOCK
25 int read( std::string
& data
, std::size_t desired
);
29 // for simulating a real nonblocking API
30 void set_data( std::string
const& data
, std::size_t chunksize
);
31 void inject_error( int ec
);
37 std::size_t chunksize_
;
42 /*****************************************************************************
43 * fake NonblockingAPI implementation... pay no attention to the little man
44 * behind the curtain...
45 *****************************************************************************/
46 NonblockingAPI::NonblockingAPI() :
52 void NonblockingAPI::set_data( std::string
const& data
, std::size_t chunksize
) {
54 chunksize_
= chunksize
;
55 // This delimits the start of a new test. Reset state.
60 void NonblockingAPI::inject_error( int ec
) {
64 int NonblockingAPI::read( std::string
& data
, std::size_t desired
) {
69 // copy injected_ because we're about to reset it
70 auto injected( injected_
);
72 // after an error situation, restart success count
78 // no injected error, but the resource isn't yet ready
82 // tell caller there's nothing left
83 if ( data_
.empty() ) {
87 // okay, finally have some data
88 // but return minimum of desired and chunksize_
89 std::size_t size( ( std::min
)( desired
, chunksize_
) );
90 data
= data_
.substr( 0, size
);
91 // strip off what we just returned
92 data_
= data_
.substr( size
);
93 // reset I/O retries count for next time
99 /*****************************************************************************
101 *****************************************************************************/
102 //[nonblocking_read_chunk
103 // guaranteed not to return EWOULDBLOCK
104 int read_chunk( NonblockingAPI
& api
, std::string
& data
, std::size_t desired
) {
106 while ( EWOULDBLOCK
== ( error
= api
.read( data
, desired
) ) ) {
107 // not ready yet -- try again on the next iteration of the
108 // application's main loop
109 boost::this_fiber::yield();
115 //[nonblocking_read_desired
116 // keep reading until desired length, EOF or error
117 // may return both partial data and nonzero error
118 int read_desired( NonblockingAPI
& api
, std::string
& data
, std::size_t desired
) {
119 // we're going to accumulate results into 'data'
123 while ( data
.length() < desired
&&
124 ( error
= read_chunk( api
, chunk
, desired
- data
.length() ) ) == 0) {
131 //[nonblocking_IncompleteRead
132 // exception class augmented with both partially-read data and errorcode
133 class IncompleteRead
: public std::runtime_error
{
135 IncompleteRead( std::string
const& what
, std::string
const& partial
, int ec
) :
136 std::runtime_error( what
),
141 std::string
get_partial() const {
145 int get_errorcode() const {
150 std::string partial_
;
156 // read all desired data or throw IncompleteRead
157 std::string
read( NonblockingAPI
& api
, std::size_t desired
) {
159 int ec( read_desired( api
, data
, desired
) );
161 // for present purposes, EOF isn't a failure
162 if ( 0 == ec
|| EOF
== ec
) {
166 // oh oh, partial read
167 std::ostringstream msg
;
168 msg
<< "NonblockingAPI::read() error " << ec
<< " after "
169 << data
.length() << " of " << desired
<< " characters";
170 throw IncompleteRead( msg
.str(), data
, ec
);
174 int main( int argc
, char *argv
[]) {
176 const std::string
sample_data("abcdefghijklmnopqrstuvwxyz");
178 // Try just reading directly from NonblockingAPI
179 api
.set_data( sample_data
, 5);
181 int ec
= api
.read( data
, 13);
182 // whoops, underlying resource not ready
183 assert(ec
== EWOULDBLOCK
);
184 assert(data
.empty());
187 api
.set_data( sample_data
, 5);
188 data
= read( api
, 13);
189 assert(data
== "abcdefghijklm");
192 api
.set_data( sample_data
, 5);
193 // don't accidentally pick either EOF or EWOULDBLOCK
195 assert(EWOULDBLOCK
!= 1);
199 data
= read( api
, 13);
200 } catch ( IncompleteRead
const& e
) {
201 thrown
= e
.get_errorcode();
205 std::cout
<< "done." << std::endl
;