The Pedigree Project  0.1
system/kernel/core/process/Ipc.cc
1 /*
2  * Copyright (c) 2008-2014, Pedigree Developers
3  *
4  * Please see the CONTRIB file in the root of the source tree for a full
5  * list of contributors.
6  *
7  * Permission to use, copy, modify, and distribute this software for any
8  * purpose with or without fee is hereby granted, provided that the above
9  * copyright notice and this permission notice appear in all copies.
10  *
11  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18  */
19 
20 #include "pedigree/kernel/process/Ipc.h"
21 #include "pedigree/kernel/LockGuard.h"
22 #include "pedigree/kernel/processor/MemoryRegion.h"
23 #include "pedigree/kernel/processor/PhysicalMemoryManager.h"
24 #include "pedigree/kernel/processor/Processor.h"
25 #include "pedigree/kernel/processor/ProcessorInformation.h"
26 #include "pedigree/kernel/processor/VirtualAddressSpace.h"
27 #include "pedigree/kernel/utilities/MemoryPool.h"
29 #include "pedigree/kernel/utilities/Result.h"
30 
31 using namespace Ipc;
32 
33 #define MEMPOOL_BUFF_SIZE 4096
34 #define MEMPOOL_BASE_SIZE 1024
35 
36 static MemoryPool __ipc_mempool("IPC Message Pool");
37 
38 static RadixTree<IpcEndpoint *> __endpoints;
39 
40 IpcEndpoint *Ipc::getEndpoint(String &name)
41 {
42  RadixTree<IpcEndpoint *>::LookupType result = __endpoints.lookup(name);
43  return result.hasValue() ? result.value() : nullptr;
44 }
45 
46 void Ipc::createEndpoint(String &name)
47 {
48  if (__endpoints.lookup(name).hasValue())
49  return;
50  __endpoints.insert(name, new IpcEndpoint(name));
51 }
52 
53 void Ipc::removeEndpoint(String &name)
54 {
55  if (!__endpoints.lookup(name).hasValue())
56  return;
57  __endpoints.remove(name);
58 }
59 
60 bool Ipc::send(IpcEndpoint *pEndpoint, IpcMessage *pMessage, bool bAsync)
61 {
62  if (!(pEndpoint && pMessage))
63  return false;
64 
65  Mutex *pMutex = pEndpoint->pushMessage(pMessage, bAsync);
66  if (!pMutex)
67  return false;
68 
69  // Block if we're allowed to.
70  if (!bAsync)
71  {
72  pMutex->acquire();
73  delete pMutex;
74  }
75 
76  return true;
77 }
78 
79 bool Ipc::recv(IpcEndpoint *pEndpoint, IpcMessage **pMessage, bool bAsync)
80 {
81  if (!(pEndpoint && pMessage))
82  return false;
83 
84  IpcMessage *pMsg = pEndpoint->getMessage(!bAsync);
85  if (pMsg)
86  {
90  *pMessage = new IpcMessage(*pMsg);
91 
92  return true;
93  }
94 
95  return false;
96 }
97 
98 Mutex *IpcEndpoint::pushMessage(IpcMessage *pMessage, bool bAsync)
99 {
100  LockGuard<Mutex> guard(m_QueueLock);
101 
102  QueuedMessage *p = new QueuedMessage;
103  p->pMessage = pMessage;
104  p->pMutex = new Mutex(true);
105  p->bAsync = bAsync;
106 
107  m_Queue.pushBack(p);
108  m_QueueSize.release();
109 
110  return p->pMutex;
111 }
112 
113 IpcMessage *IpcEndpoint::getMessage(bool bBlock)
114 {
115  // Handle the case where m_QueueSize acquire() returns but the queue is
116  // already emptied by the time we acquire the Mutex.
117  QueuedMessage *p = 0;
118  while (p == 0)
119  {
120  bool b = m_QueueSize.tryAcquire();
121  if (!b)
122  {
123  if (!bBlock)
124  return 0;
125  else
126  {
127  m_QueueSize.acquire();
128  }
129  }
130 
131  m_QueueLock.acquire();
132  p = m_Queue.popFront();
133  m_QueueLock.release();
134  }
135 
136  IpcMessage *pReturn = p->pMessage;
137 
138  p->pMutex->release();
139  if (p->bAsync)
140  {
141  delete p->pMutex;
142  }
143  delete p;
144 
145  return pReturn;
146 }
147 
148 Ipc::IpcMessage::IpcMessage() : nPages(1), m_vAddr(0), m_pMemRegion(0)
149 {
150  if (!__ipc_mempool.initialised())
151  {
152  if (!__ipc_mempool.initialise(MEMPOOL_BASE_SIZE, MEMPOOL_BUFF_SIZE))
153  {
154  ERROR("IpcMessage: memory pool could not be initialised.");
155  return;
156  }
157  }
158 
159  // Allocate the message.
160  uintptr_t msg = __ipc_mempool.allocate();
161  if (msg)
162  {
163  // Remap to user read/write.
164  Processor::information().getVirtualAddressSpace().setFlags(
165  reinterpret_cast<void *>(msg), VirtualAddressSpace::Write);
166 
167  m_vAddr = msg;
168  }
169  else
170  {
171  ERROR("IpcMessage: no memory available.");
172  return;
173  }
174 }
175 
176 Ipc::IpcMessage::IpcMessage(size_t nBytes, uintptr_t regionHandle)
177  : nPages(0), m_vAddr(0), m_pMemRegion(0)
178 {
179  nPages = (nBytes / 4096) + 1;
180 
181  if (nPages == 1) // Don't be silly with memory regions and such when the
182  // pool is adequate.
183  IpcMessage();
184  else
185  {
186  MemoryRegion *pRegion = reinterpret_cast<MemoryRegion *>(regionHandle);
187  if (!pRegion)
188  {
189  // Need to allocate RAM for this space.
190  m_pMemRegion = new MemoryRegion("IPC Message");
191  if (!PhysicalMemoryManager::instance().allocateRegion(
194  {
195  delete m_pMemRegion;
196  m_pMemRegion = 0;
197 
198  ERROR("IpcMessage: region allocation failed.");
199  }
200  }
201  else
202  {
203  // Need to remap the given region into this address space, if it
204  // isn't mapped in already.
205  void *pAddress = pRegion->virtualAddress();
206  physical_uintptr_t phys = pRegion->physicalAddress();
207 
208  VirtualAddressSpace &va =
209  Processor::information().getVirtualAddressSpace();
210  if (va.isMapped(pAddress))
211  {
212  size_t ignore = 0;
213  physical_uintptr_t map_phys = 0;
214  va.getMapping(pAddress, map_phys, ignore);
215 
216  // This works because we ask for continuous physical memory.
217  // Even if we didn't, it would still be a valid check. We would
218  // just have to verify a few more physical pages to be 100%
219  // certain.
220  if (phys == map_phys)
221  {
222  m_pMemRegion = pRegion;
223  return;
224  }
225  }
226 
227  // Create the region.
228  m_pMemRegion = new MemoryRegion("IPC Message");
229  if (!PhysicalMemoryManager::instance().allocateRegion(
232  {
233  delete m_pMemRegion;
234  m_pMemRegion = 0;
235 
236  ERROR("IpcMessage: region allocation (via handle) failed.");
237  }
238  }
239  }
240 }
241 
243 {
246  if (m_pMemRegion)
247  {
248  delete m_pMemRegion;
249  }
250  else if (m_vAddr)
251  {
252  __ipc_mempool.free(m_vAddr);
253  }
254 }
255 
257 {
258  if (m_vAddr)
259  return reinterpret_cast<void *>(m_vAddr);
260  else if (m_pMemRegion)
261  return m_pMemRegion->virtualAddress();
262  else
263  return 0;
264 }
265 
267 {
268  if (nPages > 1)
269  return m_pMemRegion;
270  else
271  return 0;
272 }
uintptr_t m_vAddr
Virtual address of a message when m_pMemRegion is invalid.
A key/value dictionary for string keys.
Definition: RadixTree.h:45
static PhysicalMemoryManager & instance()
bool acquire(size_t n=1, size_t timeoutSecs=0, size_t timeoutUsecs=0)
Definition: Semaphore.h:62
virtual void getMapping(void *virtualAddress, physical_uintptr_t &physicalAddress, size_t &flags)=0
virtual bool isMapped(void *virtualAddress)=0
void insert(const String &key, const T &value)
Definition: RadixTree.h:347
Definition: Mutex.h:58
Definition: String.h:49
Definition: Result.h:36
static ProcessorInformation & information()
Definition: Processor.cc:45
bool initialised()
Call if you aren&#39;t certain that the object has been initialised yet.
Definition: MemoryPool.h:73
Result< T, bool > lookup(const String &key) const
Definition: RadixTree.h:462
void release(size_t n=1)
Definition: Semaphore.cc:239
Special memory entity in the kernel&#39;s virtual address space.
Definition: MemoryRegion.h:35
uintptr_t allocate()
Definition: MemoryPool.cc:176
physical_uintptr_t physicalAddress() const
Definition: MemoryRegion.cc:44
bool initialise(size_t poolSize, size_t bufferSize=1024)
Definition: MemoryPool.cc:128
void free(uintptr_t buffer)
Frees an allocated buffer, allowing it to be used elsewhere.
Definition: MemoryPool.cc:251
void * virtualAddress() const
Definition: MemoryRegion.cc:39
#define ERROR(text)
Definition: Log.h:82
bool tryAcquire(size_t n=1)
Definition: Semaphore.cc:223
void remove(const String &key)
Definition: RadixTree.h:511
Implements a Radix Tree, a kind of Trie with compressed keys.