FreeNOS
ChannelServer.h
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#ifndef __LIBIPC_CHANNELSERVER_H
19#define __LIBIPC_CHANNELSERVER_H
20
21#include <FreeNOS/User.h>
22#include <FreeNOS/ProcessManager.h>
23#include <FreeNOS/ProcessEvent.h>
24#include <FreeNOS/ProcessShares.h>
25#include <HashIterator.h>
26#include <Timer.h>
27#include <Vector.h>
28#include "MemoryChannel.h"
29#include "ChannelClient.h"
30#include "ChannelRegistry.h"
31
43template <class Func> struct MessageHandler
44{
51 MessageHandler(const Func func, const bool reply)
52 : exec(func)
53 , sendReply(reply)
54 {
55 }
56
57 const bool operator == (const struct MessageHandler<Func> & h) const
58 {
59 return false;
60 }
61
62 const bool operator != (const struct MessageHandler<Func> & h) const
63 {
64 return false;
65 }
66
68 const Func exec;
69
71 const bool sendReply;
72};
73
79template <class Base, class MsgType> class ChannelServer
80{
81 private:
82
84 static const Size MaximumHandlerCount = 255u;
85
86 protected:
87
89 typedef void (Base::*IPCHandlerFunction)(MsgType *);
90
92 typedef void (Base::*IRQHandlerFunction)(Size);
93
94 public:
95
106
107 public:
108
112 ChannelServer(Base *inst)
113 : m_instance(inst)
114 , m_client(ChannelClient::instance())
115 , m_registry(m_client->getRegistry())
116 , m_kernelEvent(Channel::Consumer, sizeof(ProcessEvent))
117 , m_ipcHandlers()
118 , m_irqHandlers()
119 {
121
122 // Reset timeout values
124 m_expiry.ticks = 0;
125
126 // Setup kernel event channel
127 const SystemInformation info;
129 share.pid = KERNEL_PID;
130 share.coreId = info.coreId;
131 share.tagId = 0;
132
133 if (VMShare(SELF, API::Read, &share) != API::Success)
134 {
135 FATAL("failed to get kernel event channel");
136 }
137 else
138 {
140 share.range.virt + PAGESIZE, false);
141 }
142
143 // Try to recover channels after a restart
145 }
146
151 {
154 }
155
161 int run()
162 {
163 // Enter loop
164 while (true)
165 {
166 processAll();
168 }
169
170 // Satify compiler
171 return 0;
172 }
173
179 void setTimeout(const uint msec)
180 {
181 DEBUG("msec = " << msec);
182
184 {
185 ERROR("failed to retrieve system timer info");
186 return;
187 }
188
189 const Size msecPerTick = 1000 / m_time.frequency;
191 m_expiry.ticks = m_time.ticks + ((msec / msecPerTick) + 1);
192 }
193
194 protected:
195
203 void addIPCHandler(const Size slot, IPCHandlerFunction h, const bool sendReply = true)
204 {
206 }
207
215 {
217 }
218
222 virtual void timeout()
223 {
224 DEBUG("");
225
227 }
228
234 virtual bool retryRequests()
235 {
236 return false;
237 }
238
244 virtual void onProcessTerminated(const ProcessID pid)
245 {
246 }
247
252 {
253 while (m_instance->retryRequests())
254 ;
255 }
256
257 private:
258
262 inline void processAll()
263 {
264 // Process kernel events
266
267 // Process user messages
268 readChannels();
269
270 // Retry requests until all served (EAGAIN or return value)
272 }
273
277 inline void sleepUntilWakeup()
278 {
279 // Sleep with timeout or return in case the process is
280 // woken up by an external (wakeup) interrupt.
281 DEBUG("EnterSleep");
282 Address expiry = 0;
283
285 expiry = (Address) &m_expiry;
286
287 const Error r = ProcessCtl(SELF, EnterSleep, expiry, (Address) (m_expiry.frequency ? &m_time : 0));
288 DEBUG("EnterSleep returned: " << (int)r);
289
290 // Check for sleep timeout
292 {
294 {
295 ERROR("failed to retrieve system timer");
296 }
297 else if (m_expiry.ticks < m_time.ticks)
298 {
300 timeout();
301 }
302 }
303 }
304
315 const Memory::Range range,
316 const bool hardReset = true)
317 {
318 Address prodAddr, consAddr;
319
320 // ProcessID's determine where the producer/consumer is placed
321 if (m_self < pid)
322 {
323 prodAddr = range.virt;
324 consAddr = range.virt + (PAGESIZE * 2);
325 }
326 else
327 {
328 prodAddr = range.virt + (PAGESIZE * 2);
329 consAddr = range.virt;
330 }
331
332 // Create consumer
333 if (!m_registry.getConsumer(pid))
334 {
335 MemoryChannel *consumer = new MemoryChannel(Channel::Consumer, sizeof(MsgType));
336 assert(consumer != NULL);
337 consumer->setVirtual(consAddr, consAddr + PAGESIZE, hardReset);
338 m_registry.registerConsumer(pid, consumer);
339 }
340
341 // Create producer
342 if (!m_registry.getProducer(pid))
343 {
344 MemoryChannel *producer = new MemoryChannel(Channel::Producer, sizeof(MsgType));
345 assert(producer != NULL);
346 producer->setVirtual(prodAddr,
347 prodAddr + PAGESIZE,
348 hardReset);
349 m_registry.registerProducer(pid, producer);
350 }
351
352 // Done
353 return Success;
354 }
355
360 {
361 const SystemInformation info;
362
363 for (ProcessID i = 0; i < MAX_PROCS; i++)
364 {
365 if (i != m_self && i != KERNEL_PID)
366 {
368 share.pid = i;
369 share.coreId = info.coreId;
370 share.tagId = 0;
371
372 const API::Result result = VMShare(SELF, API::Read, &share);
373 if (result == API::Success)
374 {
375 const Result r = accept(i, share.range, false);
376 if (r != Success)
377 {
378 ERROR("failed to recover share for PID " << i << ": " << (int)r);
379 }
380 }
381 }
382 }
383 }
384
391 {
392 ProcessEvent event;
394
395 // Try to read a message on the kernel event channel
396 while (m_kernelEvent.read(&event) == Channel::Success)
397 {
398 DEBUG(m_self << ": got kernel event: " << (int) event.type);
399
400 switch (event.type)
401 {
402 case ShareCreated:
403 {
404 DEBUG(m_self << ": share created for PID: " << event.share.pid);
405 accept(event.share.pid, event.share.range);
406 break;
407 }
408 case InterruptEvent:
409 {
410 DEBUG(m_self << ": interrupt: " << event.number);
411
413 if (h)
414 {
415 (m_instance->*h->exec) (event.number);
416 }
417 else
418 {
419 ERROR(m_self << ": unhandled IRQ raised: " << event.number);
420 }
421 break;
422 }
424 {
425 DEBUG(m_self << ": process terminated: PID " << event.number);
426 result = m_registry.unregisterConsumer(event.number);
427 if (result != ChannelRegistry::Success)
428 {
429 ERROR("failed to unregister consumer for PID " <<
430 event.number << ": " << (int)result);
431 }
432
433 result = m_registry.unregisterProducer(event.number);
434 if (result != ChannelRegistry::Success)
435 {
436 ERROR("failed to unregister producer for PID " <<
437 event.number << ": " << (int)result);
438 }
439
440 // cleanup the VMShare area now for that process
441 const API::Result shareResult = VMShare(event.number, API::Delete, ZERO);
442 if (shareResult != API::Success)
443 {
444 ERROR("failed to remove shares with VMShare for PID " <<
445 event.number << ": " << (int)shareResult);
446 }
447
449 break;
450 }
451 default:
452 WARNING(m_self << ": unknown event.type: " << event.type);
453 break;
454 }
455 }
456 return Success;
457 }
458
465 {
466 MsgType msg;
467
468 // Try to receive message on each consumer channel
469 for (HashIterator<ProcessID, Channel *> i(m_registry.getConsumers()); i.hasCurrent(); i++)
470 {
471 Channel *ch = i.current();
472 DEBUG(m_self << ": trying to receive from PID " << i.key());
473
474 // Read all messages in the consumer channel
475 while (ch->read(&msg) == Channel::Success)
476 {
477 DEBUG(m_self << ": received message");
478 msg.from = i.key();
479
480 // Is the message a response from earlier client request?
481 if (msg.type == ChannelMessage::Response)
482 {
483 if (m_client->processResponse(msg.from, &msg) != ChannelClient::Success)
484 {
485 ERROR(m_self << ": failed to process client response from PID " <<
486 msg.from << " with identifier " << msg.identifier);
487 }
488 }
489 // Message is a request to us
490 else
491 {
493 if (h)
494 {
495 (m_instance->*h->exec) (&msg);
496
497 // Send reply
498 if (h->sendReply)
499 {
500 Channel *ch = m_registry.getProducer(i.key());
501 if (!ch)
502 {
503 ERROR(m_self << ": no producer channel found for PID: " << i.key());
504 }
505 else if (ch->write(&msg) != Channel::Success)
506 {
507 ERROR(m_self << ": failed to send reply message to PID: " << i.key());
508 }
509 else
510 ProcessCtl(i.key(), Wakeup, 0);
511 }
512 }
513 else
514 {
515 ERROR(m_self << ": invalid action " << (int)msg.action << " from PID " << i.key());
516 }
517 }
518 }
519 }
520 return Success;
521 }
522
523 protected:
524
527
530
533
536
539
542
545
548
551};
552
558#endif /* __LIBIPC_CHANNELSERVER_H */
Result
Enumeration of generic kernel API result codes.
Definition API.h:69
@ Success
Definition API.h:70
@ Read
Definition API.h:98
@ Delete
Definition API.h:94
Client for using Channels on the local processor.
virtual Result processResponse(const ProcessID pid, ChannelMessage *msg)
Process a response message.
Registration for Channels.
Result registerProducer(const ProcessID pid, Channel *channel)
Register producer channel.
HashTable< ProcessID, Channel * > & getConsumers()
Get all consumers.
Channel * getProducer(const ProcessID pid)
Get one producer.
Result unregisterConsumer(const ProcessID pid)
Unregister consumer channel.
Result
Result codes.
Result registerConsumer(const ProcessID pid, Channel *channel)
Register consumer channel.
Channel * getConsumer(const ProcessID pid)
Get one consumer.
Result unregisterProducer(const ProcessID pid)
Unregister producer channel.
Template class which serves incoming messages from Channels using MessageHandlers.
static const Size MaximumHandlerCount
Maximum number of IPC/IRQ handlers.
Timer::Info m_expiry
System timer expiration value.
void sleepUntilWakeup()
Let this process sleep until more events are raised.
void processAll()
Process all current events and channels.
Result accept(const ProcessID pid, const Memory::Range range, const bool hardReset=true)
Accept new channel connection.
void recoverChannels()
Read existing shares to recover MemoryChannels after restart.
ChannelRegistry & m_registry
Contains registered channels.
Result readKernelEvents()
Read and process kernel events.
virtual bool retryRequests()
Retry any pending requests.
Index< MessageHandler< IPCHandlerFunction >, MaximumHandlerCount > m_ipcHandlers
IPC handler functions.
Timer::Info m_time
System timer value.
ChannelServer(Base *inst)
Constructor function.
void setTimeout(const uint msec)
Set a sleep timeout.
void retryAllRequests()
Keep retrying requests until all served.
void(Base::* IRQHandlerFunction)(Size)
Member function pointer inside Base, to handle interrupts.
MemoryChannel m_kernelEvent
Kernel event channel.
virtual void onProcessTerminated(const ProcessID pid)
Called whenever another Process is terminated.
ProcessID m_self
ProcessID of ourselves.
virtual void timeout()
Called when sleep timeout is reached.
ChannelClient * m_client
Client for sending replies.
void addIRQHandler(const Size slot, IRQHandlerFunction h)
Register a new IRQ message vector handler.
Result readChannels()
Read each Channel for messages.
void(Base::* IPCHandlerFunction)(MsgType *)
Member function pointer inside Base, to handle IPC messages.
int run()
Enters an infinite loop, serving incoming requests.
Result
Result codes.
virtual ~ChannelServer()
Destructor function.
Base * m_instance
Server object instance.
Index< MessageHandler< IRQHandlerFunction >, MaximumHandlerCount > m_irqHandlers
IRQ handler functions.
void addIPCHandler(const Size slot, IPCHandlerFunction h, const bool sendReply=true)
Register a new IPC message action handler.
Unidirectional point-to-point messaging channel.
Definition Channel.h:35
@ Consumer
Definition Channel.h:59
@ Producer
Definition Channel.h:58
virtual Result write(const void *buffer)
Write a message.
Definition Channel.cpp:40
virtual Result read(void *buffer)
Read a message.
Definition Channel.cpp:35
@ Success
Definition Channel.h:43
Iterate through a HashTable.
Index is a N-sized array of pointers to items of type T.
Definition Index.h:37
virtual T * get(const Size position) const
Returns the item at the given position.
Definition Index.h:187
void deleteAll()
Removes and delete()'s all items.
Definition Index.h:166
virtual bool insertAt(const Size position, T *item)
Inserts the given item at the given position.
Definition Index.h:113
Unidirectional point-to-point channel using shared memory.
virtual Result read(void *buffer)
Read a message.
Result setVirtual(const Address data, const Address feedback, const bool hardReset=true)
Set memory pages by virtual address.
#define MAX_PROCS
Maximum number of processes.
@ ProcessTerminated
@ InterruptEvent
@ ShareCreated
#define KERNEL_PID
Definition ProcessID.h:36
#define SELF
Definition ProcessID.h:35
API::Result ProcessCtl(const ProcessID proc, const ProcessOperation op, const Address addr=0, const Address output=0)
Prototype for user applications.
Definition ProcessCtl.h:93
API::Result VMShare(const ProcessID pid, const API::Operation op, ProcessShares::MemoryShare *share)
Prototype for user applications.
Definition VMShare.h:41
@ EnterSleep
Definition ProcessCtl.h:51
@ InfoTimer
Definition ProcessCtl.h:49
@ GetPID
Definition ProcessCtl.h:41
@ Wakeup
Definition ProcessCtl.h:53
#define PAGESIZE
ARM uses 4K pages.
Definition ARMConstant.h:97
#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 long Address
A memory address.
Definition Types.h:131
slong Error
Error code defined in Error.h.
Definition Types.h:159
#define ERROR(msg)
Output an error message.
Definition Log.h:61
#define WARNING(msg)
Output a warning message.
Definition Log.h:68
#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
Memory range.
Definition Memory.h:56
Address virt
Virtual address.
Definition Memory.h:57
Message handler function (dummy) container.
MessageHandler(const Func func, const bool reply)
Constructor function.
const bool operator==(const struct MessageHandler< Func > &h) const
const bool operator!=(const struct MessageHandler< Func > &h) const
const Func exec
Handler function.
const bool sendReply
Whether to send a reply or not.
Represents a process which may run on the host.
ProcessEventType type
ProcessShares::MemoryShare share
ProcessID pid
Remote process id for this share.
Size tagId
Share tag id is defined by the application.
Memory::Range range
Physical memory address range.
Size coreId
CoreId for the other process.
System information structure.
Definition SystemInfo.h:80
uint coreId
Core Identifier.
Definition SystemInfo.h:105
Timer information structure.
Definition Timer.h:43
u32 ticks
Definition Timer.h:44
Size frequency
Definition Timer.h:45