blob: c86176ef2df5499782c8ee985591e093aba3764e [file] [log] [blame]
Austin Schuh812d0d12021-11-04 20:16:48 -07001// 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.
Brian Silverman8fce7482020-01-05 13:18:21 -08004
5#include "wpi/EventLoopRunner.h"
6
7#include "wpi/SmallVector.h"
8#include "wpi/condition_variable.h"
9#include "wpi/mutex.h"
10#include "wpi/uv/AsyncFunction.h"
11#include "wpi/uv/Loop.h"
12
13using namespace wpi;
14
15class EventLoopRunner::Thread : public SafeThread {
16 public:
17 using UvExecFunc = uv::AsyncFunction<void(LoopFunc)>;
18
19 Thread() : m_loop(uv::Loop::Create()) {
20 // set up async handles
Austin Schuh812d0d12021-11-04 20:16:48 -070021 if (!m_loop) {
22 return;
23 }
Brian Silverman8fce7482020-01-05 13:18:21 -080024
25 // run function
26 m_doExec = UvExecFunc::Create(
27 m_loop, [loop = m_loop.get()](auto out, LoopFunc func) {
28 func(*loop);
29 out.set_value();
30 });
31 }
32
Austin Schuh812d0d12021-11-04 20:16:48 -070033 void Main() override {
34 if (m_loop) {
35 m_loop->Run();
36 }
Brian Silverman8fce7482020-01-05 13:18:21 -080037 }
38
39 // the loop
40 std::shared_ptr<uv::Loop> m_loop;
41
42 // run function
43 std::weak_ptr<UvExecFunc> m_doExec;
44};
45
Austin Schuh812d0d12021-11-04 20:16:48 -070046EventLoopRunner::EventLoopRunner() {
47 m_owner.Start();
48}
Brian Silverman8fce7482020-01-05 13:18:21 -080049
Austin Schuh812d0d12021-11-04 20:16:48 -070050EventLoopRunner::~EventLoopRunner() {
51 Stop();
52}
Brian Silverman8fce7482020-01-05 13:18:21 -080053
54void EventLoopRunner::Stop() {
55 ExecAsync([](uv::Loop& loop) {
56 // close all handles; this will (eventually) stop the loop
57 loop.Walk([](uv::Handle& h) {
58 h.SetLoopClosing(true);
59 h.Close();
60 });
61 });
62 m_owner.Join();
63}
64
65void EventLoopRunner::ExecAsync(LoopFunc func) {
66 if (auto thr = m_owner.GetThread()) {
67 if (auto doExec = thr->m_doExec.lock()) {
Austin Schuh812d0d12021-11-04 20:16:48 -070068 doExec->Call(std::move(func));
Brian Silverman8fce7482020-01-05 13:18:21 -080069 }
70 }
71}
72
73void EventLoopRunner::ExecSync(LoopFunc func) {
74 wpi::future<void> f;
75 if (auto thr = m_owner.GetThread()) {
76 if (auto doExec = thr->m_doExec.lock()) {
Austin Schuh812d0d12021-11-04 20:16:48 -070077 f = doExec->Call(std::move(func));
Brian Silverman8fce7482020-01-05 13:18:21 -080078 }
79 }
Austin Schuh812d0d12021-11-04 20:16:48 -070080 if (f.valid()) {
81 f.wait();
82 }
Brian Silverman8fce7482020-01-05 13:18:21 -080083}
84
85std::shared_ptr<uv::Loop> EventLoopRunner::GetLoop() {
Austin Schuh812d0d12021-11-04 20:16:48 -070086 if (auto thr = m_owner.GetThread()) {
87 return thr->m_loop;
88 }
Brian Silverman8fce7482020-01-05 13:18:21 -080089 return nullptr;
90}