예제 #1
0
/**
 * Change the protection of one or more pages in an allocation.
 *
 * (This will of course only work correctly on memory allocated by kHlpPageAlloc().)
 *
 * @returns 0 on success, non-zero OS status code on failure.
 * @param   pv          First page. Page aligned.
 * @param   cb          Number of bytes. Page aligned.
 * @param   enmProt     The new protection. Copy-on-write is invalid.
 */
KHLP_DECL(int) kHlpPageProtect(void *pv, KSIZE cb, KPROT enmProt)
{
#if K_OS == K_OS_DARWIN \
 || K_OS == K_OS_FREEBSD \
 || K_OS == K_OS_LINUX \
 || K_OS == K_OS_NETBSD \
 || K_OS == K_OS_OPENBSD \
 || K_OS == K_OS_SOLARIS
    int rc;

    rc = kHlpSys_mprotect(pv, cb, kHlpPageProtToNative(enmProt));
    if (!rc)
        return 0;
    /** @todo convert errno -> kErrors */
    kHlpAssert(0);
    return rc;

#elif K_OS == K_OS_OS2
    APIRET      rc;
    ULONG       fFlags = kHlpPageProtToNative(enmProt);

    /*
     * The non-stub pages.
     */
    rc = DosSetMem(pv, cb, fFlags);
    if (rc && fFlags != PAG_DECOMMIT)
        rc = DosSetMem(pv, cb, fFlags | PAG_COMMIT);
    if (rc)
    {
        /* Try page by page. */
        while (cb > 0)
        {
            rc = DosSetMem(pv, 0x1000, fFlags);
            if (rc && fFlags != PAG_DECOMMIT)
                rc = DosSetMem(pv, 0x1000, fFlags | PAG_COMMIT);
            if (rc)
                return rc;
            pv = (void *)((KUPTR)pv + 0x1000);
            cb -= 0x1000;
        }
    }
    kHlpAssert(!rc);
    return rc;

#elif  K_OS == K_OS_WINDOWS
    DWORD fOldProt = 0;
    DWORD fProt = kHlpPageProtToNative(enmProt);
    int rc = 0;

    if (!VirtualProtect(pv, cb, fProt, &fOldProt))
    {
        rc = GetLastError();
        kHlpAssert(0);
    }
    return rc;
#else
# error "port me"
#endif
}
예제 #2
0
파일: shared.c 프로젝트: bitwiseworks/libcx
/*
 * @todo Currently we reserve a static block of HEAP_SIZE at LIBCx init
 * which we commit/release as needed. The disadvantage is obvious - we
 * constantly occupy the address space that could be needed for other
 * purposes, but limit the max memory size which may be not enough under
 * certain LIBCx load. But in order to allow for dynamic allocation of
 * shared memory we need to track all proccess IDs that are currently
 * using LIBCx so that we give them the newly allocated shared memory.
 * This is for later. See https://github.com/bitwiseworks/libcx/issues/9.
 */
