FreeNOS
ProcessManager.cpp
Go to the documentation of this file.
1/*
2 * Copyright (C) 2015 Niek Linnenbank
3 *
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 3 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18#include <FreeNOS/System.h>
19#include <Log.h>
20#include <ListIterator.h>
21#include "Scheduler.h"
22#include "ProcessEvent.h"
23#include "ProcessManager.h"
24
26 : m_procs()
27 , m_interruptNotifyList(256)
28{
29 DEBUG("m_procs = " << MAX_PROCS);
30
31 m_scheduler = new Scheduler();
33 m_idle = ZERO;
35}
36
38{
39 if (m_scheduler != NULL)
40 {
41 delete m_scheduler;
42 }
43}
44
46 const MemoryMap &map,
47 const bool readyToRun,
48 const bool privileged)
49{
50 Size pid = 0;
51
52 // Insert a dummy to determine the next available PID
53 if (!m_procs.insert(pid, (Process *) ~ZERO))
54 {
55 return ZERO;
56 }
57
58 // Create the new Process
59 Process *proc = new Arch::Process(pid, entry, privileged, map);
60 if (!proc)
61 {
62 ERROR("failed to allocate Process");
63 m_procs.remove(pid);
64 return ZERO;
65 }
66
67 // Initialize the Process
68 const Process::Result result = proc->initialize();
69 if (result != Process::Success)
70 {
71 ERROR("failed to initialize Process: result = " << (int) result);
72 m_procs.remove(pid);
73 delete proc;
74 return ZERO;
75 }
76
77 // Overwrite dummy with actual Process
78 m_procs.insertAt(pid, proc);
79
80 // Report to scheduler, if requested
81 if (readyToRun)
82 {
83 resume(proc);
84 }
85
86 // Assign parent, if any
87 if (m_current != 0)
88 {
89 proc->setParent(m_current->getID());
90 }
91
92 return proc;
93}
94
96{
97 return m_procs.get(id);
98}
99
100void ProcessManager::remove(Process *proc, const uint exitStatus)
101{
102 if (proc == m_idle)
103 m_idle = ZERO;
104
105 if (proc == m_current)
106 m_current = ZERO;
107
108 // Notify processes which are waiting for this Process
109 const Size size = m_procs.size();
110 for (Size i = 0; i < size; i++)
111 {
112 if (m_procs[i] != ZERO &&
113 m_procs[i]->getState() == Process::Waiting &&
114 m_procs[i]->getWait() == proc->getID())
115 {
116 const Process::Result result = m_procs[i]->join(exitStatus);
117 if (result != Process::Success)
118 {
119 FATAL("failed to join() PID " << m_procs[i]->getID() <<
120 ": result = " << (int) result);
121 }
122
123 const Result r = enqueueProcess(m_procs[i]);
124 if (r != Success)
125 {
126 FATAL("failed to enqueue() PID " << m_procs[i]->getID() <<
127 ": result = " << (int) r);
128 }
129 }
130 }
131
132 // Unregister any interrupt events for this process
134
135 // Remove process from administration and schedule
136 m_procs.remove(proc->getID());
137
138 if (proc->getState() == Process::Ready)
139 {
140 const Result result = dequeueProcess(proc, true);
141 if (result != Success)
142 {
143 FATAL("failed to dequeue PID " << proc->getID());
144 }
145 }
146
147 const Size countRemoved = m_sleepTimerQueue.remove(proc);
148 assert(countRemoved <= 1U);
149 (void) countRemoved;
150
151 // Free the process memory
152 delete proc;
153}
154
156{
157 const Timer *timer = Kernel::instance()->getTimer();
158 const Size sleepTimerCount = m_sleepTimerQueue.count();
159
160 // Let the scheduler select a new process
161 Process *proc = m_scheduler->select();
162
163 // If no process ready, let us idle
164 if (!proc)
165 proc = m_idle;
166
167 if (!proc)
168 {
169 FATAL("no process found to run!");
170 }
171
172 // Try to wakeup processes that are waiting for a timer to expire
173 for (Size i = 0; i < sleepTimerCount; i++)
174 {
176 const Timer::Info & procTimer = p->getSleepTimer();
177
178 if (timer->isExpired(procTimer))
179 {
180 const Result result = wakeup(p);
181 if (result != Success)
182 {
183 FATAL("failed to wakeup PID " << p->getID());
184 }
185 }
186 else
187 {
189 }
190 }
191
192 // Only execute if its a different process
193 if (proc != m_current)
194 {
195 Process *previous = m_current;
196 m_current = proc;
197 proc->execute(previous);
198 }
199
200 return Success;
201}
202
204{
205 return m_current;
206}
207
209{
210 const Result result = dequeueProcess(proc, true);
211 if (result != Success)
212 {
213 FATAL("failed to dequeue PID " << proc->getID());
214 }
215
216 m_idle = proc;
217}
218
220{
221 if (m_current->wait(proc->getID()) != Process::Success)
222 {
223 ERROR("process ID " << m_current->getID() << " failed to wait");
224 return IOError;
225 }
226
228}
229
231{
232 const Process::State state = proc->getState();
233 const Process::Result result = proc->stop();
234 if (result != Process::Success)
235 {
236 ERROR("failed to stop PID " << proc->getID() << ": result = " << (int) result);
237 return IOError;
238 }
239
240 if (state == Process::Ready)
241 {
242 return dequeueProcess(proc);
243 }
244 else
245 {
246 return Success;
247 }
248}
249
251{
252 const Process::Result result = proc->resume();
253 if (result != Process::Success)
254 {
255 ERROR("failed to resume PID " << proc->getID() << ": result = " << (int) result);
256 return IOError;
257 }
258
259 return enqueueProcess(proc);
260}
261
263{
264 if (proc == m_current)
265 {
266 ERROR("cannot reset current Process");
267 return IOError;
268 }
269
270 proc->reset(entry);
271 return Success;
272}
273
274ProcessManager::Result ProcessManager::sleep(const Timer::Info *timer, const bool ignoreWakeups)
275{
276 const Process::Result result = m_current->sleep(timer, ignoreWakeups);
277 switch (result)
278 {
280 return WakeupPending;
281
282 case Process::Success: {
283 const Result res = dequeueProcess(m_current);
284 if (res != Success)
285 {
286 FATAL("failed to dequeue PID " << m_current->getID());
287 }
288
289 if (timer)
290 {
293 }
294 break;
295 }
296
297 default:
298 ERROR("failed to sleep process ID " << m_current->getID() <<
299 ": result: " << (uint) result);
300 return IOError;
301 }
302
303 return Success;
304}
305
307{
308 const Process::Result result = proc->wakeup();
309
310 switch (result)
311 {
313 return Success;
314
315 case Process::Success:
316 return enqueueProcess(proc);
317
318 default:
319 ERROR("failed to wakeup process ID " << proc->getID() <<
320 ": result: " << (uint) result);
321 return IOError;
322 }
323}
324
326{
327 const Process::Result result = proc->raiseEvent(event);
328
329 switch (result)
330 {
332 return Success;
333
334 case Process::Success:
335 return enqueueProcess(proc);
336
337 default:
338 ERROR("failed to raise event in process ID " << proc->getID() <<
339 ": result: " << (uint) result);
340 return IOError;
341 }
342}
343
345{
346 // Create List if necessary
347 if (!m_interruptNotifyList[vec])
348 {
350 }
351
352 // Check for duplicates
353 if (m_interruptNotifyList[vec]->contains(proc))
354 return AlreadyExists;
355
356 // Append the Process
357 m_interruptNotifyList[vec]->append(proc);
358 return Success;
359}
360
362{
363 // Remove the Process from all notify lists
364 for (Size i = 0; i < m_interruptNotifyList.size(); i++)
365 {
367 if (lst)
368 {
369 lst->remove(proc);
370 }
371 }
372
373 return Success;
374}
375
377{
379 if (lst)
380 {
381 ProcessEvent event;
382 event.type = InterruptEvent;
383 event.number = vector;
384
385 for (ListIterator<Process *> i(lst); i.hasCurrent(); i++)
386 {
387 if (raiseEvent(i.current(), &event) != Success)
388 {
389 ERROR("failed to raise InterruptEvent for IRQ #" << vector <<
390 " on Process ID " << i.current()->getID());
391 return IOError;
392 }
393 }
394 }
395
396 return Success;
397}
398
400{
401 if (m_scheduler->enqueue(proc, ignoreState) != Scheduler::Success)
402 {
403 ERROR("process ID " << proc->getID() << " not added to Scheduler");
404 return IOError;
405 }
406
407 const Size countRemoved = m_sleepTimerQueue.remove(proc);
408 assert(countRemoved <= 1U);
409 (void) countRemoved;
410
411 return Success;
412}
413
415{
416 if (m_scheduler->dequeue(proc, ignoreState) != Scheduler::Success)
417 {
418 ERROR("process ID " << proc->getID() << " not removed from Scheduler");
419 return IOError;
420 }
421
422 return Success;
423}
u32 entry[]
Definition IntelACPI.h:1
virtual T * get(const Size position) const
Returns the item at the given position.
Definition Index.h:187
virtual bool insertAt(const Size position, T *item)
Inserts the given item at the given position.
Definition Index.h:113
virtual bool insert(Size &position, T *item)
Adds the given item, if possible.
Definition Index.h:60
virtual Size size() const
Size of the Index.
Definition Index.h:217
virtual bool remove(const Size position)
Removes the item at the given position.
Definition Index.h:143
Timer * getTimer()
Get Timer.
Definition Kernel.cpp:163
Iterate through a List.
virtual bool hasCurrent() const
Check if there is a current item on the List.
Simple linked list template class.
Definition List.h:37
virtual int remove(T t)
Remove all items which are equal to the given item.
Definition List.h:166
Describes virtual memory map layout.
Definition MemoryMap.h:39
Result unregisterInterruptNotify(Process *proc)
Remove all interrupt notifications for a Process.
Result reset(Process *proc, const Address entry)
Restart execution of a Process at the given entry point.
Result registerInterruptNotify(Process *proc, const u32 vector)
Register an interrupt notification for a Process.
ProcessManager()
Constructor function.
void setIdle(Process *proc)
Set the idle process.
Result resume(Process *proc)
Resume scheduling of the given Process.
Result sleep(const Timer::Info *timer=0, const bool ignoreWakeups=false)
Let current Process sleep until a timer expires or wakeup occurs.
Result dequeueProcess(Process *proc, const bool ignoreState=false) const
Remove the given process on the Schedule queue.
Scheduler * m_scheduler
Object which selects processes to run.
Result wait(Process *proc)
Let current Process wait for another Process to terminate.
Result
Result code.
Process * create(const Address entry, const MemoryMap &map, const bool readyToRun=false, const bool privileged=false)
Create a new Process.
Process * m_idle
Idle process.
Result wakeup(Process *proc)
Take Process out of Sleep state and mark ready for execution.
void remove(Process *proc, const uint exitStatus=0)
Remove a Process.
Vector< List< Process * > * > m_interruptNotifyList
Interrupt notification list.
Result raiseEvent(Process *proc, const struct ProcessEvent *event)
Raise kernel event for a Process.
Queue< Process *, MAX_PROCS > m_sleepTimerQueue
Queue with sleeping processes waiting for a Timer to expire.
Result stop(Process *proc)
Remove given Process from the Scheduler.
Result schedule()
Schedule next process to run.
Process * m_current
Currently executing process.
Result enqueueProcess(Process *proc, const bool ignoreState=false)
Place the given process on the Schedule queue.
Result interruptNotify(const u32 vector)
Raise interrupt notifications for a interrupt vector.
virtual ~ProcessManager()
Destructor function.
Process * get(const ProcessID id)
Retrieve a Process by it's ID.
Process * current()
Current process running.
Index< Process, MAX_PROCS > m_procs
All known Processes.
Represents a process which may run on the host.
Definition Process.h:45
virtual void reset(const Address entry)=0
Restart execution at the given entry point.
const Timer::Info & getSleepTimer() const
Get sleep timer.
Definition Process.cpp:90
Result wait(ProcessID id)
Let Process wait for other Process to terminate.
Definition Process.cpp:110
State
Represents the execution state of the Process.
Definition Process.h:67
@ Ready
Definition Process.h:68
@ Waiting
Definition Process.h:70
Result stop()
Stop execution of this process.
Definition Process.cpp:137
Result resume()
Resume execution when this process is stopped.
Definition Process.cpp:149
Result
Result codes.
Definition Process.h:55
@ Success
Definition Process.h:56
@ WakeupPending
Definition Process.h:60
Result sleep(const Timer::Info *timer, bool ignoreWakeups)
Stops the process for executing until woken up.
Definition Process.cpp:244
State getState() const
Retrieves the current state.
Definition Process.cpp:80
virtual Result initialize()
Initialize the Process.
Definition Process.cpp:172
ProcessID getID() const
Retrieve our ID number.
Definition Process.cpp:60
void setParent(ProcessID id)
Set parent process ID.
Definition Process.cpp:105
virtual void execute(Process *previous)=0
Allow the Process to run on the CPU.
Result wakeup()
Prevent process from sleeping.
Definition Process.cpp:224
Result raiseEvent(const struct ProcessEvent *event)
Raise kernel event.
Definition Process.cpp:161
bool contains(const T &item) const
Look if an item exists on the Queue.
Definition Queue.h:92
Size remove(T value)
Remove all items with the given value.
Definition Queue.h:110
T & pop()
Remove item from the tail of the Queue.
Definition Queue.h:76
virtual Size count() const
Returns the number of items in the Queue.
Definition Queue.h:153
bool push(const T &item)
Add item to the head of the Queue.
Definition Queue.h:55
Responsible for deciding which Process may execute on the local Core.
Definition Scheduler.h:37
Result dequeue(Process *proc, bool ignoreState)
Remove a Process from the run schedule.
Definition Scheduler.cpp:44
Process * select()
Select the next process to run.
Definition Scheduler.cpp:69
Result enqueue(Process *proc, bool ignoreState)
Add a Process to the run schedule.
Definition Scheduler.cpp:32
virtual void fill(T value)
Fill the Sequence with the given value.
Definition Sequence.h:73
Represents a configurable timer device.
Definition Timer.h:36
bool isExpired(const Info &info) const
Check if a timer value is expired.
Definition Timer.cpp:85
virtual Size size() const
Returns the maximum size of this Vector.
Definition Vector.h:194
virtual int insert(const T &item)
Adds the given item to the Vector, if possible.
Definition Vector.h:93
static Kernel * instance()
Retrieve the instance.
Definition Singleton.h:86
#define MAX_PROCS
Maximum number of processes.
@ InterruptEvent
#define assert(exp)
Insert program diagnostics.
Definition assert.h:60
#define NULL
NULL means zero.
Definition Macros.h:39
u32 ProcessID
Process Identification Number.
Definition Types.h:140
unsigned int u32
Unsigned 32-bit number.
Definition Types.h:53
unsigned long Address
A memory address.
Definition Types.h:131
#define ERROR(msg)
Output an error message.
Definition Log.h:61
#define FATAL(msg)
Output a critical message and terminate program immediatly.
Definition Log.h:50
unsigned int uint
Unsigned integer number.
Definition Types.h:44
unsigned int Size
Any sane size indicator cannot go negative.
Definition Types.h:128
#define ZERO
Zero value.
Definition Macros.h:43
#define DEBUG(msg)
Output a debug message to standard output.
Definition Log.h:89
ARMProcess Process
Definition ARMProcess.h:105
Represents a process which may run on the host.
ProcessEventType type
Timer information structure.
Definition Timer.h:43