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();
32  m_current = ZERO;
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 
100 void 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 
227  return dequeueProcess(m_current);
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 
274 ProcessManager::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 {
378  List<Process *> *lst = m_interruptNotifyList[vector];
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 }
Scheduler
Responsible for deciding which Process may execute on the local Core.
Definition: Scheduler.h:36
ProcessManager::resume
Result resume(Process *proc)
Resume scheduling of the given Process.
Definition: ProcessManager.cpp:250
ProcessManager::m_idle
Process * m_idle
Idle process.
Definition: ProcessManager.h:246
Queue::remove
Size remove(T value)
Remove all items with the given value.
Definition: Queue.h:110
ProcessManager::raiseEvent
Result raiseEvent(Process *proc, const struct ProcessEvent *event)
Raise kernel event for a Process.
Definition: ProcessManager.cpp:325
ProcessManager::~ProcessManager
virtual ~ProcessManager()
Destructor function.
Definition: ProcessManager.cpp:37
Process::reset
virtual void reset(const Address entry)=0
Restart execution at the given entry point.
Index::insertAt
virtual bool insertAt(const Size position, T *item)
Inserts the given item at the given position.
Definition: Index.h:113
Queue::contains
bool contains(const T &item) const
Look if an item exists on the Queue.
Definition: Queue.h:92
ProcessManager::Result
Result
Result code.
Definition: ProcessManager.h:51
Scheduler::Success
@ Success
Definition: Scheduler.h:45
Process::getState
State getState() const
Retrieves the current state.
Definition: Process.cpp:80
Process
Represents a process which may run on the host.
Definition: Process.h:44
ProcessManager::reset
Result reset(Process *proc, const Address entry)
Restart execution of a Process at the given entry point.
Definition: ProcessManager.cpp:262
Process::WakeupPending
@ WakeupPending
Definition: Process.h:60
Process::raiseEvent
Result raiseEvent(const struct ProcessEvent *event)
Raise kernel event.
Definition: Process.cpp:161
ProcessManager::m_current
Process * m_current
Currently executing process.
Definition: ProcessManager.h:243
ProcessManager::create
Process * create(const Address entry, const MemoryMap &map, const bool readyToRun=false, const bool privileged=false)
Create a new Process.
Definition: ProcessManager.cpp:45
ProcessManager::IOError
@ IOError
Definition: ProcessManager.h:55
ProcessManager::unregisterInterruptNotify
Result unregisterInterruptNotify(Process *proc)
Remove all interrupt notifications for a Process.
Definition: ProcessManager.cpp:361
Process::Ready
@ Ready
Definition: Process.h:68
Arch::Process
ARMProcess Process
Definition: ARMProcess.h:105
Process::getID
ProcessID getID() const
Retrieve our ID number.
Definition: Process.cpp:60
ProcessManager::dequeueProcess
Result dequeueProcess(Process *proc, const bool ignoreState=false) const
Remove the given process on the Schedule queue.
Definition: ProcessManager.cpp:414
ProcessManager::sleep
Result sleep(const Timer::Info *timer=0, const bool ignoreWakeups=false)
Let current Process sleep until a timer expires or wakeup occurs.
Definition: ProcessManager.cpp:274
ProcessID
u32 ProcessID
Process Identification Number.
Definition: Types.h:140
Address
unsigned long Address
A memory address.
Definition: Types.h:131
ProcessManager::wakeup
Result wakeup(Process *proc)
Take Process out of Sleep state and mark ready for execution.
Definition: ProcessManager.cpp:306
Process::Success
@ Success
Definition: Process.h:56
ProcessManager::wait
Result wait(Process *proc)
Let current Process wait for another Process to terminate.
Definition: ProcessManager.cpp:219
Timer::Info
Timer information structure.
Definition: Timer.h:42
Timer
Represents a configurable timer device.
Definition: Timer.h:35
Process::wakeup
Result wakeup()
Prevent process from sleeping.
Definition: Process.cpp:224
Sequence::fill
virtual void fill(T value)
Fill the Sequence with the given value.
Definition: Sequence.h:73
Log.h
uint
unsigned int uint
Unsigned integer number.
Definition: Types.h:44
ProcessManager::WakeupPending
@ WakeupPending
Definition: ProcessManager.h:56
List::remove
virtual int remove(T t)
Remove all items which are equal to the given item.
Definition: List.h:166
InterruptEvent
@ InterruptEvent
Definition: ProcessEvent.h:32
Process::stop
Result stop()
Stop execution of this process.
Definition: Process.cpp:137
FATAL
#define FATAL(msg)
Output a critical message and terminate program immediatly.
Definition: Log.h:50
DEBUG
#define DEBUG(msg)
Output a debug message to standard output.
Definition: Log.h:89
Process::Result
Result
Result codes.
Definition: Process.h:54
Process::resume
Result resume()
Resume execution when this process is stopped.
Definition: Process.cpp:149
ProcessManager::Success
@ Success
Definition: ProcessManager.h:53
ProcessManager::stop
Result stop(Process *proc)
Remove given Process from the Scheduler.
Definition: ProcessManager.cpp:230
ProcessEvent
Represents a process which may run on the host.
Definition: ProcessEvent.h:40
ListIterator::hasCurrent
virtual bool hasCurrent() const
Check if there is a current item on the List.
Definition: ListIterator.h:104
Process::execute
virtual void execute(Process *previous)=0
Allow the Process to run on the CPU.
MAX_PROCS
#define MAX_PROCS
Maximum number of processes.
Definition: ProcessManager.h:39
Index::size
virtual Size size() const
Size of the Index.
Definition: Index.h:217
NULL
#define NULL
NULL means zero.
Definition: Macros.h:39
Scheduler::select
Process * select()
Select the next process to run.
Definition: Scheduler.cpp:69
ProcessManager.h
u32
unsigned int u32
Unsigned 32-bit number.
Definition: Types.h:53
ProcessEvent.h
ProcessManager::ProcessManager
ProcessManager()
Constructor function.
Definition: ProcessManager.cpp:25
MemoryMap
Describes virtual memory map layout.
Definition: MemoryMap.h:38
Size
unsigned int Size
Any sane size indicator cannot go negative.
Definition: Types.h:128
WeakSingleton< Kernel >::instance
static Kernel * instance()
Retrieve the instance.
Definition: Singleton.h:86
Scheduler.h
ProcessManager::schedule
Result schedule()
Schedule next process to run.
Definition: ProcessManager.cpp:155
Vector::insert
virtual int insert(const T &item)
Adds the given item to the Vector, if possible.
Definition: Vector.h:93
Timer::isExpired
bool isExpired(const Info &info) const
Check if a timer value is expired.
Definition: Timer.cpp:85
Vector::size
virtual Size size() const
Returns the maximum size of this Vector.
Definition: Vector.h:194
Index::get
virtual T * get(const Size position) const
Returns the item at the given position.
Definition: Index.h:187
ProcessManager::get
Process * get(const ProcessID id)
Retrieve a Process by it's ID.
Definition: ProcessManager.cpp:95
Process::setParent
void setParent(ProcessID id)
Set parent process ID.
Definition: Process.cpp:105
Scheduler::enqueue
Result enqueue(Process *proc, bool ignoreState)
Add a Process to the run schedule.
Definition: Scheduler.cpp:32
Process::Waiting
@ Waiting
Definition: Process.h:70
ProcessManager::m_procs
Index< Process, MAX_PROCS > m_procs
All known Processes.
Definition: ProcessManager.h:237
ListIterator.h
Queue::count
virtual Size count() const
Returns the number of items in the Queue.
Definition: Queue.h:153
ProcessManager::interruptNotify
Result interruptNotify(const u32 vector)
Raise interrupt notifications for a interrupt vector.
Definition: ProcessManager.cpp:376
Process::initialize
virtual Result initialize()
Initialize the Process.
Definition: Process.cpp:172
assert
#define assert(exp)
Insert program diagnostics.
Definition: assert.h:60
Process::State
State
Represents the execution state of the Process.
Definition: Process.h:66
ERROR
#define ERROR(msg)
Output an error message.
Definition: Log.h:61
entry
u32 entry[]
Definition: IntelACPI.h:64
ProcessManager::remove
void remove(Process *proc, const uint exitStatus=0)
Remove a Process.
Definition: ProcessManager.cpp:100
Process::sleep
Result sleep(const Timer::Info *timer, bool ignoreWakeups)
Stops the process for executing until woken up.
Definition: Process.cpp:244
Queue::pop
T & pop()
Remove item from the tail of the Queue.
Definition: Queue.h:76
Index::remove
virtual bool remove(const Size position)
Removes the item at the given position.
Definition: Index.h:143
List< Process * >
ProcessEvent::type
ProcessEventType type
Definition: ProcessEvent.h:42
Queue::push
bool push(const T &item)
Add item to the head of the Queue.
Definition: Queue.h:55
ProcessManager::m_sleepTimerQueue
Queue< Process *, MAX_PROCS > m_sleepTimerQueue
Queue with sleeping processes waiting for a Timer to expire.
Definition: ProcessManager.h:249
ProcessManager::m_scheduler
Scheduler * m_scheduler
Object which selects processes to run.
Definition: ProcessManager.h:240
ProcessManager::current
Process * current()
Current process running.
Definition: ProcessManager.cpp:203
Scheduler::dequeue
Result dequeue(Process *proc, bool ignoreState)
Remove a Process from the run schedule.
Definition: Scheduler.cpp:44
Index::insert
virtual bool insert(Size &position, T *item)
Adds the given item, if possible.
Definition: Index.h:60
Process::getSleepTimer
const Timer::Info & getSleepTimer() const
Get sleep timer.
Definition: Process.cpp:90
Kernel::getTimer
Timer * getTimer()
Get Timer.
Definition: Kernel.cpp:163
ZERO
#define ZERO
Zero value.
Definition: Macros.h:43
ProcessManager::setIdle
void setIdle(Process *proc)
Set the idle process.
Definition: ProcessManager.cpp:208
Process::wait
Result wait(ProcessID id)
Let Process wait for other Process to terminate.
Definition: Process.cpp:110
ProcessManager::m_interruptNotifyList
Vector< List< Process * > * > m_interruptNotifyList
Interrupt notification list.
Definition: ProcessManager.h:252
ProcessManager::AlreadyExists
@ AlreadyExists
Definition: ProcessManager.h:57
ProcessManager::registerInterruptNotify
Result registerInterruptNotify(Process *proc, const u32 vector)
Register an interrupt notification for a Process.
Definition: ProcessManager.cpp:344
ListIterator
Iterate through a List.
Definition: ListIterator.h:37
ProcessManager::enqueueProcess
Result enqueueProcess(Process *proc, const bool ignoreState=false)
Place the given process on the Schedule queue.
Definition: ProcessManager.cpp:399