static void *mem_alloc(Heap_t h, size_t *psize, int *pclean)
{
  APIRET arc;
  char *mem;
  size_t size;

  TRACE("psize %d\n", *psize);

  /* Round requested size up to HEAP_INC_SIZE */
  size = (*psize + HEAP_INC_SIZE - 1) / HEAP_INC_SIZE * HEAP_INC_SIZE;
  if (size + gpData->size > HEAP_SIZE)
  {
    TRACE("out of memory");
    return NULL;
  }

  mem = (char *)gpData + gpData->size;

  /* Commit the new block */
  arc = DosSetMem(mem, size, PAG_DEFAULT | PAG_COMMIT);
  TRACE("DosSetMem(%p, %d) = %ld\n", mem, size, arc);

  if (arc)
    return NULL;

  /* DosAllocSharedMem gives us zeroed mem */
  *pclean = _BLOCK_CLEAN;
  /* Return the actually allocated number of bytes */
  *psize = size;

  gpData->size += size;
  return mem;
}
예제 #3
0
void *os2ldcalloc(size_t num_elem, size_t size_elem) {
	APIRET rc;
	int ret;

	if (FirstTime) {
		if ((rc=DosAllocMem(&os2ldBase,RESERVED_BLOCKS * 4096, 
				PAG_READ | PAG_WRITE | PAG_EXECUTE)) != 0) {
			xf86Msg(X_ERROR,
				"OS2LD: DosAllocMem failed, rc=%d\n",
				rc);
			return NULL;
		}

		/* Now commit the first 128Kb, the rest will 
		 * be done dynamically */
		if ((rc=DosSetMem(os2ldBase,
				  32*4096,
				  PAG_DEFAULT | PAG_COMMIT)) != 0) {
			xf86Msg(X_ERROR,
				"OS2LD: DosSetMem failed, rc=%d\n",rc);
			DosFreeMem(os2ldBase);
			return NULL;
		}
	        os2ldCommitedTop = os2ldBase + 32*4096;
		os2ldTotalCommitedBlocks = 32;
#ifdef DEBUG
		xf86Msg(X_INFO,
			"OS2LD: Initial heap at addr=%p\n",
			os2ldBase);
#endif

		if ((os2ldHeap=_ucreate(os2ldBase,
					32*4096, _BLOCK_CLEAN,
					_HEAP_REGULAR, os2ldAddToHeap, 
					os2ldRemoveFromHeap)) == NULL) {
			xf86Msg(X_ERROR,
				"OS2LD: heap creation failed\n");
			DosFreeMem(os2ldBase);
			return NULL;
		}
	
		if ((ret=_uopen(os2ldHeap)) != 0) {
			xf86Msg(X_ERROR,
				"OS2LD: heap open failed\n");
			ret = _udestroy(os2ldHeap,_FORCE);
			DosFreeMem(os2ldBase);
			return(NULL);
		}

		FirstTime = FALSE;

#ifdef DEBUG
		xf86Msg(X_INFO,"OS2LD: Created module heap at addr=%p\n",
			os2ldHeap);
#endif
	}

	return _ucalloc(os2ldHeap,num_elem,size_elem);
}
예제 #4
0
ULONG APIENTRY  FileExceptionHandler( PEXCEPTIONREPORTRECORD pReport,
                             struct _EXCEPTIONREGISTRATIONRECORD * pXReg,
                             PCONTEXTRECORD pContext,
                             PVOID pDispatch)

