示例#1
0
/**
 * \brief Open the specified file.
 *
 * This function is an interface to open a file on disk.
 * It sets the handle which can later be used to read, seek etc.
 * \param[in]   pzPath    character string specifying the file to open.
 * \param[in]   flags     character string specifying the file mode to be used.
 * \param[out]  pHandle   the passed address will point to the file handle on success.
 * \return      Returns TRUE if file was opened successfully, FALSE otherwise.
 */
int File_Open( char * pzPath, char * flags, void ** pHandle )
{
  if ( (*pHandle = fopen(pzPath, flags) ) == NULL )
  {
    PMS_SHOW_ERROR(" ***ASSERT*** File_Open: Failed to open file %s \n", pzPath);
    return FALSE;
  }
  return TRUE;
}
示例#2
0
/*! \brief Start a new thread.
 *
 * UNIX/Linux
 *
 * \param start_address Funtion pointer to the threads entry point.
 * \param stack_size Size of stack to use, in bytes.
 * \param arglist Pointer to argument list.
 * \return Pointer to thread (casted to void * for platform portability)
 *
*/
void *PMS_BeginThread(void( *start_address )( void * ), unsigned int stack_size, void *arglist )
{
  pthread_attr_t attr;
  unsigned int result;
#ifdef PMS_OIL_MERGE_DISABLE_MEM
  PMS_TyThreadFunction *ptThreadInfo = OSMalloc(sizeof(PMS_TyThreadFunction), PMS_MemoryPoolPMS);
#else
  PMS_TyThreadFunction *ptThreadInfo = mmalloc(sizeof(PMS_TyThreadFunction));
#endif

  if(!ptThreadInfo) {
    return (NULL);
  }

  ptThreadInfo->bCondBroadcasted = 0;

  if ( pthread_mutex_init(&ptThreadInfo->mutexThread, NULL) != 0 ) {
    goto thread_info_destroy;
  }

  if ( pthread_cond_init(&ptThreadInfo->condThread, NULL) != 0 ) {
    goto thread_mutex_destroy;
  }

  if (pthread_attr_init(&attr)) {
    goto thread_cond_destroy;
  }

  ptThreadInfo->start_routine = start_address;
  ptThreadInfo->arg = arglist;
  result = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE) ||
           pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM) ||
           pthread_create(&ptThreadInfo->tid, &attr, PMSThreadWrapper, (void*)ptThreadInfo);

  (void)pthread_attr_destroy(&attr) ;

  if (result != 0) {
    PMS_SHOW_ERROR("Failed to create thread: \n");
    goto thread_cond_destroy;
  }

  return (void*)ptThreadInfo;

thread_cond_destroy:
  (void)pthread_cond_destroy(&ptThreadInfo->condThread) ;
thread_mutex_destroy:
  (void)pthread_mutex_destroy(&ptThreadInfo->mutexThread) ;
thread_info_destroy:
#ifdef PMS_OIL_MERGE_DISABLE_MEM
  OSFree(ptThreadInfo, PMS_MemoryPoolPMS);
#else
  mfree(ptThreadInfo);
#endif
  return (NULL);
}
示例#3
0
/**
 * \brief Read the file associated with the specified handle.
 *
 * This function is an interface to read a file on disk.
 * \param[out]  buffer   the requested bytes are read into the buffer pointed to by this address
 * \param[in]   nBytesToRead    number of bytes to read
 * \param[in]   pHandle   address pointing to the file handle.
 * \return      Returns number of bytes read on success, negative value otherwise.
 */
