Changeset 8e24583 in mainline for uspace/lib/cpp/src/__bits/test/future.cpp
- Timestamp:
- 2019-07-03T16:59:49Z (5 years ago)
- Branches:
- lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
- Children:
- 46c66f8
- Parents:
- 96fec16
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/lib/cpp/src/__bits/test/future.cpp
r96fec16 r8e24583 27 27 */ 28 28 29 #include <__bits/test/mock.hpp> 29 30 #include <__bits/test/tests.hpp> 31 #include <chrono> 32 #include <exception> 30 33 #include <future> 34 #include <tuple> 35 #include <utility> 36 37 using namespace std::chrono_literals; 38 39 namespace 40 { 41 template<class R> 42 auto prepare() 43 { 44 auto res = std::tuple< 45 std::promise<R>, std::future<R>, 46 std::aux::shared_state<R>* 47 >{}; 48 std::get<0>(res) = std::promise<R>{}; 49 std::get<1>(res) = std::get<0>(res).get_future(); 50 std::get<2>(res) = std::get<1>(res).__state(); 51 52 return res; 53 } 54 } 31 55 32 56 namespace std::test … … 39 63 test_future(); 40 64 test_promise(); 65 test_future_promise(); 41 66 test_async(); 42 67 test_packaged_task(); … … 53 78 void future_test::test_future() 54 79 { 55 // TODO: 80 std::future<int> f1{}; 81 test("default constructed invalid", !f1.valid()); 82 83 std::future<int> f2{new std::aux::shared_state<int>{}}; 84 test("state constructed valid", f2.valid()); 85 86 f1 = std::move(f2); 87 test("move assignment source invalid", !f2.valid()); 88 test("move assignment destination valid", f1.valid()); 89 90 std::future<int> f3{std::move(f1)}; 91 test("move construction source invalid", !f1.valid()); 92 test("move construction destination valid", f3.valid()); 56 93 } 57 94 58 95 void future_test::test_promise() 59 96 { 60 // TODO: 97 std::promise<int> p1{}; 98 test("default constructed promise has state", p1.__state()); 99 100 std::promise<int> p2{}; 101 auto* s1 = p1.__state(); 102 auto* s2 = p2.__state(); 103 p2.swap(p1); 104 std::swap(s1, s2); 105 106 test_eq("swap switches states pt1", s1, p1.__state()); 107 test_eq("swap switches states pt2", s2, p2.__state()); 108 109 std::promise<int> p3{std::move(p1)}; 110 test_eq("move construction state moved", s1, p3.__state()); 111 test_eq("move construction source empty", p1.__state(), nullptr); 112 113 p1 = std::move(p3); 114 test_eq("move assignment state move", s1, p1.__state()); 115 test_eq("move assignment source empty", p3.__state(), nullptr); 116 117 p1.set_value(42); 118 test("set_value marks state as ready", s1->is_set()); 119 test_eq("set_value sets value", s1->get(), 42); 120 } 121 122 void future_test::test_future_promise() 123 { 124 /** 125 * Note: As we currently have no exception 126 * propagation support, we do not test 127 * exceptions here. However, the logic there 128 * is basically identical to that of the value 129 * setting. 130 */ 131 auto [p1, f1, s1] = prepare<int>(); 132 test_eq("refcount in basic case", s1->refs(), 2); 133 134 p1.set_value(1); 135 test("simple case valid", f1.valid()); 136 test_eq("simple case get", f1.get(), 1); 137 138 auto [p2, f2, s2] = prepare<int>(); 139 std::thread t2{ 140 [&p2](){ 141 std::this_thread::sleep_for(20ms); 142 p2.set_value(42); 143 } 144 }; 145 146 test_eq("parallel get waits and has correct value", f2.get(), 42); 147 148 auto [p3, f3, s3] = prepare<int>(); 149 std::thread t3{ 150 [&p3](){ 151 std::this_thread::sleep_for(20ms); 152 p3.set_value(42); 153 } 154 }; 155 156 f3.wait(); 157 test("after wait value is set", s3->is_set()); 158 test_eq("after wait value is correct", s3->get(), 42); 159 160 auto [p4, f4, s4] = prepare<int>(); 161 std::thread t4{ 162 [&p4](){ 163 p4.set_value_at_thread_exit(42); 164 } 165 }; 166 std::this_thread::sleep_for(10ms); // Let the value be set inside state. 167 168 /* test("shared state marked as ready at thread exit", s4->is_set()); */ 169 test_eq("value set inside state while in thread", s4->get(), 42); 170 /* test_eq("value set at thread exit", f4.get(), 42); */ 171 172 mock::clear(); 173 std::aux::shared_state<std::test::mock>* s5{}; 174 { 175 std::promise<std::test::mock> p5{}; 176 s5 = p5.__state(); 177 test_eq("refcount with just promise", s5->refs(), 1); 178 { 179 auto f5 = p5.get_future(); 180 test_eq("refcount after creating future", s5->refs(), 2); 181 } 182 test_eq("refcount after future is destroyed", s5->refs(), 1); 183 test_eq("state not destroyed with future", mock::destructor_calls, 0U); 184 } 185 test_eq("state destroyed with promise", mock::destructor_calls, 1U); 186 187 mock::clear(); 188 { 189 std::aux::shared_state<std::test::mock>* s6{}; 190 std::future<std::test::mock> f6{}; 191 { 192 std::promise<std::test::mock> p6{}; 193 s6 = p6.__state(); 194 { 195 f6 = p6.get_future(); 196 test_eq("move construction only increments refcount once", s6->refs(), 2); 197 } 198 } 199 test_eq("refcount after promise is destroyed", s6->refs(), 1); 200 test_eq("state not destroyed with promise", mock::destructor_calls, 0U); 201 } 202 test_eq("state destroyed with future", mock::destructor_calls, 1U); 203 204 auto [p7, f7, s7] = prepare<int>(); 205 auto res7 = f7.wait_for(5ms); 206 test_eq("wait_for timeout", res7, std::future_status::timeout); 207 208 res7 = f7.wait_until(std::chrono::system_clock::now() + 5ms); 209 test_eq("wait_until timeout", res7, std::future_status::timeout); 210 211 std::thread t7{ 212 [&p7](){ 213 std::this_thread::sleep_for(5ms); 214 p7.set_value(42); 215 } 216 }; 217 res7 = f7.wait_for(10ms); 218 test_eq("wait_for ready", res7, std::future_status::ready); 219 220 auto [p8, f8, s8] = prepare<int>(); 221 std::thread t8{ 222 [&p8](){ 223 std::this_thread::sleep_for(5ms); 224 p8.set_value(42); 225 } 226 }; 227 228 auto res8 = f8.wait_until(std::chrono::system_clock::now() + 10ms); 229 test_eq("wait_until ready", res8, std::future_status::ready); 230 231 int x{}; 232 std::promise<int&> p9{}; 233 std::future<int&> f9 = p9.get_future(); 234 p9.set_value(x); 235 int& y = f9.get(); 236 237 test_eq("reference equal to original", x, y); 238 239 ++x; 240 test_eq("equal after modifying original", x, y); 241 242 ++y; 243 test_eq("equal after modifying reference", x, y); 61 244 } 62 245 63 246 void future_test::test_async() 64 247 { 65 // TODO: 248 auto res1 = std::async( 249 [](){ 250 return 42; 251 } 252 ); 253 test_eq("ret async default policy", res1.get(), 42); 254 255 auto res2 = std::async( 256 std::launch::deferred, [](){ 257 return 42; 258 } 259 ); 260 test_eq("ret async deferred policy", res2.get(), 42); 261 262 auto res3 = std::async( 263 std::launch::async, [](){ 264 return 42; 265 } 266 ); 267 test_eq("ret async async policy", res3.get(), 42); 268 269 int x{}; 270 auto res4 = std::async( 271 [&x](){ 272 x = 42; 273 } 274 ); 275 276 res4.get(); 277 test_eq("void async", x, 42); 66 278 } 67 279 68 280 void future_test::test_packaged_task() 69 281 { 70 // TODO: 282 std::packaged_task<int(int)> pt1{}; 283 test("default constructed packaged_task not valid", !pt1.valid()); 284 285 pt1 = std::packaged_task<int(int)>{ 286 [](int x){ 287 return x + 1; 288 } 289 }; 290 test("packaged_task default constructed and move assigned valid", pt1.valid()); 291 292 auto f1 = pt1.get_future(); 293 test("future from valid packaged_task valid", f1.valid()); 294 295 pt1(10); 296 test_eq("result stored in future correct", f1.get(), 11); 297 298 std::packaged_task<int()> pt2{ 299 [](){ 300 return 42; 301 } 302 }; 303 auto f2 = pt2.get_future(); 304 pt2(); 305 test_eq("no argument packaged_task return value correct", f2.get(), 42); 306 307 pt2.reset(); 308 test_eq("reset causes refcount decrement", f2.__state()->refs(), 1); 309 310 auto f3 = pt2.get_future(); 311 pt2(); 312 test_eq("invocation after reset returns correct value", f3.get(), 42); 313 test("reset recreates state", (f2.__state() != f3.__state())); 71 314 } 72 315 73 316 void future_test::test_shared_future() 74 317 { 75 // TODO: 318 auto [p1, f1, s1] = prepare<int>(); 319 auto sf1 = f1.share(); 320 321 test("future invalid after share", !f1.valid()); 322 test_eq("shared state moved on share", sf1.__state(), s1); 323 test_eq("no refcount increment on share", s1->refs(), 2); 324 325 { 326 auto sf2 = sf1; 327 test_eq("refcount increment on copy", s1->refs(), 3); 328 test_eq("shared state shared between copies", sf1.__state(), sf2.__state()); 329 } 330 test_eq("refcount decrement when copy gets destroyed", s1->refs(), 2); 331 332 auto sf2 = sf1; 333 int res1{}, res2{}; 334 std::thread t1{ 335 [&](){ 336 res1 = sf1.get(); 337 } 338 }; 339 std::thread t2{ 340 [&](){ 341 res2 = sf2.get(); 342 } 343 }; 344 345 std::this_thread::sleep_for(20ms); 346 p1.set_value(42); 347 std::this_thread::sleep_for(20ms); 348 test_eq("first result correct", res1, 42); 349 test_eq("second result correct", res2, 42); 76 350 } 77 351 }
Note:
See TracChangeset
for help on using the changeset viewer.