123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181 |
- #include "cmUVHandlePtr.h"
- #include <algorithm>
- #include <chrono>
- #include <iostream>
- #include <thread>
- #include "cm_uv.h"
- static void signal_reset_fn(uv_async_t* handle)
- {
- auto ptr = static_cast<cm::uv_async_ptr*>(handle->data);
- ptr->reset();
- }
- // A common pattern is to use an async signal to shutdown the server.
- static bool testAsyncShutdown()
- {
- uv_loop_t Loop;
- auto err = uv_loop_init(&Loop);
- if (err != 0) {
- std::cerr << "Could not init loop" << std::endl;
- return false;
- }
- {
- cm::uv_async_ptr signal;
- signal.init(Loop, &signal_reset_fn, &signal);
- std::thread([&] {
- std::this_thread::sleep_for(std::chrono::seconds(2));
- signal.send();
- }).detach();
- if (uv_run(&Loop, UV_RUN_DEFAULT) != 0) {
- std::cerr << "Unclean exit state in testAsyncDtor" << std::endl;
- return false;
- }
- if (signal.get()) {
- std::cerr << "Loop exited with signal not being cleaned up" << std::endl;
- return false;
- }
- }
- uv_loop_close(&Loop);
- return true;
- }
- static void signal_fn(uv_async_t*)
- {
- }
- // Async dtor is sort of a pain; since it locks a mutex we must be sure its
- // dtor always calls reset otherwise the mutex is deleted then locked.
- static bool testAsyncDtor()
- {
- uv_loop_t Loop;
- auto err = uv_loop_init(&Loop);
- if (err != 0) {
- std::cerr << "Could not init loop" << std::endl;
- return false;
- }
- {
- cm::uv_async_ptr signal;
- signal.init(Loop, signal_fn);
- }
- if (uv_run(&Loop, UV_RUN_DEFAULT) != 0) {
- std::cerr << "Unclean exit state in testAsyncDtor" << std::endl;
- return false;
- }
- uv_loop_close(&Loop);
- return true;
- }
- // Async needs a relatively stateful deleter; make sure that is properly
- // accounted for and doesn't try to hold on to invalid state when it is
- // moved
- static bool testAsyncMove()
- {
- uv_loop_t Loop;
- auto err = uv_loop_init(&Loop);
- if (err != 0) {
- std::cerr << "Could not init loop" << std::endl;
- return false;
- }
- {
- cm::uv_async_ptr signal;
- {
- cm::uv_async_ptr signalTmp;
- signalTmp.init(Loop, signal_fn);
- signal = std::move(signalTmp);
- }
- }
- if (uv_run(&Loop, UV_RUN_DEFAULT) != 0) {
- std::cerr << "Unclean exit state in testAsyncDtor" << std::endl;
- return false;
- }
- uv_loop_close(&Loop);
- return true;
- }
- // When a type is castable to another uv type (pipe -> stream) here,
- // and the deleter is convertible as well, we should allow moves from
- // one type to the other.
- static bool testCrossAssignment()
- {
- uv_loop_t Loop;
- auto err = uv_loop_init(&Loop);
- if (err != 0) {
- std::cerr << "Could not init loop" << std::endl;
- return false;
- }
- {
- cm::uv_pipe_ptr pipe;
- pipe.init(Loop, 0);
- cm::uv_stream_ptr stream = std::move(pipe);
- if (pipe.get()) {
- std::cerr << "Move should be sure to invalidate the previous ptr"
- << std::endl;
- return false;
- }
- cm::uv_handle_ptr handle = std::move(stream);
- if (stream.get()) {
- std::cerr << "Move should be sure to invalidate the previous ptr"
- << std::endl;
- return false;
- }
- }
- if (uv_run(&Loop, UV_RUN_DEFAULT) != 0) {
- std::cerr << "Unclean exit state in testCrossAssignment" << std::endl;
- return false;
- }
- uv_loop_close(&Loop);
- return true;
- }
- // This test can't fail at run time; but this makes sure we have all our move
- // ctors created correctly.
- static bool testAllMoves()
- {
- using namespace cm;
- struct allTypes
- {
- uv_stream_ptr _7;
- uv_timer_ptr _8;
- uv_tty_ptr _9;
- uv_process_ptr _11;
- uv_pipe_ptr _12;
- uv_async_ptr _13;
- uv_signal_ptr _14;
- uv_handle_ptr _15;
- };
- allTypes a;
- allTypes b(std::move(a));
- allTypes c = std::move(b);
- return true;
- };
- int testUVRAII(int, char** const)
- {
- if ((testAsyncShutdown() &&
- testAsyncDtor() & testAsyncMove() & testCrossAssignment() &
- testAllMoves()) == 0) {
- return -1;
- }
- return 0;
- }
|