int File_Read(unsigned char * buffer, int nBytesToRead, void * handle)
{
  int nbytes_read;

  if(handle==NULL)
      return (0);

  nbytes_read = (int)fread(buffer, 1, nBytesToRead, handle);
  if(nbytes_read < 0)
  {
    PMS_SHOW_ERROR("Failed to read from file");
    fclose(handle);
    handle = NULL;
  }
  return (nbytes_read);
}
示例#4
0
/*! \brief Wait for a semaphore for a specified time.
 *
 * UNIX/Linux
 *
 * \param[in] semaHandle Pointer returned by \c PMS_CreateSemaphore.
 * \param[in] nMilliSeconds Timeout in milliseconds.
 * \return 1 if successful, 0 otherwise.
*/
int PMS_WaitOnSemaphore(void * semaHandle, unsigned int nMilliSeconds)
{
  int val;
  sem_t *sem = (sem_t*)semaHandle;
#ifndef MACOSX
  struct timespec ts;

  /* CLOCK_REALTIME can go up forward in leaps, and occasionally backwards.
     CLOCK_MONOTONIC does neither, it just keeps going forwards.
  */
  val = clock_gettime( CLOCK_MONOTONIC, &ts );
  if (val != 0) {
      val = clock_gettime( CLOCK_REALTIME, &ts );
      if (val != 0) {
        PMS_SHOW_ERROR("PMS_WaitOnSemaphore: clock_gettime failed\n");
      }
  }

  ts.tv_sec += (nMilliSeconds/1000);
  ts.tv_nsec += (nMilliSeconds%1000)*1000000;
  if( ts.tv_nsec > 1000000000L ) {
    ts.tv_sec++;
    ts.tv_nsec = ts.tv_nsec % 1000000000L;
  }
#endif

  do {
#ifdef MACOSX
    /* TODO: no sem_timedwait() on Mac OS X */
    val = sem_wait(sem);
#else
#ifdef __NetBSD__
    /* TODO: no sem_timedwait() on NetBSD 6.0 */
    val = sem_wait(sem);
#else
    val = sem_timedwait(sem,&ts);
#endif
#endif
    if(errno == ETIMEDOUT)
      return 0;
  } while (val != 0 && errno == EINTR);

  return 1;
}
示例#5
0
/**
 * \brief Read from File Data Stream, but move the file position back to the start of the read.
 *
 * This routine reads the requested number of bytes from the file and puts them
 * in the buffer and return the file position back to the start of the read.\n
 * It is an implementation of PMS_PeekDataStream callback. \n
 */
int File_PeekDataStream(unsigned char * buffer, int nBytesToRead)
{
  int nbytes_read;

  /* PMS_SHOW("File_PeekDataStream(0x%p, %d)\n", buffer, nBytesToRead); */
  if(g_tSystemInfo.nStoreJobBeforeRip)
  {
    if((l_nStoreBufferPos + nBytesToRead) < l_nStoreBufferUsed)
    {
      nbytes_read = nBytesToRead;
    }
    else
    {
      nbytes_read = l_nStoreBufferUsed - l_nStoreBufferPos;
    }
    memcpy(buffer, l_pStoreBuffer + l_nStoreBufferPos, nbytes_read);
  }
  else
  {
    if(l_fileCurrent==NULL)
      return (0);

    nbytes_read = (int)fread(buffer, 1, nBytesToRead, l_fileCurrent);
    if(nbytes_read < 0)
    {
      PMS_SHOW_ERROR("Failed to read from file");
      fclose(l_fileCurrent);
      l_fileCurrent = NULL;
    }
    else if (nbytes_read == 0)
    {
      fclose(l_fileCurrent);
      l_fileCurrent = NULL;
    }
    else
    {
      fseek(l_fileCurrent, -nbytes_read, SEEK_CUR);
    }
  }

  return (nbytes_read);
}
/**
 * \brief Wrapper for closing hot folder function
 *
 */
