]> git.proxmox.com Git - ceph.git/blob - ceph/src/boost/libs/fiber/examples/adapt_nonblocking.cpp
update sources to v12.2.3
[ceph.git] / 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)
5
6 #include <boost/fiber/all.hpp>
7 #include <iostream>
8 #include <sstream>
9 #include <exception>
10 #include <string>
11 #include <algorithm> // std::min()
12 #include <errno.h> // EWOULDBLOCK
13 #include <cassert>
14 #include <cstdio>
15
16 /*****************************************************************************
17 * example nonblocking API
18 *****************************************************************************/
19 //[NonblockingAPI
20 class NonblockingAPI {
21 public:
22 NonblockingAPI();
23
24 // nonblocking operation: may return EWOULDBLOCK
25 int read( std::string & data, std::size_t desired);
26
27 /*= ...*/
28 //<-
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);
32
33 private:
34 std::string data_;
35 int injected_;
36 unsigned tries_;
37 std::size_t chunksize_;
38 //->
39 };
40 //]
41
42 /*****************************************************************************
43 * fake NonblockingAPI implementation... pay no attention to the little man
44 * behind the curtain...
45 *****************************************************************************/
46 NonblockingAPI::NonblockingAPI() :
47 injected_( 0),
48 tries_( 0),
49 chunksize_( 9999) {
50 }
51
52 void NonblockingAPI::set_data( std::string const& data, std::size_t chunksize) {
53 data_ = data;
54 chunksize_ = chunksize;
55 // This delimits the start of a new test. Reset state.
56 injected_ = 0;
57 tries_ = 0;
58 }
59
60 void NonblockingAPI::inject_error( int ec) {
61 injected_ = ec;
62 }
63
64 int NonblockingAPI::read( std::string & data, std::size_t desired) {
65 // in case of error
66 data.clear();
67
68 if ( injected_) {
69 // copy injected_ because we're about to reset it
70 auto injected( injected_);
71 injected_ = 0;
72 // after an error situation, restart success count
73 tries_ = 0;
74 return injected;
75 }
76
77 if ( ++tries_ < 5) {
78 // no injected error, but the resource isn't yet ready
79 return EWOULDBLOCK;
80 }
81
82 // tell caller there's nothing left
83 if ( data_.empty() ) {
84 return EOF;
85 }
86
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
94 tries_ = 0;
95 // success
96 return 0;
97 }
98
99 /*****************************************************************************
100 * adapters
101 *****************************************************************************/
102 //[nonblocking_read_chunk
103 // guaranteed not to return EWOULDBLOCK
104 int read_chunk( NonblockingAPI & api, std::string & data, std::size_t desired) {
105 int error;
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();
110 }
111 return error;
112 }
113 //]
114
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'
120 data.clear();
121 std::string chunk;
122 int error = 0;
123 while ( data.length() < desired &&
124 ( error = read_chunk( api, chunk, desired - data.length() ) ) == 0) {
125 data.append( chunk);
126 }
127 return error;
128 }
129 //]
130
131 //[nonblocking_IncompleteRead
132 // exception class augmented with both partially-read data and errorcode
133 class IncompleteRead : public std::runtime_error {
134 public:
135 IncompleteRead( std::string const& what, std::string const& partial, int ec) :
136 std::runtime_error( what),
137 partial_( partial),
138 ec_( ec) {
139 }
140
141 std::string get_partial() const {
142 return partial_;
143 }
144
145 int get_errorcode() const {
146 return ec_;
147 }
148
149 private:
150 std::string partial_;
151 int ec_;
152 };
153 //]
154
155 //[nonblocking_read
156 // read all desired data or throw IncompleteRead
157 std::string read( NonblockingAPI & api, std::size_t desired) {
158 std::string data;
159 int ec( read_desired( api, data, desired) );
160
161 // for present purposes, EOF isn't a failure
162 if ( 0 == ec || EOF == ec) {
163 return data;
164 }
165
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);
171 }
172 //]
173
174 int main( int argc, char *argv[]) {
175 NonblockingAPI api;
176 const std::string sample_data("abcdefghijklmnopqrstuvwxyz");
177
178 // Try just reading directly from NonblockingAPI
179 api.set_data( sample_data, 5);
180 std::string data;
181 int ec = api.read( data, 13);
182 // whoops, underlying resource not ready
183 assert(ec == EWOULDBLOCK);
184 assert(data.empty());
185
186 // successful read()
187 api.set_data( sample_data, 5);
188 data = read( api, 13);
189 assert(data == "abcdefghijklm");
190
191 // read() with error
192 api.set_data( sample_data, 5);
193 // don't accidentally pick either EOF or EWOULDBLOCK
194 assert(EOF != 1);
195 assert(EWOULDBLOCK != 1);
196 api.inject_error(1);
197 int thrown = 0;
198 try {
199 data = read( api, 13);
200 } catch ( IncompleteRead const& e) {
201 thrown = e.get_errorcode();
202 }
203 assert(thrown == 1);
204
205 std::cout << "done." << std::endl;
206
207 return EXIT_SUCCESS;
208 }