blob: b885385279baf6befecdbcf4bd9ee582beb90a61 [file] [log] [blame]
Brian Silverman41cdd3e2019-01-19 19:48:58 -08001/*----------------------------------------------------------------------------*/
2/* Copyright (c) 2018 FIRST. All Rights Reserved. */
3/* 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
52 loop.Walk([](uv::Handle& h) { h.Close(); });
53 });
54 m_owner.Join();
55}
56
57void EventLoopRunner::ExecAsync(LoopFunc func) {
58 if (auto thr = m_owner.GetThread()) {
59 if (auto doExec = thr->m_doExec.lock()) {
60 doExec->Call(func);
61 }
62 }
63}
64
65void EventLoopRunner::ExecSync(LoopFunc func) {
66 wpi::future<void> f;
67 if (auto thr = m_owner.GetThread()) {
68 if (auto doExec = thr->m_doExec.lock()) {
69 f = doExec->Call(func);
70 }
71 }
72 if (f.valid()) f.wait();
73}
74
75std::shared_ptr<uv::Loop> EventLoopRunner::GetLoop() {
76 if (auto thr = m_owner.GetThread()) return thr->m_loop;
77 return nullptr;
78}