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
29
33
38
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
144 for (HashIterator<ProcessID, Channel *> i(m_registry.getConsumers()); i.hasCurrent(); i++)
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
292ChannelClient::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 }
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}
@ Success
Definition API.h:70
@ TemporaryUnavailable
Definition API.h:78
@ Create
Definition API.h:93
Represents a callback function.
Definition Callback.h:35
virtual void execute(void *parameter)=0
Execute the callback.
Client for using Channels on the local processor.
virtual Result sendRequest(const ProcessID pid, void *buffer, const Size msgSize, CallbackFunction *callback)
Send asynchronous request message.
Index< Request, MaximumRequests > m_requests
Contains ongoing requests.
ChannelRegistry m_registry
Contains registered channels.
virtual Result processResponse(const ProcessID pid, ChannelMessage *msg)
Process a response message.
virtual Result syncSendReceive(void *buffer, const Size msgSize, const ProcessID pid)
Synchronous send and receive to/from one process.
Channel * findConsumer(const ProcessID pid, const Size msgSize)
Get consumer for a process.
Result
Result codes.
virtual ~ChannelClient()
Destructor.
virtual Result initialize()
Initialize the ChannelClient.
ChannelRegistry & getRegistry()
Get channel registry.
virtual Result receiveAny(void *buffer, const Size msgSize, ProcessID *pid)
Try to receive message from any channel.
static const Size MaxConnectRetries
Maximum number of retries for establishing new connection.
virtual Result connect(const ProcessID pid, const Size msgSize)
Connect to a process.
const ProcessID m_pid
Current Process ID.
Channel * findProducer(const ProcessID pid, const Size msgSize)
Get producer for a process.
virtual Result syncSendTo(const void *buffer, const Size msgSize, const ProcessID pid)
Synchronous send to one process.
ChannelClient()
Constructor.
virtual Result syncReceiveFrom(void *buffer, const Size msgSize, const ProcessID pid)
Synchronous receive from one process.
Basic message format for sending on a Channel.
Size identifier
Optional request identifier.
Type type
Message type is either a request or response.
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 registerConsumer(const ProcessID pid, Channel *channel)
Register consumer channel.
Channel * getConsumer(const ProcessID pid)
Get one consumer.
Unidirectional point-to-point messaging channel.
Definition Channel.h:35
const Size getMessageSize() const
Get message size.
Definition Channel.cpp:30
@ 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
Result
Result codes.
Definition Channel.h:42
@ Success
Definition Channel.h:43
@ ChannelFull
Definition Channel.h:48
Iterate through a HashTable.
static Size copy(void *dest, const void *src, Size count)
Copy memory from one place to another.
Unidirectional point-to-point channel using shared memory.
Result setVirtual(const Address data, const Address feedback, const bool hardReset=true)
Set memory pages by virtual address.
Singleton design pattern: only one instance is allowed.
Definition Singleton.h:40
#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
@ GetPID
Definition ProcessCtl.h:41
@ Schedule
Definition ProcessCtl.h:52
@ 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
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
unsigned char u8
Unsigned 8-bit number.
Definition Types.h:59
@ User
Definition Memory.h:44
@ Readable
Definition Memory.h:41
@ Writable
Definition Memory.h:42
Holds an outgoing request.
CallbackFunction * callback
ChannelMessage * message
Size size
Size in number of bytes.
Definition Memory.h:59
Address phys
Physical address.
Definition Memory.h:58
Address virt
Virtual address.
Definition Memory.h:57
Access access
Page access flags.
Definition Memory.h:60
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