ping-pong-fltk_and_thread.cpp 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151
  1. #include <rotor/fltk.hpp>
  2. #include <rotor/thread.hpp>
  3. #include <FL/Fl.H>
  4. #include <FL/Fl_Window.H>
  5. #include <FL/Fl_Box.H>
  6. #ifndef _WIN32
  7. #include <X11/Xlib.h>
  8. #include <cstdlib>
  9. #endif
  10. namespace r = rotor;
  11. namespace rf = r::fltk;
  12. namespace rt = r::thread;
  13. namespace payload {
  14. struct pong_t {};
  15. struct ping_t {
  16. using response_t = pong_t;
  17. };
  18. } // namespace payload
  19. namespace message {
  20. using ping_t = r::request_traits_t<payload::ping_t>::request::message_t;
  21. using pong_t = r::request_traits_t<payload::ping_t>::response::message_t;
  22. } // namespace message
  23. struct pinger_t : public r::actor_base_t {
  24. using rotor::actor_base_t::actor_base_t;
  25. void configure(r::plugin::plugin_base_t &plugin) noexcept override {
  26. r::actor_base_t::configure(plugin);
  27. plugin.with_casted<r::plugin::starter_plugin_t>([](auto &p) { p.subscribe_actor(&pinger_t::on_pong); });
  28. plugin.with_casted<r::plugin::registry_plugin_t>(
  29. [&](auto &p) { p.discover_name("ponger", ponger_addr, true).link(); });
  30. }
  31. void on_start() noexcept override {
  32. r::actor_base_t::on_start();
  33. auto timeout = r::pt::seconds{2};
  34. start_timer(timeout, *this, &pinger_t::on_ping_timer);
  35. }
  36. void on_ping_timer(r::request_id_t, bool) noexcept {
  37. box->label("ping has been sent");
  38. auto timeout = r::pt::seconds{3};
  39. request<payload::ping_t>(ponger_addr).send(timeout);
  40. }
  41. void on_pong(message::pong_t &) noexcept {
  42. box->label("pong has been received, going to shutdown");
  43. auto timeout = r::pt::seconds{1};
  44. start_timer(timeout, *this, &pinger_t::on_shutdown_timer);
  45. }
  46. void on_shutdown_timer(r::request_id_t, bool) noexcept { supervisor->do_shutdown(); }
  47. rotor::address_ptr_t ponger_addr;
  48. Fl_Box *box;
  49. };
  50. struct ponger_t : r::actor_base_t {
  51. using rotor::actor_base_t::actor_base_t;
  52. using ping_message_ptr_t = r::intrusive_ptr_t<message::ping_t>;
  53. void configure(r::plugin::plugin_base_t &plugin) noexcept override {
  54. r::actor_base_t::configure(plugin);
  55. plugin.with_casted<r::plugin::starter_plugin_t>([](auto &p) { p.subscribe_actor(&ponger_t::on_ping); });
  56. plugin.with_casted<rotor::plugin::registry_plugin_t>(
  57. [&](auto &p) { p.register_name("ponger", get_address()); });
  58. }
  59. void on_ping(message::ping_t &message) noexcept {
  60. auto timeout = r::pt::seconds{2};
  61. request = &message;
  62. start_timer(timeout, *this, &ponger_t::on_timer);
  63. }
  64. void on_timer(r::request_id_t, bool) noexcept {
  65. reply_to(*request);
  66. request.reset();
  67. }
  68. ping_message_ptr_t request;
  69. };
  70. bool is_display_available() {
  71. #ifndef _WIN32
  72. char *disp = getenv("DISPLAY");
  73. if (disp == nullptr)
  74. return false;
  75. Display *dpy = XOpenDisplay(disp);
  76. if (dpy == nullptr)
  77. return false;
  78. XCloseDisplay(dpy);
  79. #endif
  80. return true;
  81. }
  82. int main(int argc, char **argv) {
  83. if (!is_display_available()) {
  84. return 0;
  85. }
  86. // let fltk-core be aware of lockin mechanism (i.e. Fl::awake will work)
  87. Fl::lock();
  88. Fl_Window window = Fl_Window(400, 180);
  89. Fl_Box *box = new Fl_Box(20, 40, 360, 100, "auto shutdown in 5 seconds");
  90. box->box(FL_UP_BOX);
  91. window.end();
  92. window.show(argc, argv);
  93. auto fltk_context = rf::system_context_fltk_t();
  94. auto timeout = r::pt::millisec{500};
  95. auto fltk_supervisor =
  96. fltk_context.create_supervisor<rf::supervisor_fltk_t>().timeout(timeout).create_registry().finish();
  97. // warm-up
  98. fltk_supervisor->do_process();
  99. auto pinger = fltk_supervisor->create_actor<pinger_t>().timeout(timeout).finish();
  100. pinger->box = box;
  101. auto thread_context = rt::system_context_thread_t();
  102. auto thread_supervisor = thread_context.create_supervisor<rt::supervisor_thread_t>()
  103. .timeout(timeout)
  104. .registry_address(fltk_supervisor->get_registry_address())
  105. .finish();
  106. auto ponger = thread_supervisor->create_actor<ponger_t>().timeout(timeout).finish();
  107. auto auxiliary_thread = std::thread([&]() { thread_context.run(); });
  108. Fl::add_check([](auto *data) { reinterpret_cast<r::supervisor_t *>(data)->do_process(); }, fltk_supervisor.get());
  109. while (!fltk_supervisor->get_shutdown_reason()) {
  110. fltk_supervisor->do_process();
  111. Fl::wait(0.1);
  112. }
  113. thread_supervisor->shutdown();
  114. auxiliary_thread.join();
  115. return 0;
  116. }