blob: 6c143ac674fc61c90f451a93f87d749fdc67e8a2 [file] [log] [blame]
James Kuszmaulcf324122023-01-14 14:07:17 -08001// Copyright (c) FIRST and other WPILib contributors.
2// Open Source Software; you can modify and/or share it under the terms of
3// the WPILib BSD license file in the root directory of this project.
4
5#include "wpinet/EventLoopRunner.h"
6
7#include <wpi/SmallVector.h>
8#include <wpi/condition_variable.h>
9#include <wpi/mutex.h>
10
11#include "wpinet/uv/AsyncFunction.h"
12#include "wpinet/uv/Loop.h"
13
14using namespace wpi;
15
16class EventLoopRunner::Thread : public SafeThread {
17 public:
18 using UvExecFunc = uv::AsyncFunction<void(LoopFunc)>;
19
20 Thread() : m_loop(uv::Loop::Create()) {
21 // set up async handles
22 if (!m_loop) {
23 return;
24 }
25
26 // run function
27 m_doExec = UvExecFunc::Create(
28 m_loop, [loop = m_loop.get()](auto out, LoopFunc func) {
29 func(*loop);
30 out.set_value();
31 });
32 }
33
34 void Main() override {
35 if (m_loop) {
36 m_loop->Run();
37 }
38 }
39
40 // the loop
41 std::shared_ptr<uv::Loop> m_loop;
42
43 // run function
44 std::weak_ptr<UvExecFunc> m_doExec;
45};
46
47EventLoopRunner::EventLoopRunner() {
48 m_owner.Start();
49}
50
51EventLoopRunner::~EventLoopRunner() {
52 Stop();
53}
54
55void EventLoopRunner::Stop() {
56 ExecAsync([](uv::Loop& loop) {
57 // close all handles; this will (eventually) stop the loop
58 loop.Walk([](uv::Handle& h) {
59 h.SetLoopClosing(true);
60 h.Close();
61 });
James Kuszmaulb13e13f2023-11-22 20:44:04 -080062 loop.SetClosing();
James Kuszmaulcf324122023-01-14 14:07:17 -080063 });
64 m_owner.Join();
65}
66
67void EventLoopRunner::ExecAsync(LoopFunc func) {
68 if (auto thr = m_owner.GetThread()) {
69 if (auto doExec = thr->m_doExec.lock()) {
70 doExec->Call(std::move(func));
71 }
72 }
73}
74
75void EventLoopRunner::ExecSync(LoopFunc func) {
76 wpi::future<void> f;
77 if (auto thr = m_owner.GetThread()) {
78 if (auto doExec = thr->m_doExec.lock()) {
79 f = doExec->Call(std::move(func));
80 }
81 }
82 if (f.valid()) {
83 f.wait();
84 }
85}
86
87std::shared_ptr<uv::Loop> EventLoopRunner::GetLoop() {
88 if (auto thr = m_owner.GetThread()) {
89 return thr->m_loop;
90 }
91 return nullptr;
92}