Resources | developer.brewmp.com Resources | developer.brewmp.com

Developer

resources

Sharing between processes

Clients can use IMemGroup to create and manage regions of memory for sharing between processes.

Using shared memory efficiently and safely requires a thorough understanding of OS Services shared memory operations. Shared memory is often problematic from a security perspective. It is a mechanism that is easily misused by applications. Coordination of multiple processes accessing the same memory can lead to race conditions, which can introduce subtle bugs. The generally coarse granularity of shared memory is also problematic. However, OS Services uses of shared memory are restricted and of the sort that avoid many of the potential security problems.

OS Services grants access to shared memory by passing an IMemRegion1 service object from one process to another process.

The safest and recommended method of memory sharing follows this sequence:

  1. Party A creates an IMemGroup object and uses this object to create a shared memory region (IMemRegion1).
  2. Party A may use IMemSpace to map this region into its own address space.
  3. Party A passes an IMemRegion1 object to party B. The object could be an input parameter when A invokes B, or an output parameter when B invokes A.
  4. B invokes its own IMemSpace object, passing it the region.
  5. B's IMemSpace establishes the mapping for B, returning an IMemMap object to B along with the virtual address at which the memory is mapped.
  6. B accesses the memory.

The following example illustrates how to share a memory region between two processes:

In component A:

IMemGroup* piMemGroup = NULL;
   IMemSpace* piMemSpace = NULL;
   IMemRegion1* piMemRegion1 = NULL;
   uint32 cbBuf = 4096;
   uint32 cbBufReq;
   PhysMemInfo physInfo;
   uint32 nErr = AEE_SUCCESS;

   nErr = IEnv_CreateInstance(pMe->piEnv, AEECLSID_MemGroup,
               (void **)&piMemGroup);
   if (AEE_SUCCESS != nErr) {
      goto bail;
   }

   nErr = IEnv_CreateInstance(pMe->piEnv, AEECLSID_MemSpace,
               (void **)&piMemSpace);
   if (AEE_SUCCESS != nErr) {
      goto bail;
   }

   physInfo.ulStart = MEMREGION_ANYADDR;
   physInfo.ulSize = (uint32)cbBuf;
   physInfo.ulPerms = MEMREGION_ACCESS_READ | MEMREGION_ACCESS_WRITE;

   nErr = IMemGroup_CreateRegion(piMemGroup, 0,
               MEMREGION_ANYADDR, &physInfo, 1,
               MEMREGION_SHARE_COMMON, &piMemRegion1);

   if (AEE_SUCCESS != nErr) {
      goto bail;
   }

   cbBufReq = cbBuf;
   nErr = IMemSpace_MapRegion(piMemSpace, piMemRegion1,
               MEMREGION_ACCESS_READ | MEMREGION_ACCESS_WRITE,
               (uint32)cbBufReq, &pMe->piMemMap,
               (uint32 *)&pMe->pvSharedMemAddr,
               (uint32 *)&cbBuf);

   if (AEE_SUCCESS != nErr) {
      goto bail;
   }
   if (cbBuf < cbBufReq) {
      nErr = AEE_ENOMEMORY;
      goto bail;
   }
   /* Send piMemRegion1 object reference to the Server Object. */
   …
   /* Use the Shared Memory Region */
   …
   /* Release the Mapped region when finished. */
   IQI_RELEASEIF(pMe->piMemMap);

The following figure illustrates this flow:

Component A can then pass piMemRegion1 to the remote side (Component B). On the Component B side, the code would look like this:

/* piMemRegion1 reference is received from Client Object. */
   int nErr = AEE_SUCCESS;
   uint32 nBytesMapped;
   IMemSpace* piMemSpace;

   nErr = IEnv_CreateInstance(pMe->piEnv, AEECLSID_MemSpace,
               (void**)&piMemSpace);
   if(AEE_SUCCESS != nErr)
   {
      goto bail;
   }

   nErr = IMemSpace_MapRegion(piMemSpace, piMemRegion1,
               MEMREGION_ACCESS_READ|MEMREGION_ACCESS_WRITE,
               4096, &pMe->piMemMap,
               (uint32*)&pMe->pvSharedMemAddr,
               &nBytesMapped);

   if(AEE_SUCCESS != nErr || nBytesMapped < 4096)
   {
      goto bail;
   }
   …
   /* Use Shared Memory Region */
   …
   /* Release the Mapped region when finished. */
   IQI_Release(pMe->piMemMap);

The following figure illustrates this flow: