AsyncFw 1.2
Async Framework is c++ runtime with timers, poll notifiers, sockets, coroutines, etc.
 
Loading...
Searching...
No Matches
MainThread.h
1/*
2Copyright (c) 2026 Alexandr Kuzmuk
3
4This file is part of the AsyncFw project. Licensed under the MIT License.
5See {Link: LICENSE file https://mit-license.org} in the project root for full license information.
6*/
7
8#pragma once
9
10#include "../core/Thread.h"
11#include "Instance.h"
12
13#ifndef _WIN32
14 #define EXIT_ON_UNIX_SIGNAL
15#endif
16
17#ifdef USE_QAPPLICATION
18 #include <map>
19 #include <QTimerEvent>
20 #include <QSocketNotifier>
21 #include <QApplication>
22#endif
23
24#ifdef EXIT_ON_UNIX_SIGNAL
25 #include <sys/eventfd.h>
26#endif
27
28namespace AsyncFw {
33class MainThread : private Thread
34#ifdef USE_QAPPLICATION
35 ,
36 private QObject
37#endif
38{
39public:
40 template <typename M>
41 static void setExitTask(M method) {
42 if (mt_.exitTask && !mt_.invokeMethod([_p = mt_.exitTask]() { delete _p; })) delete mt_.exitTask;
43 mt_.exitTask = new Thread::Task(std::forward<M>(method));
44 }
45 static int exec() {
46#ifndef USE_QAPPLICATION
47 if (mt_.running()) return -1;
48 mt_.Thread::exec();
49 return mt_.code_;
50#else
51 mt_.state_ = 1;
52 return qApp->exec();
53#endif
54 }
55 static void exit() {
56#ifdef EXIT_ON_UNIX_SIGNAL
57 if (mt_.eventfd_ >= 0) eventfd_write(mt_.eventfd_, 1);
58#else
59 (*mt_.exitTask)();
60#endif
61 }
62 static void exit(int code) {
63 mt_.code_ = code;
64 exit();
65 }
66 static void quit() {
67#ifndef USE_QAPPLICATION
68 mt_.Thread::quit();
69#else
70 qApp->exit(mt_.code_);
71#endif
72 }
73
74private:
75 MainThread() : Thread("Main") {
76 setId();
77 setExitTask([]() { quit(); });
78#ifdef USE_QAPPLICATION
80 QObject::connect(qApp, &QCoreApplication::aboutToQuit, [this]() {
82 { //lock scope
83 LockGuard lock = lockGuard();
84 state_ = 2;
85 }
86 qApp->processEvents();
87 });
88 });
89#endif
90#ifdef EXIT_ON_UNIX_SIGNAL
91 eventfd_ = eventfd(0, EFD_NONBLOCK);
92 #ifdef USE_QAPPLICATION
94 #endif
95 appendPollTask(eventfd_, AbstractThread::PollIn, [this](AbstractThread::PollEvents) {
96 eventfd_t _v;
97 if (eventfd_read(eventfd_, &_v) == 0) (*exitTask)();
98 });
99 #ifdef USE_QAPPLICATION
100 startedEvent();
101 });
102 #endif
103#endif
104 }
105 ~MainThread() {
106#ifdef EXIT_ON_UNIX_SIGNAL
107 if (eventfd_ >= 0) {
108 removePollDescriptor(eventfd_);
109 ::close(eventfd_);
110 }
111#endif
112 delete exitTask;
113 AbstractInstance::List::destroyValues();
114 clearId();
115#ifdef USE_QAPPLICATION
116 for (const std::shared_ptr<Poll> &_n : notifiers) { delete _n->task; }
117 for (const Timer &_t : timers) { delete _t.task; }
118#endif
119 }
120#ifdef USE_QAPPLICATION
121 struct Timer {
122 int id;
123 int qid;
124 AbstractTask *task;
125 };
126 std::vector<Timer> timers;
127
128 bool running() const override {
129 LockGuard lock = lockGuard();
130 return state_ == 1;
131 }
132
133 virtual int appendTimer(int msec, AbstractTask *task) override {
134 int id = 0;
135 int qid = -1;
136 LockGuard lock = lockGuard();
137 std::vector<Timer>::iterator it = timers.begin();
138 for (; it != timers.end(); ++it, ++id)
139 if (it->id != id) break;
140 if (msec > 0) { qid = QObject::startTimer(msec); }
141 timers.emplace(it, Timer {id, qid, task});
142 return id;
143 }
144
145 virtual bool modifyTimer(int id, int msec) override {
146 LockGuard lock = lockGuard();
147 for (std::vector<Timer>::iterator it = timers.begin(); it != timers.end(); ++it) {
148 if (it->id == id) {
149 if (it->qid >= 0) QObject::killTimer(it->qid);
150 it->qid = (msec > 0) ? QObject::startTimer(msec) : -1;
151 return true;
152 }
153 }
154 return false;
155 }
156
157 virtual void removeTimer(int id) override {
158 AbstractTask *_t = nullptr;
159 { //lock scope
160 LockGuard lock = lockGuard();
161 for (std::vector<Timer>::iterator it = timers.begin(); it != timers.end(); ++it) {
162 if (it->id == id) {
163 if (it->qid >= 0) QObject::killTimer(it->qid);
164 _t = new Task([p = it->task] { delete p; });
165 timers.erase(it);
166 break;
167 }
168 }
169 }
170 if (!invokeTask(_t)) {
171 (*_t)();
172 delete _t;
173 }
174 }
175
176 void timerEvent(QTimerEvent *e) override {
177 int qid = e->timerId();
178 AbstractTask *_t = nullptr;
179 { //lock scope
180 LockGuard lock = lockGuard();
181 for (std::vector<Timer>::iterator it = timers.begin(); it != timers.end(); ++it) {
182 if (it->qid == qid) {
183 _t = it->task;
184 break;
185 }
186 }
187 }
188 if (_t) (*_t)();
189 }
190
191 bool invokeTask(AbstractTask *task) const override {
192 LockGuard lock = lockGuard();
193 if (state_ == 2) return false;
194 QMetaObject::invokeMethod(
195 const_cast<MainThread *>(this),
196 [task]() {
197 (*task)();
198 delete task;
199 },
200 Qt::QueuedConnection);
201 return true;
202 }
203
204 struct Poll {
205 Poll(int fd) : in(fd, QSocketNotifier::Read), out(fd, QSocketNotifier::Write) {
206 QObject::connect(&in, &QSocketNotifier::activated, [this]() { (*task)(AbstractThread::PollIn); });
207 QObject::connect(&out, &QSocketNotifier::activated, [this]() { (*task)(AbstractThread::PollOut); });
208 }
209
210 QSocketNotifier in;
211 QSocketNotifier out;
212 AbstractPollTask *task;
213 };
214
215 bool appendPollDescriptor(int fd, AbstractThread::PollEvents e, AbstractPollTask *task) override {
216 LockGuard lock = lockGuard();
217 for (const std::shared_ptr<Poll> &poll : notifiers)
218 if (poll->in.socket() == fd) return false;
219 std::shared_ptr<Poll> poll = std::make_shared<Poll>(fd);
220 poll->in.setEnabled(e & AbstractThread::PollIn);
221 poll->out.setEnabled(e & AbstractThread::PollOut);
222 poll->task = task;
223 notifiers.append(std::move(poll));
224 return true;
225 }
226
227 bool modifyPollDescriptor(int fd, PollEvents e) override {
228 LockGuard lock = lockGuard();
229 for (const std::shared_ptr<Poll> &poll : notifiers)
230 if (poll->in.socket() == fd) {
231 poll->in.setEnabled(e & AbstractThread::PollIn);
232 poll->out.setEnabled(e & AbstractThread::PollOut);
233 return true;
234 }
235 return false;
236 }
237
238 void removePollDescriptor(int fd) override {
239 AbstractTask *_t = nullptr;
240 { //lock scope
241 LockGuard lock = lockGuard();
242 for (const std::shared_ptr<Poll> &poll : notifiers)
243 if (poll->in.socket() == fd) {
244 _t = new Task([p = poll->task] { delete p; });
245 notifiers.removeAll(poll);
246 break;
247 }
248 }
249 if (!_t) return;
250 if (!invokeTask(_t)) {
251 (*_t)();
252 delete _t;
253 }
254 }
255
256 QList<std::shared_ptr<Poll>> notifiers;
257#endif
258 AbstractThread::AbstractTask *exitTask = nullptr;
259 int code_ = 0;
260#ifdef EXIT_ON_UNIX_SIGNAL
261 int eventfd_ = -1;
262#endif
263#ifdef USE_QAPPLICATION
264 int state_ = 0;
265#endif
266 static MainThread mt_;
267};
268inline MainThread MainThread::mt_;
269} // namespace AsyncFw
The AbstractTask class.
Definition Task.h:16
bool appendPollTask(int fd, PollEvents events, M method)
Append poll task.
Definition AbstractThread.h:106
virtual int appendTimer(int, AbstractTask *)
Append timer.
Definition AbstractThread.cpp:675
std::thread::id id() const
Returns unique identifier of managed thread.
Definition AbstractThread.cpp:669
virtual void removePollDescriptor(int)
Remove poll descriptor.
Definition AbstractThread.cpp:800
virtual bool modifyTimer(int, int)
Modify timer.
Definition AbstractThread.cpp:694
std::lock_guard< std::mutex > LockGuard
The LockGuard type.
Definition AbstractThread.h:54
LockGuard lockGuard() const
Locks the managed thread and returns a LockGuard variable. The thread is unblocked after this variabl...
Definition AbstractThread.cpp:673
virtual bool appendPollDescriptor(int, PollEvents, AbstractPollTask *)
Append poll descriptor.
Definition AbstractThread.cpp:731
virtual bool running() const
Returns true if the managed thread is running.
Definition AbstractThread.cpp:315
std::enable_if< std::is_void< typenamestd::invoke_result< M >::type >::value, bool >::type invokeMethod(M method, bool sync=false) const
Runs a method in a managed thread.
Definition AbstractThread.h:74
AbstractFunction<> AbstractTask
The AbstractTask type.
Definition AbstractThread.h:56
virtual bool invokeTask(AbstractTask *) const
Runs a task in a managed thread.
Definition AbstractThread.cpp:619
static AbstractThread * currentThread()
Returns a pointer to the AsyncFw::AbstractThread that manages the currently executing thread.
Definition AbstractThread.cpp:295
AbstractFunction< AbstractThread::PollEvents > AbstractPollTask
The AbstractPollTask type.
Definition AbstractThread.h:58
virtual void removeTimer(int)
Remove timer.
Definition AbstractThread.cpp:712
virtual bool modifyPollDescriptor(int, PollEvents)
Modify poll descriptor.
Definition AbstractThread.cpp:768
The MainThread class.
Definition MainThread.h:38
void startedEvent() override
Runs started()
Definition Thread.cpp:51
void finishedEvent() override
Runs finished()
Definition Thread.cpp:62
Thread(const std::string &="Thread")
Constructs a thread.
Definition Thread.cpp:33
The Timer class.
Definition Timer.h:15