blob: 1c54bdf9e5481fbfe02f83774b6033491538e348 [file] [log] [blame]
Brian Silverman41cdd3e2019-01-19 19:48:58 -08001/*----------------------------------------------------------------------------*/
James Kuszmaul4f3ad3c2019-12-01 16:35:21 -08002/* Copyright (c) 2018-2019 FIRST. All Rights Reserved. */
Brian Silverman41cdd3e2019-01-19 19:48:58 -08003/* Open Source Software - may be modified and shared by FRC teams. The code */
4/* must be accompanied by the FIRST BSD license file in the root directory of */
5/* the project. */
6/*----------------------------------------------------------------------------*/
7
8#include "wpi/EventLoopRunner.h"
9
10#include "wpi/SmallVector.h"
11#include "wpi/condition_variable.h"
12#include "wpi/mutex.h"
13#include "wpi/uv/AsyncFunction.h"
14#include "wpi/uv/Loop.h"
15
16using namespace wpi;
17
18class EventLoopRunner::Thread : public SafeThread {
19 public:
20 using UvExecFunc = uv::AsyncFunction<void(LoopFunc)>;
21
22 Thread() : m_loop(uv::Loop::Create()) {
23 // set up async handles
24 if (!m_loop) return;
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() {
35 if (m_loop) m_loop->Run();
36 }
37
38 // the loop
39 std::shared_ptr<uv::Loop> m_loop;
40
41 // run function
42 std::weak_ptr<UvExecFunc> m_doExec;
43};
44
45EventLoopRunner::EventLoopRunner() { m_owner.Start(); }
46
47EventLoopRunner::~EventLoopRunner() { Stop(); }
48
49void EventLoopRunner::Stop() {
50 ExecAsync([](uv::Loop& loop) {
51 // close all handles; this will (eventually) stop the loop
James Kuszmaul4f3ad3c2019-12-01 16:35:21 -080052 loop.Walk([](uv::Handle& h) {
53 h.SetLoopClosing(true);
54 h.Close();
55 });
Brian Silverman41cdd3e2019-01-19 19:48:58 -080056 });
57 m_owner.Join();
58}
59
60void EventLoopRunner::ExecAsync(LoopFunc func) {
61 if (auto thr = m_owner.GetThread()) {
62 if (auto doExec = thr->m_doExec.lock()) {
63 doExec->Call(func);
64 }
65 }
66}
67
68void EventLoopRunner::ExecSync(LoopFunc func) {
69 wpi::future<void> f;
70 if (auto thr = m_owner.GetThread()) {
71 if (auto doExec = thr->m_doExec.lock()) {
72 f = doExec->Call(func);
73 }
74 }
75 if (f.valid()) f.wait();
76}
77
78std::shared_ptr<uv::Loop> EventLoopRunner::GetLoop() {
79 if (auto thr = m_owner.GetThread()) return thr->m_loop;
80 return nullptr;
81}