scheduler.cpp

main 139 lines · 3.3 KB Raw
Alex Alex Commit Server upload 18/10/2026 23:38
1/**
2 * The Forgotten Server - a free and open-source MMORPG server emulator
3 * Copyright (C) 2019 Mark Samman <mark.samman@gmail.com>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 */
19
20#include "otpch.h"
21
22#include "scheduler.h"
23
24void Scheduler::threadMain()
25{
26 std::unique_lock<std::mutex> eventLockUnique(eventLock, std::defer_lock);
27 while (getState() != THREAD_STATE_TERMINATED) {
28 std::cv_status ret = std::cv_status::no_timeout;
29
30 eventLockUnique.lock();
31 if (eventList.empty()) {
32 eventSignal.wait(eventLockUnique);
33 } else {
34 ret = eventSignal.wait_until(eventLockUnique, eventList.top()->getCycle());
35 }
36
37 // the mutex is locked again now...
38 if (ret == std::cv_status::timeout && !eventList.empty()) {
39 // ok we had a timeout, so there has to be an event we have to execute...
40 SchedulerTask* task = eventList.top();
41 eventList.pop();
42
43 // check if the event was stopped
44 auto it = eventIds.find(task->getEventId());
45 if (it == eventIds.end()) {
46 eventLockUnique.unlock();
47 delete task;
48 continue;
49 }
50 eventIds.erase(it);
51 eventLockUnique.unlock();
52
53 task->setDontExpire();
54 g_dispatcher.addTask(task, true);
55 } else {
56 eventLockUnique.unlock();
57 }
58 }
59}
60
61uint32_t Scheduler::addEvent(SchedulerTask* task)
62{
63 eventLock.lock();
64
65 if (getState() != THREAD_STATE_RUNNING) {
66 eventLock.unlock();
67 delete task;
68 return 0;
69 }
70
71 // check if the event has a valid id
72 if (task->getEventId() == 0) {
73 // if not generate one
74 if (++lastEventId == 0) {
75 lastEventId = 1;
76 }
77
78 task->setEventId(lastEventId);
79 }
80
81 // insert the event id in the list of active events
82 uint32_t eventId = task->getEventId();
83 eventIds.insert(eventId);
84
85 // add the event to the queue
86 eventList.push(task);
87
88 // if the list was empty or this event is the top in the list
89 // we have to signal it
90 bool do_signal = (task == eventList.top());
91
92 eventLock.unlock();
93
94 if (do_signal) {
95 eventSignal.notify_one();
96 }
97
98 return eventId;
99}
100
101bool Scheduler::stopEvent(uint32_t eventId)
102{
103 if (eventId == 0) {
104 return false;
105 }
106
107 std::lock_guard<std::mutex> lockClass(eventLock);
108
109 // search the event id..
110 auto it = eventIds.find(eventId);
111 if (it == eventIds.end()) {
112 return false;
113 }
114
115 eventIds.erase(it);
116 return true;
117}
118
119void Scheduler::shutdown()
120{
121 setState(THREAD_STATE_TERMINATED);
122 eventLock.lock();
123
124 //this list should already be empty
125 while (!eventList.empty()) {
126 delete eventList.top();
127 eventList.pop();
128 }
129
130 eventIds.clear();
131 eventLock.unlock();
132 eventSignal.notify_one();
133}
134
135SchedulerTask* createSchedulerTask(uint32_t delay, std::function<void (void)> f)
136{
137 return new SchedulerTask(delay, std::move(f));
138}
139
Top