int HotFolder_CloseDataStream(void)
{
  int nResult = 0;
  if(bActiveFile && !bVirtualFile)
  {
    File_CloseDataStream();
    nResult = remove(aszHotFolderFiles[0]);
    bActiveFile = FALSE;
  }
  else if(bVirtualFile)
  {
    nResult = remove(aszHotFolderFiles[0]);
    bActiveFile = FALSE;
    bVirtualFile = FALSE;
  }
  if(nResult != 0) {
    PMS_SHOW_ERROR("Failed to remove file \"%s\" from hot folder.\n", aszHotFolderFiles[0]);
  }
  return 1;
}
示例#7
0
/*! \brief Create and initialize a critical section
 *
 * UNIX/Linux
 *
 * \return Pointer to critical section created and initialized (casted to \c void *).
*/
void * PMS_CreateCriticalSection(void)
{
  pthread_mutex_t * ptCS;          /* Mutex for critical section */
  pthread_mutexattr_t mutexattr;   /* Mutex attribute variable */

#ifdef PMS_OIL_MERGE_DISABLE_MEM
  ptCS = (pthread_mutex_t *)malloc(sizeof(pthread_mutex_t));
#else
  ptCS = (pthread_mutex_t *)mmalloc(sizeof(pthread_mutex_t));
#endif
  if(!ptCS) {
    PMS_SHOW_ERROR("Failed to allocation critical section structure\n");
    return NULL;
  }

  /* Initialize the attributes set */
  pthread_mutexattr_init(&mutexattr);

#ifdef MACOSX
  /* Set the mutex as a normal mutex */
  pthread_mutexattr_settype(&mutexattr, PTHREAD_MUTEX_NORMAL);
#else
#ifdef __NetBSD__
  /* Set the mutex as a normal mutex */
  pthread_mutexattr_settype(&mutexattr, PTHREAD_MUTEX_NORMAL);
#else
  /* Set the mutex as a fast mutex */
  pthread_mutexattr_settype(&mutexattr, PTHREAD_MUTEX_ADAPTIVE_NP);
#endif
#endif

  /* create the mutex with the attributes set */
  pthread_mutex_init(ptCS, &mutexattr);

  /* After initializing the mutex, the attribute can be destroyed */
  pthread_mutexattr_destroy(&mutexattr);

  return (void*)ptCS;
}
示例#8
0
/**
 * \brief Check for memory leaks and display if there are any.
 *
 */
unsigned int CheckMemLeaks()
{
  unsigned int retval=0;

  int pool;

  for(pool = 0; pool < PMS_NumOfMemPools; pool++)
  {
    if(l_tPMSMem[pool].bMemIsInitialised)
    {
      if(l_tPMSMem[pool].iCurrentMemory>0)
      {
        PMS_SHOW_ERROR("*** CheckMemLeaks: Pool %d - possible leak of %d ***\n",
          pool,
          l_tPMSMem[pool].iCurrentMemory);
        retval = 1;
      }
    }
  }
  PMS_SHOW("\n");

  return (retval);
}
示例#9
0
/*! \brief Close and free a thread.
 *
 * UNIX/Linux
 *
 * \param[in] pThread Pointer to thread created by PMS_BeginThread.
 * \param[in] nWaitForThreadToExit Timeout in milliseconds.
 *              Negative: wait forever or until thread exits.
 *              Zero: do not wait.
 *              Postive: wait for up to # milliseconds or until thread exits.
 * \return 0: failure, 1: success, -1: success, but timeout occured whilst waiting for thread to exit.
*/
int PMS_CloseThread(void *pThread, int nWaitForThreadToExit)
{
  PMS_TyThreadFunction *pTInfo = pThread;
  int nRetVal = 0;

  if(!pTInfo)
    return 0;

  if(nWaitForThreadToExit > 0) {

    struct timeval now;
    struct timespec ts;
    int e;

    gettimeofday(&now, NULL);
    ts.tv_sec = now.tv_sec;
    ts.tv_nsec = now.tv_usec*1000;

    ts.tv_sec += nWaitForThreadToExit / 1000;

    ts.tv_nsec += nWaitForThreadToExit % 1000 * 1000000;

    if (ts.tv_nsec > 999999999){
      ts.tv_sec++;
      ts.tv_nsec = ts.tv_nsec % 1000000000;
    }

    /* wait (with timeout) until thread has finished */
    pthread_mutex_lock(&pTInfo->mutexThread);

    /* If the thread has already broadcasted the cond signal then we
       shouldn't wait for another one... there won't be another one. */
    if(pTInfo->bCondBroadcasted == 1) {
      e = 0;
    } else {
      e = pthread_cond_timedwait(&pTInfo->condThread, &pTInfo->mutexThread, &ts);
      pthread_mutex_unlock(&pTInfo->mutexThread);
    }

    /* now join so we wait until thread has -really- finished */
    if (e == ETIMEDOUT) {
      PMS_SHOW_ERROR("Timed out waiting for thread to exit.\n");
      (void)pthread_cancel(pTInfo->tid); /* try to forcefully stop it at
                                            a cancellation point */
      nRetVal = -1;
    } else {
      (void)pthread_join(pTInfo->tid, NULL);
      nRetVal = 1;
    }
  }
  else if (nWaitForThreadToExit < 0) {
    (void)pthread_join(pTInfo->tid, NULL) ;
    nRetVal = 1;
  }
  else {
    (void)pthread_cancel(pTInfo->tid); /* try to forcefully stop it at
                                          a cancellation point */
    nRetVal = 1;
  }

  (void)pthread_cond_destroy(&pTInfo->condThread) ;
  (void)pthread_mutex_destroy(&pTInfo->mutexThread) ;
  OSFree(pTInfo, PMS_MemoryPoolPMS);

  return nRetVal;
}
示例#10
0
/**
 * \brief Open the next file.
 *
 * Opens the file contaning next job data.\n
 */
