testUVRAII.cxx 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181
  1. #include "cmUVHandlePtr.h"
  2. #include <algorithm>
  3. #include <chrono>
  4. #include <iostream>
  5. #include <thread>
  6. #include "cm_uv.h"
  7. static void signal_reset_fn(uv_async_t* handle)
  8. {
  9. auto ptr = static_cast<cm::uv_async_ptr*>(handle->data);
  10. ptr->reset();
  11. }
  12. // A common pattern is to use an async signal to shutdown the server.
  13. static bool testAsyncShutdown()
  14. {
  15. uv_loop_t Loop;
  16. auto err = uv_loop_init(&Loop);
  17. if (err != 0) {
  18. std::cerr << "Could not init loop" << std::endl;
  19. return false;
  20. }
  21. {
  22. cm::uv_async_ptr signal;
  23. signal.init(Loop, &signal_reset_fn, &signal);
  24. std::thread([&] {
  25. std::this_thread::sleep_for(std::chrono::seconds(2));
  26. signal.send();
  27. }).detach();
  28. if (uv_run(&Loop, UV_RUN_DEFAULT) != 0) {
  29. std::cerr << "Unclean exit state in testAsyncDtor" << std::endl;
  30. return false;
  31. }
  32. if (signal.get()) {
  33. std::cerr << "Loop exited with signal not being cleaned up" << std::endl;
  34. return false;
  35. }
  36. }
  37. uv_loop_close(&Loop);
  38. return true;
  39. }
  40. static void signal_fn(uv_async_t*)
  41. {
  42. }
  43. // Async dtor is sort of a pain; since it locks a mutex we must be sure its
  44. // dtor always calls reset otherwise the mutex is deleted then locked.
  45. static bool testAsyncDtor()
  46. {
  47. uv_loop_t Loop;
  48. auto err = uv_loop_init(&Loop);
  49. if (err != 0) {
  50. std::cerr << "Could not init loop" << std::endl;
  51. return false;
  52. }
  53. {
  54. cm::uv_async_ptr signal;
  55. signal.init(Loop, signal_fn);
  56. }
  57. if (uv_run(&Loop, UV_RUN_DEFAULT) != 0) {
  58. std::cerr << "Unclean exit state in testAsyncDtor" << std::endl;
  59. return false;
  60. }
  61. uv_loop_close(&Loop);
  62. return true;
  63. }
  64. // Async needs a relatively stateful deleter; make sure that is properly
  65. // accounted for and doesn't try to hold on to invalid state when it is
  66. // moved
  67. static bool testAsyncMove()
  68. {
  69. uv_loop_t Loop;
  70. auto err = uv_loop_init(&Loop);
  71. if (err != 0) {
  72. std::cerr << "Could not init loop" << std::endl;
  73. return false;
  74. }
  75. {
  76. cm::uv_async_ptr signal;
  77. {
  78. cm::uv_async_ptr signalTmp;
  79. signalTmp.init(Loop, signal_fn);
  80. signal = std::move(signalTmp);
  81. }
  82. }
  83. if (uv_run(&Loop, UV_RUN_DEFAULT) != 0) {
  84. std::cerr << "Unclean exit state in testAsyncDtor" << std::endl;
  85. return false;
  86. }
  87. uv_loop_close(&Loop);
  88. return true;
  89. }
  90. // When a type is castable to another uv type (pipe -> stream) here,
  91. // and the deleter is convertible as well, we should allow moves from
  92. // one type to the other.
  93. static bool testCrossAssignment()
  94. {
  95. uv_loop_t Loop;
  96. auto err = uv_loop_init(&Loop);
  97. if (err != 0) {
  98. std::cerr << "Could not init loop" << std::endl;
  99. return false;
  100. }
  101. {
  102. cm::uv_pipe_ptr pipe;
  103. pipe.init(Loop, 0);
  104. cm::uv_stream_ptr stream = std::move(pipe);
  105. if (pipe.get()) {
  106. std::cerr << "Move should be sure to invalidate the previous ptr"
  107. << std::endl;
  108. return false;
  109. }
  110. cm::uv_handle_ptr handle = std::move(stream);
  111. if (stream.get()) {
  112. std::cerr << "Move should be sure to invalidate the previous ptr"
  113. << std::endl;
  114. return false;
  115. }
  116. }
  117. if (uv_run(&Loop, UV_RUN_DEFAULT) != 0) {
  118. std::cerr << "Unclean exit state in testCrossAssignment" << std::endl;
  119. return false;
  120. }
  121. uv_loop_close(&Loop);
  122. return true;
  123. }
  124. // This test can't fail at run time; but this makes sure we have all our move
  125. // ctors created correctly.
  126. static bool testAllMoves()
  127. {
  128. using namespace cm;
  129. struct allTypes
  130. {
  131. uv_stream_ptr _7;
  132. uv_timer_ptr _8;
  133. uv_tty_ptr _9;
  134. uv_process_ptr _11;
  135. uv_pipe_ptr _12;
  136. uv_async_ptr _13;
  137. uv_signal_ptr _14;
  138. uv_handle_ptr _15;
  139. };
  140. allTypes a;
  141. allTypes b(std::move(a));
  142. allTypes c = std::move(b);
  143. return true;
  144. };
  145. int testUVRAII(int, char** const)
  146. {
  147. if ((testAsyncShutdown() &&
  148. testAsyncDtor() & testAsyncMove() & testCrossAssignment() &
  149. testAllMoves()) == 0) {
  150. return -1;
  151. }
  152. return 0;
  153. }