FreeNOS
ChannelClient.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/User.h>
19 #include <Log.h>
20 #include <HashIterator.h>
21 #include "ChannelClient.h"
22 #include "MemoryChannel.h"
23 
26  , m_pid(ProcessCtl(SELF, GetPID, 0))
27 {
28 }
29 
31 {
32 }
33 
35 {
36  return m_registry;
37 }
38 
40 {
41  return Success;
42 }
43 
45 {
46  Address prodAddr, consAddr;
47  const SystemInformation info;
48 
49  // Allocate consumer
50  MemoryChannel *cons = new MemoryChannel(Channel::Consumer, messageSize);
51  if (!cons)
52  {
53  ERROR("failed to allocate consumer MemoryChannel");
54  return OutOfMemory;
55  }
56 
57  // Allocate producer
58  MemoryChannel *prod = new MemoryChannel(Channel::Producer, messageSize);
59  if (!prod)
60  {
61  ERROR("failed to allocate producer MemoryChannel");
62  delete cons;
63  return OutOfMemory;
64  }
65 
66  // Call VMShare to create shared memory mapping for MemoryChannel.
68  share.pid = pid;
69  share.coreId = info.coreId;
70  share.tagId = 0;
71  share.range.size = PAGESIZE * 4;
72  share.range.virt = 0;
73  share.range.phys = 0;
75 
76  // Create shared memory mapping
77  Error r = VMShare(pid, API::Create, &share);
78  if (r != API::Success)
79  {
80  // It is possible that the other Process is still detaching
81  // from a previous shared memory channel (e.g. if a PID is re-used)
82  for (Size i = 0; i < MaxConnectRetries && r == API::TemporaryUnavailable; i++)
83  {
84  ProcessCtl(pid, Wakeup, 0);
86  r = VMShare(pid, API::Create, &share);
87  }
88 
89  if (r != API::Success)
90  {
91  ERROR("VMShare failed for PID " << pid << ": result = " << (int) r);
92  delete prod;
93  delete cons;
94  return IOError;
95  }
96  }
97 
98  // ProcessID's determine where the producer/consumer is placed
99  if (m_pid < pid)
100  {
101  prodAddr = share.range.virt;
102  consAddr = share.range.virt + (PAGESIZE * 2);
103  }
104  else
105  {
106  prodAddr = share.range.virt + (PAGESIZE * 2);
107  consAddr = share.range.virt;
108  }
109 
110  // Setup producer memory address
111  MemoryChannel::Result memResult = prod->setVirtual(prodAddr, prodAddr + PAGESIZE);
112  if (memResult != MemoryChannel::Success)
113  {
114  ERROR("failed to set producer virtual memory for PID " <<
115  pid << " to " << (void *) prodAddr <<
116  ": result = " << (int) memResult);
117  delete prod;
118  delete cons;
119  return IOError;
120  }
121 
122  // Setup consumer memory address
123  memResult = cons->setVirtual(consAddr, consAddr + PAGESIZE);
124  if (memResult != MemoryChannel::Success)
125  {
126  ERROR("failed to set consumer virtual memory for PID " <<
127  pid << " to " << (void *) consAddr <<
128  ": result = " << (int) memResult);
129  delete prod;
130  delete cons;
131  return IOError;
132  }
133 
134  // Register channels
135  m_registry.registerConsumer(pid, cons);
136  m_registry.registerProducer(pid, prod);
137  return Success;
138 }
139 
141 {
142  assert(msgSize > 0);
143 
145  {
146  if (i.current()->read(buffer) == Channel::Success)
147  {
148  *pid = i.key();
149  return Success;
150  }
151  }
152 
153  return NotFound;
154 }
155 
157  void *buffer,
158  const Size msgSize,
159  CallbackFunction *callback)
160 {
161  Request *req = 0;
162  Size identifier = 0;
163  Channel *ch = findProducer(pid, msgSize);
164  if (!ch)
165  {
166  ERROR("failed to find producer for PID " << pid);
167  return NotFound;
168  }
169 
170  // Find request object
171  for (Size i = 0; i < m_requests.count(); i++)
172  {
173  req = m_requests.get(i);
174  if (!req->active)
175  {
176  identifier = i;
177  break;
178  }
179  }
180 
181  // Allocate new request object if none available
182  if (!req || req->active)
183  {
184  req = new Request;
185  assert(req != NULL);
186  req->message = (ChannelMessage *) new u8[ch->getMessageSize()];
187  assert(req->message != NULL);
188 
189  if (!m_requests.insert(identifier, req))
190  {
191  ERROR("failed to insert Request");
192  return OutOfMemory;
193  }
194  }
195 
196  // Fill request object
197  MemoryBlock::copy(req->message, buffer, ch->getMessageSize());
198  req->pid = pid;
199  req->message->identifier = identifier;
201  req->callback = callback;
202  req->active = true;
203 
204  DEBUG("sending request with id = " << req->message->identifier << " to PID " << pid);
205 
206  // Try to send the message
207  Channel::Result r = ch->write(req->message);
208  if (r != Channel::Success)
209  {
210  ERROR("failed to write to Channel for PID " << pid << ": result = " << (int) r);
211  req->active = false;
212  return IOError;
213  }
214 
215  // Wakeup the receiver
216  ProcessCtl(pid, Wakeup, 0);
217  return Success;
218 }
219 
221  ChannelMessage *msg)
222 {
223  const Size count = m_requests.count();
224 
225  for (Size i = 0; i < count; i++)
226  {
227  Request *req = m_requests.get(i);
228 
229  if (req->active &&
230  req->pid == pid &&
231  req->message->identifier == msg->identifier)
232  {
233  req->callback->execute(msg);
234  req->active = false;
235  return Success;
236  }
237  }
238 
239  return NotFound;
240 }
241 
242 
244 {
245  Channel *ch = m_registry.getConsumer(pid);
246  if (ch)
247  return ch;
248 
249  // Try to connect
250  Result r = connect(pid, msgSize);
251  if (r != Success)
252  {
253  ERROR("failed to connect to PID " << pid << ": result = " << (int) r);
254  return ZERO;
255  }
256 
257  return m_registry.getConsumer(pid);
258 }
259 
261 {
262  Channel *ch = m_registry.getProducer(pid);
263  if (ch)
264  return ch;
265 
266  // Try to connect
267  Result r = connect(pid, msgSize);
268  if (r != Success)
269  {
270  ERROR("failed to connect to PID " << pid << ": result = " << (int) r);
271  return ZERO;
272  }
273 
274  return m_registry.getProducer(pid);
275 }
276 
278 {
279  Channel *ch = findConsumer(pid, msgSize);
280  if (!ch)
281  {
282  ERROR("failed to find consumer for PID " << pid);
283  return NotFound;
284  }
285 
286  while (ch->read(buffer) != Channel::Success)
288 
289  return Success;
290 }
291 
292 ChannelClient::Result ChannelClient::syncSendTo(const void *buffer, const Size msgSize, const ProcessID pid)
293 {
294  Channel *ch = findProducer(pid, msgSize);
295  if (!ch)
296  {
297  ERROR("failed to find producer for PID " << pid);
298  return NotFound;
299  }
300 
301  while (true)
302  {
303  switch (ch->write(buffer))
304  {
305  case Channel::Success:
306  ProcessCtl(pid, Wakeup, 0);
307  return Success;
308 
310  ProcessCtl(pid, Wakeup, 0);
311  break;
312 
313  default:
314  return IOError;
315  }
316  ProcessCtl(SELF, Schedule, 0);
317  }
318 
319  return IOError;
320 }
321 
323 {
324  Result result = syncSendTo(buffer, msgSize, pid);
325  if (result != Success)
326  {
327  ERROR("syncSendTo failed to PID " << pid << ": result = " << (int) result);
328  return result;
329  }
330 
331  result = syncReceiveFrom(buffer, msgSize, pid);
332  if (result != Success)
333  {
334  ERROR("syncReceiveFrom failed from PID " << pid << ": result = " << (int) result);
335  return result;
336  }
337 
338  return Success;
339 }
Channel
Unidirectional point-to-point messaging channel.
Definition: Channel.h:34
MemoryBlock::copy
static Size copy(void *dest, const void *src, Size count)
Copy memory from one place to another.
Definition: MemoryBlock.cpp:36
ChannelClient::ChannelClient
ChannelClient()
Constructor.
Definition: ChannelClient.cpp:24
ProcessShares::MemoryShare::tagId
Size tagId
Share tag id is defined by the application.
Definition: ProcessShares.h:57
Channel::Success
@ Success
Definition: Channel.h:43
ChannelClient.h
StrictSingleton
Singleton design pattern: only one instance is allowed.
Definition: Singleton.h:39
ProcessShares::MemoryShare
Definition: ProcessShares.h:48
ProcessShares::MemoryShare::pid
ProcessID pid
Remote process id for this share.
Definition: ProcessShares.h:51
MemoryChannel::setVirtual
Result setVirtual(const Address data, const Address feedback, const bool hardReset=true)
Set memory pages by virtual address.
Definition: MemoryChannel.cpp:54
ChannelClient::m_requests
Index< Request, MaximumRequests > m_requests
Contains ongoing requests.
Definition: ChannelClient.h:232
CallbackFunction::execute
virtual void execute(void *parameter)=0
Execute the callback.
ChannelClient::NotFound
@ NotFound
Definition: ChannelClient.h:88
ChannelClient::receiveAny
virtual Result receiveAny(void *buffer, const Size msgSize, ProcessID *pid)
Try to receive message from any channel.
Definition: ChannelClient.cpp:140
CallbackFunction
Represents a callback function.
Definition: Callback.h:34
ChannelClient::IOError
@ IOError
Definition: ChannelClient.h:86
Memory::Writable
@ Writable
Definition: Memory.h:42
Memory::User
@ User
Definition: Memory.h:44
HashIterator
Iterate through a HashTable.
Definition: HashIterator.h:39
PAGESIZE
#define PAGESIZE
ARM uses 4K pages.
Definition: ARMConstant.h:97
HashIterator.h
ChannelMessage::type
Type type
Message type is either a request or response.
Definition: ChannelMessage.h:48
ProcessID
u32 ProcessID
Process Identification Number.
Definition: Types.h:140
ChannelClient::syncReceiveFrom
virtual Result syncReceiveFrom(void *buffer, const Size msgSize, const ProcessID pid)
Synchronous receive from one process.
Definition: ChannelClient.cpp:277
Wakeup
@ Wakeup
Definition: ProcessCtl.h:53
ChannelClient::Success
@ Success
Definition: ChannelClient.h:83
Address
unsigned long Address
A memory address.
Definition: Types.h:131
VMShare
API::Result VMShare(const ProcessID pid, const API::Operation op, ProcessShares::MemoryShare *share)
Prototype for user applications.
Definition: VMShare.h:41
ProcessShares::MemoryShare::range
Memory::Range range
Physical memory address range.
Definition: ProcessShares.h:60
ChannelClient::findProducer
Channel * findProducer(const ProcessID pid, const Size msgSize)
Get producer for a process.
Definition: ChannelClient.cpp:260
SystemInformation::coreId
uint coreId
Core Identifier.
Definition: SystemInfo.h:105
ProcessCtl
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
ChannelClient::Request::callback
CallbackFunction * callback
Definition: ChannelClient.h:62
ChannelClient::OutOfMemory
@ OutOfMemory
Definition: ChannelClient.h:87
ProcessShares::MemoryShare::coreId
Size coreId
CoreId for the other process.
Definition: ProcessShares.h:54
ChannelRegistry::getConsumer
Channel * getConsumer(const ProcessID pid)
Get one consumer.
Definition: ChannelRegistry.cpp:35
Memory::Readable
@ Readable
Definition: Memory.h:41
ChannelRegistry::registerConsumer
Result registerConsumer(const ProcessID pid, Channel *channel)
Register consumer channel.
Definition: ChannelRegistry.cpp:63
Log.h
ChannelClient::connect
virtual Result connect(const ProcessID pid, const Size msgSize)
Connect to a process.
Definition: ChannelClient.cpp:44
Channel::read
virtual Result read(void *buffer)
Read a message.
Definition: Channel.cpp:35
Channel::getMessageSize
const Size getMessageSize() const
Get message size.
Definition: Channel.cpp:30
SELF
#define SELF
Definition: ProcessID.h:35
ChannelClient::~ChannelClient
virtual ~ChannelClient()
Destructor.
Definition: ChannelClient.cpp:30
ChannelClient::Request
Holds an outgoing request.
Definition: ChannelClient.h:57
DEBUG
#define DEBUG(msg)
Output a debug message to standard output.
Definition: Log.h:89
ChannelClient::MaxConnectRetries
static const Size MaxConnectRetries
Maximum number of retries for establishing new connection.
Definition: ChannelClient.h:52
Channel::write
virtual Result write(const void *buffer)
Write a message.
Definition: Channel.cpp:40
Memory::Range::phys
Address phys
Physical address.
Definition: Memory.h:58
GetPID
@ GetPID
Definition: ProcessCtl.h:41
ChannelRegistry::getConsumers
HashTable< ProcessID, Channel * > & getConsumers()
Get all consumers.
Definition: ChannelRegistry.cpp:53
Error
slong Error
Error code defined in Error.h.
Definition: Types.h:159
ChannelClient::syncSendTo
virtual Result syncSendTo(const void *buffer, const Size msgSize, const ProcessID pid)
Synchronous send to one process.
Definition: ChannelClient.cpp:292
NULL
#define NULL
NULL means zero.
Definition: Macros.h:39
Channel::Consumer
@ Consumer
Definition: Channel.h:59
Size
unsigned int Size
Any sane size indicator cannot go negative.
Definition: Types.h:128
ChannelClient::syncSendReceive
virtual Result syncSendReceive(void *buffer, const Size msgSize, const ProcessID pid)
Synchronous send and receive to/from one process.
Definition: ChannelClient.cpp:322
MemoryChannel
Unidirectional point-to-point channel using shared memory.
Definition: MemoryChannel.h:43
EnterSleep
@ EnterSleep
Definition: ProcessCtl.h:51
ChannelMessage::identifier
Size identifier
Optional request identifier.
Definition: ChannelMessage.h:51
ChannelRegistry::registerProducer
Result registerProducer(const ProcessID pid, Channel *channel)
Register producer channel.
Definition: ChannelRegistry.cpp:71
Channel::Producer
@ Producer
Definition: Channel.h:58
ChannelClient::Result
Result
Result codes.
Definition: ChannelClient.h:81
ChannelClient
Client for using Channels on the local processor.
Definition: ChannelClient.h:44
assert
#define assert(exp)
Insert program diagnostics.
Definition: assert.h:60
ChannelClient::getRegistry
ChannelRegistry & getRegistry()
Get channel registry.
Definition: ChannelClient.cpp:34
ERROR
#define ERROR(msg)
Output an error message.
Definition: Log.h:61
ChannelClient::Request::pid
ProcessID pid
Definition: ChannelClient.h:60
SystemInformation
System information structure.
Definition: SystemInfo.h:79
ChannelClient::initialize
virtual Result initialize()
Initialize the ChannelClient.
Definition: ChannelClient.cpp:39
u8
unsigned char u8
Unsigned 8-bit number.
Definition: Types.h:59
API::TemporaryUnavailable
@ TemporaryUnavailable
Definition: API.h:78
ChannelClient::sendRequest
virtual Result sendRequest(const ProcessID pid, void *buffer, const Size msgSize, CallbackFunction *callback)
Send asynchronous request message.
Definition: ChannelClient.cpp:156
Schedule
@ Schedule
Definition: ProcessCtl.h:52
Channel::Result
Result
Result codes.
Definition: Channel.h:41
API::Success
@ Success
Definition: API.h:70
ChannelRegistry
Registration for Channels.
Definition: ChannelRegistry.h:37
Memory::Range::virt
Address virt
Virtual address.
Definition: Memory.h:57
MemoryChannel.h
ChannelClient::Request::message
ChannelMessage * message
Definition: ChannelClient.h:61
HashIterator::hasCurrent
virtual bool hasCurrent() const
Check if there is a current item.
Definition: HashIterator.h:83
ChannelRegistry::getProducer
Channel * getProducer(const ProcessID pid)
Get one producer.
Definition: ChannelRegistry.cpp:44
ChannelClient::Request
struct ChannelClient::Request Request
Holds an outgoing request.
Memory::Range::size
Size size
Size in number of bytes.
Definition: Memory.h:59
Memory::Range::access
Access access
Page access flags.
Definition: Memory.h:60
ChannelClient::Request::active
bool active
Definition: ChannelClient.h:59
ChannelClient::findConsumer
Channel * findConsumer(const ProcessID pid, const Size msgSize)
Get consumer for a process.
Definition: ChannelClient.cpp:243
ZERO
#define ZERO
Zero value.
Definition: Macros.h:43
Channel::ChannelFull
@ ChannelFull
Definition: Channel.h:48
API::Create
@ Create
Definition: API.h:93
ChannelClient::m_pid
const ProcessID m_pid
Current Process ID.
Definition: ChannelClient.h:235
ChannelClient::processResponse
virtual Result processResponse(const ProcessID pid, ChannelMessage *msg)
Process a response message.
Definition: ChannelClient.cpp:220
ChannelClient::m_registry
ChannelRegistry m_registry
Contains registered channels.
Definition: ChannelClient.h:229
ChannelMessage
Basic message format for sending on a Channel.
Definition: ChannelMessage.h:34
ChannelMessage::Request
@ Request
Definition: ChannelMessage.h:43