1/*
2 * LegacyClonk
3 *
4 * Copyright (c) RedWolf Design
5 * Copyright (c) 2017-2020, The LegacyClonk Team and contributors
6 *
7 * Distributed under the terms of the ISC license; see accompanying file
8 * "COPYING" for details.
9 *
10 * "Clonk" is a registered trademark of Matthes Bender, used with permission.
11 * See accompanying file "TRADEMARK" for details.
12 *
13 * To redistribute this file separately, substitute the full license texts
14 * for the above references.
15 */
16
17/* A simple scheduler for ccoperative multitasking */
18
19#pragma once
20
21#include "Standard.h"
22#include "StdSync.h"
23
24// Events are Windows-specific
25#ifndef _WIN32
26#include <vector>
27
28#include <poll.h>
29#endif
30
31#include <thread>
32#include <unordered_set>
33
34// helper
35inline int MaxTimeout(int iTimeout1, int iTimeout2)
36{
37 return (iTimeout1 == -1 || iTimeout2 == -1) ? -1 : (std::max)(a: iTimeout1, b: iTimeout2);
38}
39
40// Abstract class for a process
41class StdSchedulerProc
42{
43public:
44 virtual ~StdSchedulerProc() {}
45
46 // Do whatever the process wishes to do. Should not block longer than the timeout value.
47 // Is called whenever the process is signaled or a timeout occurs.
48 virtual bool Execute(int iTimeout = -1) = 0;
49
50 // Signal for calling Execute()
51#ifdef _WIN32
52 virtual HANDLE GetEvent() { return 0; }
53#else
54 virtual void GetFDs(std::vector<pollfd> &fds) {}
55#endif
56
57 // Call Execute() after this time has elapsed (no garantuees regarding accuracy)
58 // -1 means no timeout (infinity).
59 virtual int GetTimeout() { return -1; }
60};
61
62// A simple process scheduler
63class StdScheduler
64{
65public:
66 StdScheduler() = default;
67 virtual ~StdScheduler() = default;
68
69private:
70 // Process list
71 std::unordered_set<StdSchedulerProc *> procs;
72
73
74#ifdef _WIN32
75 CStdEvent unblocker{CStdEvent::AutoReset()};
76
77 // Dummy lists (preserved to reduce allocs)
78 std::vector<HANDLE> eventHandles;
79 std::vector<StdSchedulerProc *> eventProcs;
80#else
81 CStdEvent unblocker;
82 std::vector<pollfd> fds{{.fd = unblocker.GetFD(), .events = POLLIN}};
83#endif
84
85public:
86 std::size_t getProcCnt() const { return procs.size(); }
87
88 void Clear();
89 void Add(StdSchedulerProc *proc);
90 void Remove(StdSchedulerProc *proc);
91
92 bool Execute(int iTimeout = -1);
93 void UnBlock();
94
95protected:
96 // overridable
97 virtual void OnError(StdSchedulerProc *pProc) {}
98};
99
100// A simple process scheduler thread
101class StdSchedulerThread : public StdScheduler
102{
103public:
104 StdSchedulerThread() = default;
105 virtual ~StdSchedulerThread();
106
107private:
108 // thread control
109 std::atomic_bool runThreadRun{false};
110
111 bool fThread{false};
112 std::thread thread;
113
114public:
115 void Clear();
116 void Add(StdSchedulerProc *pProc);
117 void Remove(StdSchedulerProc *pProc);
118
119 bool Start();
120 void Stop();
121};
122