{
    CAMJXRR *   pReg = (CAMJXRR*)pXReg;
    ULONG       ulRtn = XCPT_CONTINUE_SEARCH;
    ULONG       rc = 0;
    ULONG       ulSize;
    ULONG       ulAttr;
    LONG        lOffs;
    char *      pErr = 0;
    PVOID       pMem;

do {
    if (pReport->fHandlerFlags ||
        pReport->ExceptionNum     != XCPT_ACCESS_VIOLATION ||
        pReport->ExceptionAddress == (PVOID)XCPT_DATA_UNKNOWN ||
        pReport->ExceptionInfo[0] != XCPT_READ_ACCESS ||
        pReport->ExceptionInfo[1] == XCPT_DATA_UNKNOWN ||
        pReport->ExceptionInfo[1] <  (ULONG)pReg->pBase ||
        pReport->ExceptionInfo[1] >= (ULONG)pReg->pEnd) {
            printf( "*** Exception not handled - %08lx\n", pReport->ExceptionNum);
            return (ulRtn);
    }

    if (pReg->lFilePtr >= pReg->lEOF)
        ERRMSG( "already at EOF")

    pMem = (PVOID)(pReport->ExceptionInfo[1] & ~0xFFF);
    ulSize = 1;
    ulAttr = 0;

    rc = DosQueryMem( pMem, &ulSize, &ulAttr);
    if (rc)
        ERRMSG( "DosQueryMem")

    if (ulAttr & (PAG_FREE | PAG_COMMIT)) {
        rc = ulAttr;
        ERRMSG( "unexpected memory attributes")
    }

    rc = DosSetMem( pMem, 0x1000, PAG_COMMIT | PAG_DEFAULT);
    if (rc)
        ERRMSG( "DosSetMem")

    lOffs = (BYTE*)pMem - pReg->pBase;
    if (lOffs != pReg->lFilePtr) {
        rc = DosSetFilePtr( pReg->hFile, lOffs, FILE_BEGIN, &pReg->lFilePtr);
        if (rc)
            ERRMSG( "DosSetFilePtr")

        if (lOffs != pReg->lFilePtr) {
            rc = lOffs;
            ERRMSG( "seek beyond EOF")
        }
예제 #5
0
void *os2ldAddToHeap(Heap_t H, size_t *new_size, int *PCLEAN)
{
	PVOID NewBase;
	long adjusted_size;
	long blocks;
	APIRET rc;

	if (H != os2ldHeap) {
		xf86Msg(X_ERROR,
			"OS2LD: Heap corruption in GrowHeap, p=%08x\n",H);
		return NULL;
	}
	NewBase = os2ldCommitedTop;
	adjusted_size = (*new_size/65536) * 65536;
	if ((*new_size % 65536) > 0) 
		adjusted_size += 65536;
	blocks = adjusted_size / 4096;

	if ((os2ldTotalCommitedBlocks + blocks) > RESERVED_BLOCKS) {
		xf86Msg(X_ERROR,
			"OS2LD: Out of memory in GrowHeap\n");
		xf86Msg(X_ERROR,
			"OS2LD: Max available memory is of %ld bytes\n",
			RESERVED_BLOCKS * 4096);
		return NULL;
	}
	if ((rc=DosSetMem(NewBase, adjusted_size, PAG_DEFAULT | PAG_COMMIT)) != 0) {
		xf86Msg(X_ERROR,
			"OS2LD: DosSetMem failed in GrowHeap, size req'd=%d, rc=%d\n",
			adjusted_size,
			rc);
		return NULL;
	}

	os2ldCommitedTop += adjusted_size;
	os2ldTotalCommitedBlocks += blocks;
	*PCLEAN = _BLOCK_CLEAN;
	*new_size = adjusted_size;
#ifdef DEBUG
	xf86Msg(X_INFO,"OS2LD: Heap extended by %d bytes, addr=%p\n",
		adjusted_size, NewBase);
#endif
	return NewBase;
}
예제 #6
0
static void test7( void )
{
    printf("***** Test7: Decommit source memory which is destination memory "
           "of other source memory...\n");

    static const char *p1Str = "6789067890";
    static const char *p3Str = "1234567890";

    char *p1;
    char *p2;
    char *p3;

    DosAllocMem(( PPVOID )&p1, ALLOC_SIZE, fPERM | PAG_COMMIT );

    strcpy( p1, p3Str);
    p2 = copyOnWrite( p1, COPY_SIZE );
    p3 = copyOnWrite( p2, COPY_SIZE );

    printf("p1 = %p, p2 = %p, p3 = %p\n", p1, p2, p3 );
    printf("p1 = [%s], p2 = [%s], p3 = [%s]\n", p1, p2, p3 );

    printf("Decommiting p2\n");
    printf("DosSetMem( p2 ) = %ld\n",
           DosSetMem( p2, COPY_SIZE, PAG_DECOMMIT ));

    printf("Copying %.5s to p1\n", p1 + 5 );
    memcpy( p1, p1 + 5, 5 );

    printf("p1 = [%s], p3 = [%s]\n", p1, p3 );

    fprintf( stderr, "Test7: ");
    if( memcmp( p1, p1Str, strlen( p1Str ))
        || memcmp( p3, p3Str, strlen( p3Str )))
        fprintf( stderr, "Failed\n");
    else
        fprintf( stderr, "Succeeded\n");

    DosFreeMem( p3 );
    DosFreeMem( p2 );
    DosFreeMem( p1 );
}
예제 #7
0
파일: os2misc.c 프로젝트: ppbao/mozilla-os2
void * _MD_MemMap(PRFileMap *fmap, PROffset64 offset, PRUint32 len)
{
    PRUint32 rv;
    void *addr;

    /* prevent mappings beyond EOF + remainder of page */
    if (offset + len > fmap->md.maxExtent) {
        PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
        return NULL;
    }
    if (PR_Seek64(fmap->fd, offset, PR_SEEK_SET) == -1) {
        return NULL;
    }
    /* try for high memory, fall back to low memory if hi-mem fails */
#if defined(MOZ_OS2_HIGH_MEMORY)
    rv = DosAllocMem(&addr, len, OBJ_ANY | PAG_COMMIT | PAG_READ | PAG_WRITE);
    if (rv)
#endif
    {
        rv = DosAllocMem(&addr, len, PAG_COMMIT | PAG_READ | PAG_WRITE);
        if (rv) {
            PR_SetError(PR_OUT_OF_MEMORY_ERROR, rv);
            return NULL;
        }
    }
    if (PR_Read(fmap->fd, addr, len) == -1) {
        DosFreeMem(addr);
        return NULL;
    }
    /* don't permit writes if readonly */
    if (fmap->prot == PR_PROT_READONLY) {
        rv = DosSetMem(addr, len, PAG_READ);
        if (rv) {
            DosFreeMem(addr);
            PR_SetError(PR_UNKNOWN_ERROR, rv);
            return NULL;
        }
    }
    return addr;
}
/*
 * Exception handler; attempt to commit memory if access violation occures.
 */
static ULONG _System exception_handler(PEXCEPTIONREPORTRECORD pERepRec, PEXCEPTIONREGISTRATIONRECORD pERegRep, PCONTEXTRECORD pCtxRec, PVOID p)
{
   ULONG ulRet = XCPT_CONTINUE_EXECUTION;

   switch(pERepRec->ExceptionNum)
   {
      case XCPT_ACCESS_VIOLATION:
         ulRet = XCPT_CONTINUE_SEARCH;

         if(pERepRec->ExceptionAddress == (PVOID)XCPT_DATA_UNKNOWN)
         {
         }
         else
         {
            APIRET rc = NO_ERROR;
            ULONG cbMem = 1;
            ULONG flMem = 0;

            rc = DosQueryMem((PVOID)pERepRec->ExceptionInfo[1], &cbMem, &flMem);
            if((flMem & PAG_FREE) == 0)
            {
               rc = DosSetMem((PVOID)pERepRec->ExceptionInfo[1], 4096, PAG_DEFAULT | PAG_COMMIT);
               if(rc == NO_ERROR)
               {
                  ulRet = XCPT_CONTINUE_EXECUTION;
               }
            }
         }
         break;

      default:
         ulRet = XCPT_CONTINUE_SEARCH;
         break;
   }

   return ulRet;
}
예제 #9
0
void OSAllocator::decommit(void* address, size_t bytes)
{
if (DosSetMem(address, bytes, PAG_DECOMMIT))
    CRASH();
}
예제 #10
0
void OSAllocator::commit(void* address, size_t bytes, bool writable, bool executable)
{
if (DosSetMem(address, bytes, PAG_COMMIT | protection(writable, executable)))
    CRASH();
}
예제 #11
0
ULONG       FileGetJPEGInfo( CAMJpgInfo * pji, char * szFile, ULONG cbFile)

{
    ULONG       rc;
    ULONG       ul;
    ULONG       cbAlloc;
    BOOL        fHandler = FALSE;
    CAMJXRR     reg;

do
{
    memset( &reg, 0, sizeof(CAMJXRR));
    memset( pji, 0, sizeof(CAMJpgInfo));

    rc = DosOpen( szFile, &reg.hFile, &ul, 0, 0,
                  OPEN_ACTION_FAIL_IF_NEW | OPEN_ACTION_OPEN_IF_EXISTS,
                  OPEN_FLAGS_SEQUENTIAL | OPEN_SHARE_DENYWRITE |
                  OPEN_ACCESS_READONLY, 0);
    if (rc) {
        printf( "DosOpen - rc= 0x%x\n", (int)rc);
        break;
    }

    // allocate a lot of uncommited memory
    cbAlloc = ((cbFile + 0xfff) & ~0xfff);
    rc = DosAllocMem( (void**)(&reg.pBase), cbAlloc,
                      PAG_READ | PAG_WRITE);
    if (rc) {
        printf( "DosAllocMem - rc= 0x%x\n", (int)rc);
        break;
    }

    // get up to the first 16k of the file - this is enough
    // for my Canon but not enough for a Sony I've tried

    ul = (cbFile >= 0x4000) ? 0x4000 : cbAlloc;
    rc = DosSetMem( reg.pBase, ul, PAG_COMMIT | PAG_DEFAULT);
    if (rc) {
        printf( "FileGetJPEGInfo - DosSetMem - rc= 0x%x\n", (int)rc);
        break;
    }

    ul = (cbFile >= 0x4000) ? 0x4000 : cbFile;
    ul = FileReadFile( reg.hFile, reg.pBase, ul, szFile);
    if (!ul) {
        rc = CAMERR_NEEDDATA;
        break;
    }

    // any access beyond 16k will generate an exception;
    // the handler will commit the page and read the corresponding
    // 4k from the file;  if it encounters a file error, it will
    // longjmp() back to here so we can abort
    reg.lFilePtr += ul;
    reg.lEOF = cbFile;
    reg.pEnd = reg.pBase + cbAlloc;
    reg.szFile = szFile;
    reg.xrr.ExceptionHandler = FileExceptionHandler;

    // since the handler is lower on the stack than the jmpbuf,
    // longjmp() will unwind it before returning, so prevent
    // the cleanup code below from unsetting it
    if (setjmp( reg.jmpbuf)) {
        fHandler = FALSE;
        break;
    }

    rc = DosSetExceptionHandler( &reg.xrr);
    if (rc) {
        printf( "DosSetExceptionHandler - rc= 0x%x\n", (int)rc);
        break;
    }
    fHandler = TRUE;

    // parse the file
    rc = FileIdentifyFile( pji, reg.pBase);
    if (rc) {
        printf( "FileIdentifyFile - rc= 0x%x\n", (int)rc);
        break;
    }

    // change the address of the thumb into an offset into the file
    if (pji->pThumb)
        pji->offsThumb = pji->pThumb - reg.pBase;

} while (0);

    if (fHandler) {
        rc = DosUnsetExceptionHandler( &reg.xrr);
        if (rc)
            printf( "DosUnsetExceptionHandler - rc= 0x%lx\n", rc);
    }

    if (reg.pBase) {
        rc = DosFreeMem( reg.pBase);
        if (rc)
            printf( "DosFreeMem - rc= 0x%x\n", (int)rc);
    }

    if (reg.hFile) {
        rc = DosClose( reg.hFile);
        if (rc)
            printf( "DosClose - rc= 0x%x\n", (int)rc);
    }

    return (0);
}
예제 #12
0
static bool
MakeRegionExecutable(void *page)
{
  rc = DosSetMem(page, PAGESIZE, PAG_READ | PAG_WRITE | PAG_EXECUTE);
  return rc ? true : false;
}
예제 #13
0
/**
 * Free memory allocated by kHlpPageAlloc().
 *
 * @returns 0 on success, non-zero OS status code on failure.
 * @param   pv          The address returned by kHlpPageAlloc().
 * @param   cb          The byte count requested from kHlpPageAlloc().
 */
KHLP_DECL(int) kHlpPageFree(void *pv, KSIZE cb)
{
#if K_OS == K_OS_DARWIN \
 || K_OS == K_OS_FREEBSD \
 || K_OS == K_OS_LINUX \
 || K_OS == K_OS_NETBSD \
 || K_OS == K_OS_OPENBSD \
 || K_OS == K_OS_SOLARIS
    int rc;

    rc = kHlpSys_munmap(pv, cb);
    if (!rc)
        return 0;
    /** @todo convert errno -> kErrors */
    return rc;

#elif K_OS == K_OS_OS2
    APIRET rc;

    /*
     * Deal with any portion overlapping with the stub.
     */
    KUPTR offStub = (KUPTR)pv - (KUPTR)g_pvStub;
    if (offStub < g_cbStub)
    {
        /* decommit the pages in the stub. */
        KSIZE cbStub = K_MIN(g_cbStub - offStub, cb);
        rc = DosSetMem(pv, cbStub, PAG_DECOMMIT);
        if (rc)
        {
            /* Page by page, ignoring errors after the first success. */
            while (cbStub > 0)
            {
                if (!DosSetMem(pv, 0x1000, PAG_DECOMMIT))
                    rc = 0;
                pv = (void *)((KUPTR)pv + 0x1000);
                cbStub -= 0x1000;
                cb -= 0x1000;
            }
            if (rc)
            {
                kHlpAssert(!rc);
                return rc;
            }
        }
        else
        {
            cb -= cbStub;
            if (!cb)
                return 0;
            pv = (void *)((KUPTR)pv + cbStub);
        }
    }

    /*
     * Free the object.
     */
    rc = DosFreeMem(pv);
    kHlpAssert(!rc);
    return rc;

#elif  K_OS == K_OS_WINDOWS
    /*
     * Free the object.
     */
    int rc = 0;
    if (!VirtualFree(pv, 0 /*cb*/, MEM_RELEASE))
    {
        rc = GetLastError();
        kHlpAssert(0);
    }
    return rc;

#else
# error "port me"
#endif
}
예제 #14
0
파일: shared.c 프로젝트: bitwiseworks/libcx
/**
 * Initializes the shared structures.
 */
static void shared_init()
{
  APIRET arc;
  int rc;

  arc = DosExitList(EXLST_ADD, ProcessExit);
  ASSERT_MSG(arc == NO_ERROR, "%ld", arc);

#if defined(TRACE_ENABLED) && !defined(TRACE_USE_LIBC_LOG)
  /*
   * Allocate a larger buffer to fit lengthy TRACE messages and disable
   * auto-flush on EOL (to avoid breaking lines by stdout operations
   * from other threads/processes).
   */
  setvbuf(stdout, NULL, _IOFBF, 0x10000);
#endif

  while (1)
  {
    /* First, try to open the mutex */
    arc = DosOpenMutexSem(MUTEX_LIBCX, &gMutex);
    TRACE("DosOpenMutexSem = %lu\n", arc);

    if (arc == NO_ERROR)
    {
      /*
       * Init is (being) done by another process, request the mutex to
       * guarantee shared memory is already alloated, then get access to
       * it and open shared heap located in that memory.
       */
      arc = DosRequestMutexSem(gMutex, SEM_INDEFINITE_WAIT);
      ASSERT_MSG(arc == NO_ERROR, "%ld", arc);

      if (arc == NO_ERROR)
      {
        arc = DosGetNamedSharedMem((PPVOID)&gpData, SHAREDMEM_LIBCX, PAG_READ | PAG_WRITE);
        TRACE("DosGetNamedSharedMem = %lu\n", arc);
        if (arc)
        {
          /*
           * This failure means that another process was too fast to do what
           * it wanted and initiated global uninitialization before we got the
           * mutex so shared memory was already freed by this time. Retry.
           */
          DosReleaseMutexSem(gMutex);
          DosCloseMutexSem(gMutex);
          continue;
        }

        /*
         * It's an ordinary LIBCx process. Increase coutners.
         */

        TRACE("gpData->heap = %p\n", gpData->heap);
        ASSERT(gpData->heap);

        rc = _uopen(gpData->heap);
        ASSERT_MSG(rc == 0, "%d (%d)", rc, errno);

        ASSERT(gpData->refcnt);
        gpData->refcnt++;
        TRACE("gpData->refcnt = %d\n", gpData->refcnt);
      }

      break;
    }

    if (arc == ERROR_SEM_NOT_FOUND)
    {
      /* We are the first process, create the mutex */
      arc = DosCreateMutexSem(MUTEX_LIBCX, &gMutex, 0, TRUE);
      TRACE("DosCreateMutexSem = %ld\n", arc);

      if (arc == ERROR_DUPLICATE_NAME)
      {
        /* Another process is faster, attempt to open the mutex again */
        continue;
      }
    }

    ASSERT_MSG(arc == NO_ERROR, "%ld", arc);

    /*
     * It's a process that successfully created the main mutex, i.e. the first
     * LIBCx process. Proceed with the initial setup by allocating shared
     * memory and heap.
     */

    /* Allocate shared memory */
    arc = DosAllocSharedMem((PPVOID)&gpData, SHAREDMEM_LIBCX, HEAP_SIZE,
                            PAG_READ | PAG_WRITE | OBJ_ANY);
    TRACE("DosAllocSharedMem(OBJ_ANY) = %ld\n", arc);

    if (arc && arc != ERROR_ALREADY_EXISTS)
    {
      /* High memory may be unavailable, try w/o OBJ_ANY */
      arc = DosAllocSharedMem((PPVOID)&gpData, SHAREDMEM_LIBCX, HEAP_SIZE,
                              PAG_READ | PAG_WRITE);
      TRACE("DosAllocSharedMem = %ld\n", arc);
    }

    ASSERT_MSG(arc == NO_ERROR, "%ld", arc);

    TRACE("gpData %p\n", gpData);

    /* Commit the initial block */
    arc = DosSetMem(gpData, HEAP_INIT_SIZE, PAG_DEFAULT | PAG_COMMIT);
    ASSERT_MSG(arc == NO_ERROR, "%ld", arc);

    gpData->size = HEAP_INIT_SIZE;

    /* Create shared heap */
    gpData->heap = _ucreate(gpData + 1, HEAP_INIT_SIZE - sizeof(*gpData),
                            _BLOCK_CLEAN, _HEAP_REGULAR | _HEAP_SHARED,
                            mem_alloc, NULL);
    TRACE("gpData->heap = %p\n", gpData->heap);
    ASSERT(gpData->heap);

    rc = _uopen(gpData->heap);
    ASSERT_MSG(rc == 0, "%d (%d)", rc, errno);

    gpData->refcnt = 1;

    /* Initialize common structures */
    GLOBAL_NEW_ARRAY(gpData->procs, PROC_DESC_HASH_SIZE);
    TRACE("gpData->procs = %p\n", gpData->procs);
    ASSERT(gpData->procs);

    GLOBAL_NEW_ARRAY(gpData->files, FILE_DESC_HASH_SIZE);
    TRACE("gpData->files = %p\n", gpData->files);
    ASSERT(gpData->files);

    break;
  }

  /*
   * Perform common initialization (both for the first and ordinary processes).
   */

  /* Make sure a process description for this process is created */
  ProcDesc *proc = get_proc_desc(getpid());
  ASSERT(proc);

  /* Initialize individual components */
  mmap_init(proc);
  fcntl_locking_init(proc);

  /* Check if it's a spawn2 wrapper (e.g. spawn2-wrapper.c) */
  {
    char dll[CCHMAXPATH + sizeof(SPAWN2_WRAPPERNAME) + 1];
    if (get_module_name(dll, sizeof(dll)))
    {
      strcpy(_getname(dll), SPAWN2_WRAPPERNAME);

      char exe[CCHMAXPATH + 1];
      if (_execname(exe, sizeof(exe)) == 0 && stricmp(dll, exe) == 0)
      {
        proc->flags |= Proc_Spawn2Wrapper;
        TRACE("spawn2 wrapper\n");

        /* Make sure the semaphore is available (needed for spawn2-wrapper.c) */
        ASSERT(gpData->spawn2_sem);
        global_spawn2_sem(proc);
      }
    }
  }

  DosReleaseMutexSem(gMutex);

  TRACE("done\n");
}