int File_OpenDataStream(void)
{
  /* PMS_SHOW("File_OpenDataStream()\n"); */

  if(!GetNextFilename(szJobFilename))
    return -1; /* -1 means don't try opening this module again */

  if ( (l_fileCurrent = fopen((char *)szJobFilename, "rb") ) == NULL )
  {
    PMS_SHOW_ERROR(" ***ASSERT*** File_OpenDataStream: Failed to open file %s \n", szJobFilename);
    return 0; /* 0 means you may try this module again to try the next job */
  }

  if(g_tSystemInfo.nStoreJobBeforeRip)
  {
    int nRead;
    int nChunk = 16 * 1024;
    PMS_SHOW("Storing job before passing to rip...\n");
    l_pStoreBuffer = OSMalloc(g_tSystemInfo.cbReceiveBuffer,PMS_MemoryPoolMisc);
    if(!l_pStoreBuffer) {
      PMS_SHOW_ERROR(" ***ASSERT*** File_OpenDataStream: Failed to allocate buffer for storing job\n");
      fclose(l_fileCurrent);
      l_fileCurrent = NULL;
      return 0; /* 0 means you may try this module again to try the next job */
    }
    fseek(l_fileCurrent,0,SEEK_END);
    l_nStoreBufferUsed = ftell(l_fileCurrent);
    fseek(l_fileCurrent,0,SEEK_SET);

    if(l_nStoreBufferUsed > g_tSystemInfo.cbReceiveBuffer)
    {
      PMS_SHOW_ERROR(" ***ASSERT*** File_OpenDataStream: Failed to store job. Job size is larger than the memory buffer.\n");
      fclose(l_fileCurrent);
      l_fileCurrent = NULL;
      OSFree(l_pStoreBuffer, PMS_MemoryPoolMisc);
      l_pStoreBuffer = NULL;
      return 0; /* 0 means you may try this module again to try the next job */
    }

    l_nStoreBufferUsed = 0;
    l_nStoreBufferPos = 0;
    do
    {
      if((l_nStoreBufferUsed + nChunk) < g_tSystemInfo.cbReceiveBuffer)
      {
        nRead = (int)fread(l_pStoreBuffer + l_nStoreBufferUsed, 1, nChunk, l_fileCurrent);
      }
      else if(l_nStoreBufferUsed < g_tSystemInfo.cbReceiveBuffer)
      {
        nRead = (int)fread(l_pStoreBuffer + l_nStoreBufferUsed, 1, g_tSystemInfo.cbReceiveBuffer - l_nStoreBufferUsed, l_fileCurrent);
      }
      else
      {
        nRead = 0;
      }
      l_nStoreBufferUsed += nRead;
    } while (nRead>0);

    fclose(l_fileCurrent);
    l_fileCurrent = NULL;
    PMS_SHOW("Stored %d bytes.\n", l_nStoreBufferUsed);
  }

  return 1; /* 1 means we have a job ready to rip */
}
示例#11
0
void *OSMallocEx(size_t size, PMS_TyMemPool pool)
#endif
{
  void *ptr;
  unsigned char *p;
#ifdef PMS_MEM_LIMITED_POOLS
  PMS_TyMemTraceHdr hdr;
#endif

  if(!l_tPMSMem[pool].bMemIsInitialised)
  {
#ifdef PMS_MEM_LIMITED_POOLS
    memset(&l_apUsed[pool][0], 0, sizeof(l_apUsed[pool]));
    l_uCount[pool] = (unsigned int)-1;
    l_tPMSMem[pool].iCurrentMemory = 0;
    l_tPMSMem[pool].iPeakMemory = 0;

    switch(pool)
    {
      case PMS_MemoryPoolSys:
        l_tPMSMem[pool].iAvailMemory = g_tSystemInfo.cbSysMemory;
        if((g_tSystemInfo.cbSysMemory > 0) && (g_tSystemInfo.cbRIPMemory > g_tSystemInfo.cbSysMemory))
          PMS_SHOW_ERROR("*** Warning : SYS MEMORY POOL %d has to be greater than [-m <RIP memory in MB>] %d.\n",g_tSystemInfo.cbSysMemory,g_tSystemInfo.cbRIPMemory);
        break;
      case PMS_MemoryPoolApp:
        l_tPMSMem[pool].iAvailMemory = g_tSystemInfo.cbAppMemory;
        break;
      case PMS_MemoryPoolJob:
        l_tPMSMem[pool].iAvailMemory = g_tSystemInfo.cbJobMemory;
        break;
      case PMS_MemoryPoolMisc:
        l_tPMSMem[pool].iAvailMemory = g_tSystemInfo.cbMiscMemory;
        break;
      case PMS_MemoryPoolPMS:
        l_tPMSMem[pool].iAvailMemory = g_tSystemInfo.cbPMSMemory;
        break;
      default:
        PMS_SHOW_ERROR("*** OSMalloc: Invalid memory pool - %d ***\n",pool);
        l_tPMSMem[pool].iAvailMemory = 0;
    }

#endif

    l_tPMSMem[pool].bMemIsInitialised = 1;
  }

#ifdef PMS_MEM_LIMITED_POOLS
  /* Must be multiple of 8 bytes to be aligned for doubles on un*x platforms */
  size+=((sizeof(PMS_TyMemTraceHdr)+7)&~7);

  if(l_tPMSMem[pool].iAvailMemory)
  {
    if((l_tPMSMem[pool].iAvailMemory < l_tPMSMem[pool].iCurrentMemory) || (l_tPMSMem[pool].iAvailMemory - l_tPMSMem[pool].iCurrentMemory < (int)size))
    {
      PMS_SHOW_ERROR(" ***ASSERT*** OSMalloc; lack of memory in memory pool. size=%u, pool=%d\n", size, pool);
      return NULL;
    }
  }
#endif

#ifdef PMS_OIL_MERGE_DISABLE_MEM
  ptr=(void*)malloc(size);
#else
  ptr=(void*)MemAlloc(size, FALSE, FALSE);
  memVal+=size;
  if(memVal>count1)
  {
	count1=memVal;
	PMS_SHOW_ERROR("max memory %d\n", count1);
  }
#endif

  p = (unsigned char*)ptr;

  if(!ptr) {
	
	gpsInterpNotifyError(gps_client, 30016);
    PMS_SHOW_ERROR(" ***ASSERT*** OSMalloc returning NULL, %u, %d\n", size, pool);
  }
#ifdef PMS_MEM_LIMITED_POOLS
  else
  {
    memset(&hdr,0xAA,sizeof(hdr));
    hdr.cbSize=size;
    hdr.nPool=pool;
#ifdef SDK_MEMTRACE
    hdr.nLine=nLine;
    hdr.pszFile=pszFile;
#endif
    hdr.pszThread=l_szDefaultThread;

    /*Critical section to avoid simultaneous access of global variable by multiple threads (PMS and OIL)*/
    /*CRITICAL SECTION - START*/
    /* Check that critical section has been created. The create cs routine calls this malloc function */
    if(g_csMemoryUsage) {
      PMS_EnterCriticalSection(g_csMemoryUsage);
    }

    hdr.nCount=++l_uCount[pool];
    memcpy(p, &hdr, sizeof(PMS_TyMemTraceHdr));
    p += ((sizeof(PMS_TyMemTraceHdr)+7)&~7);

#ifdef SDK_MEMTRACE
    if(l_chFirstCharFileName_BestGuess==' ') {
      l_chFirstCharFileName_BestGuess = pszFile[0];
    }
    if(l_uCount[pool] < (sizeof(l_apUsed[pool]) / sizeof(l_apUsed[pool][0])))
      l_apUsed[pool][l_uCount[pool]] = p;
#endif
    l_tPMSMem[pool].iCurrentMemory+=(unsigned int)size;

    if(g_csMemoryUsage) {
      PMS_LeaveCriticalSection(g_csMemoryUsage);
    }
    /*CRITICAL SECTION - END*/

    if(l_tPMSMem[pool].iCurrentMemory > l_tPMSMem[pool].iPeakMemory)
    {
      l_tPMSMem[pool].iPeakMemory = l_tPMSMem[pool].iCurrentMemory;
    }

    PMS_MALLOC_TRACE("OSMalloc, from %s(%d), %u, 0x%p, %d bytes, pool %d, returning p=0x%p\n", pszFile, nLine, l_uCount[pool], ptr, size, pool, p);
  }
#endif

  return ((void*)p);
}
示例#12
0
/**
 * \brief Display memory PMS memory pool statistics.
 *
 */
void DisplayMemStats()
{
  int pool;
  int i;
  PMS_TyMemTraceHdr *pHdr;
  size_t size;
  unsigned int uPool;
  unsigned int uCount;
  char *pszThread;
#ifdef SDK_MEM_TRACE
  char *pszFileAlloc;
  int nLineAlloc;
#endif
  unsigned int *p;

  PMS_SHOW_ERROR("Memory pool statistics\n");
  for(pool = 0; pool < PMS_NumOfMemPools; pool++)
  {
    if(l_tPMSMem[pool].bMemIsInitialised)
    {
      switch (pool)
      {
      case PMS_MemoryPoolSys:
          PMS_SHOW_ERROR("Sys ");
          break;
      case PMS_MemoryPoolApp:
          PMS_SHOW_ERROR("App ");
          break;
      case PMS_MemoryPoolJob:
          PMS_SHOW_ERROR("Job ");
          break;
      case PMS_MemoryPoolMisc:
          PMS_SHOW_ERROR("Misc");
          break;
      case PMS_MemoryPoolPMS:
          PMS_SHOW_ERROR("PMS ");
          break;
      default:
          PMS_SHOW_ERROR("??? ");
          break;
      }

      if(l_tPMSMem[pool].iAvailMemory>0)
      {
        PMS_SHOW_ERROR("\tAvail: %u\tPeak: %u\tCurrent: %u\n",
          l_tPMSMem[pool].iAvailMemory,
          l_tPMSMem[pool].iPeakMemory,
          l_tPMSMem[pool].iCurrentMemory);
      }
      else
      {
        PMS_SHOW_ERROR("\tAvail: no limit\tPeak: %u\tCurrent: %u\n",
          l_tPMSMem[pool].iPeakMemory,
          l_tPMSMem[pool].iCurrentMemory);
      }
    }
    for(i = 0; i < (sizeof(l_apUsed[pool]) / sizeof(l_apUsed[pool][0])); i++) {
      if(l_apUsed[pool][i]) {
        PMS_SHOW_ERROR("Found unfreed memory at %d, %p\n", i, l_apUsed[pool][i]);
        p = (unsigned int*)l_apUsed[pool][i];

        pHdr = (PMS_TyMemTraceHdr *)(p - ((sizeof(PMS_TyMemTraceHdr)+7)&~7));

#ifdef SDK_MEM_TRACE
        nLineAlloc = pHdr->nLine;
        pszFileAlloc = pHdr->pszFile;
#endif
        uCount = pHdr->nCount;
        uPool = pHdr->nPool;
        size = pHdr->cbSize;
        pszThread = pHdr->pszThread;

#ifdef SDK_MEM_TRACE
        PMS_SHOW_ERROR("allocation %u from %s(%d) in thread %s, size %u, pool %u\n", uCount, pszFileAlloc, nLineAlloc, pszThread, size, uPool);
#else
        PMS_SHOW_ERROR("allocation %u in thread %s, size %u, pool %u\n", uCount, pszThread, size, uPool);
#endif
      }
    }
  }
  PMS_SHOW_ERROR("\n");
}
示例#13
0
void OSFreeEx(void *ptr, PMS_TyMemPool pool)
#endif
{
#ifndef SDK_MEMTRACE
#ifndef PMS_MEM_LIMITED_POOLS
  UNUSED_PARAM((PMS_TyMemPool), pool);
#endif
#endif

  if(ptr)
  {
#ifdef PMS_MEM_LIMITED_POOLS
    PMS_TyMemTraceHdr *pHdr;
    unsigned char *p = (unsigned char *)ptr;
    size_t size;
    unsigned int uPool;
    unsigned int uCount;
#ifdef SDK_MEMTRACE
    char *pszFileAlloc;
    int nLineAlloc;
#endif
    char *pszThread;

    p-=((sizeof(PMS_TyMemTraceHdr)+7)&~7);

    pHdr = (PMS_TyMemTraceHdr *)p;

#ifdef SDK_MEMTRACE
    nLineAlloc = pHdr->nLine;
    pszFileAlloc = pHdr->pszFile;
#endif
    pszThread = pHdr->pszThread;
    uCount = pHdr->nCount;
    uPool = pHdr->nPool;
    size = pHdr->cbSize;

#ifdef SDK_MEMTRACE
    PMS_MALLOC_TRACE("OSFree, from %s(%d), %u, 0x%p (actual 0x%p), %d bytes, pool %d, malloc from %s(%d) in thread %s\n", pszFile, nLine, uCount, ptr, p, size, pool, pszFileAlloc?pszFileAlloc:"null", nLineAlloc, pszThread?pszThread:"null");

    if(!pszThread || pszThread[0]!='G') {
      PMS_SHOW_ERROR("OSFree: Freeing memory that appears to have been stamped on. Unexpected thread string \"%s\"\n", pszThread?pszThread:"null");
      PMS_SHOW_ERROR("OSFree, from %s(%d), %u, 0x%p (actual 0x%p), %d bytes, pool %d, malloc from %s(%d) in thread %s\n", pszFile, nLine, uCount, ptr, p, size, pool, pszFileAlloc, nLineAlloc, pszThread);
    }

    /* You may want to extend this check if your sources are compiled from various drives */
    if(!pszFileAlloc || (pszFileAlloc[0]!=l_chFirstCharFileName_BestGuess)) {
      PMS_SHOW_ERROR("OSFree: Freeing memory that appears to have been stamped on. Unexpected source file string \"%s\"\n", pszFileAlloc?pszFileAlloc:"null");
      PMS_SHOW_ERROR("OSFree, from %s(%d), %u, 0x%p (actual 0x%p), %d bytes, pool %d, malloc from %s(%d) in thread %s\n", pszFile, nLine, uCount, ptr, p, size, pool, pszFileAlloc, nLineAlloc, pszThread);
    }
#endif

#ifdef PMS_OIL_MERGE_DISABLE_MEM
    free(p);
#else
    MemFree((void *)p);
#endif
#else
#ifdef PMS_OIL_MERGE_DISABLE_MEM
    free(ptr);
#else
    MemFree(ptr);
#endif
#endif

#ifdef PMS_MEM_LIMITED_POOLS
    /*Critical section to avoid simultaneous access of global variable by multiple threads (PMS and OIL)*/
    /*CRITICAL SECTION - START*/
    if(g_csMemoryUsage) {
      PMS_EnterCriticalSection(g_csMemoryUsage);
    }

    l_tPMSMem[pool].iCurrentMemory-=size;
#ifndef PMS_OIL_MERGE_DISABLE_MEM
    memVal -= size;
#endif
#ifdef SDK_MEMTRACE
    if(uCount < (sizeof(l_apUsed[pool]) / sizeof(l_apUsed[pool][0])))
      l_apUsed[pool][uCount] = NULL;
#endif

    if(g_csMemoryUsage) {
      PMS_LeaveCriticalSection(g_csMemoryUsage);
    }
    /*CRITICAL SECTION - END*/
#endif
  }
}