Пример #1
0
/* Unlock a memory pointer so it can be released if there is no
   references inside of harbour variables
*/
void *hb_gcUnlock( void *pBlock )
{

   if( pBlock )
   {
      HB_GARBAGE_PTR pAlloc = ( HB_GARBAGE_PTR ) pBlock;
      --pAlloc;

      if( pAlloc->locked )
      {
         if( --pAlloc->locked == 0 )
         {
            HB_CRITICAL_LOCK( hb_garbageAllocMutex );

            hb_gcUnlink( &s_pLockedBlock, pAlloc );

            hb_gcLink( &s_pCurrBlock, pAlloc );

            pAlloc->used = s_uUsedFlag;

            HB_CRITICAL_UNLOCK( hb_garbageAllocMutex );
         }
      }
   }

   return pBlock;
}
Пример #2
0
HB_ITEM_PTR hb_gcGripGet( HB_ITEM_PTR pOrigin )
{
   HB_GARBAGE_PTR pAlloc;

   #ifdef GC_RECYCLE
      HB_CRITICAL_LOCK( hb_garbageAllocMutex );
      if( s_pAvailableItems )
      {
         pAlloc = s_pAvailableItems;
         hb_gcUnlink( &s_pAvailableItems, s_pAvailableItems );
         HB_CRITICAL_UNLOCK( hb_garbageAllocMutex );
      }
      else
      {
         HB_CRITICAL_UNLOCK( hb_garbageAllocMutex );
         pAlloc = ( HB_GARBAGE_PTR ) hb_xgrab( sizeof( HB_ITEM ) + sizeof( HB_GARBAGE ) );
      }
   #else
      pAlloc = HB_GARBAGE_NEW( sizeof( HB_ITEM ) + sizeof( HB_GARBAGE ) );
   #endif

   if( pAlloc )
   {
      HB_ITEM_PTR pItem = ( HB_ITEM_PTR )( pAlloc + 1 );


      pAlloc->pFunc  = hb_gcGripRelease;
      pAlloc->locked = 1;
      pAlloc->used   = s_uUsedFlag;

      pItem->type = HB_IT_NIL;
      if( pOrigin )
      {
         hb_itemCopy( pItem, pOrigin );
      }

      HB_THREAD_GUARD( hb_garbageAllocMutex, hb_gcLink( &s_pLockedBlock, pAlloc ) );
      return pItem;
   }
   else
   {
      return NULL;
   }
}
Пример #3
0
/* allocates a memory block */
void * hb_gcAlloc( ULONG ulSize, HB_GARBAGE_FUNC_PTR pCleanupFunc )
{
   HB_GARBAGE_PTR pAlloc;

   #ifdef GC_RECYCLE
      HB_CRITICAL_LOCK( hb_garbageAllocMutex );
      if( s_pAvailableBaseArrays && ulSize == sizeof( HB_BASEARRAY ) )
      {
         pAlloc = s_pAvailableBaseArrays;
         hb_gcUnlink( &s_pAvailableBaseArrays, s_pAvailableBaseArrays );
         HB_CRITICAL_UNLOCK( hb_garbageAllocMutex );
      }
      else
      {
         HB_CRITICAL_UNLOCK( hb_garbageAllocMutex );
         pAlloc = ( HB_GARBAGE_PTR ) hb_xgrab( ulSize + sizeof( HB_GARBAGE ) );
      }
   #else
      pAlloc = HB_GARBAGE_NEW( ulSize + sizeof( HB_GARBAGE ) );
   #endif

   if( pAlloc )
   {
      pAlloc->pFunc  = pCleanupFunc;
      pAlloc->ulHolders = 0;
      pAlloc->locked = 0;
      pAlloc->used   = s_uUsedFlag;

      HB_CRITICAL_LOCK( hb_garbageAllocMutex );
      s_uAllocated++;
      s_uAllocatedCnt++;
      hb_gcLink( &s_pCurrBlock, pAlloc );
      HB_CRITICAL_UNLOCK( hb_garbageAllocMutex );

      HB_TRACE( HB_TR_DEBUG, ( "hb_gcAlloc %p in %p", pAlloc + 1, pAlloc ) );

      return (void *)( pAlloc + 1 );   /* hide the internal data */
   }
   else
   {
      return NULL;
   }
}
Пример #4
0
HB_EXPORT void wxTraceLog( const char * sTraceMsg, ... )
{
   char * sFile = NULL; 
   FILE *hFile;

   if( ! sTraceMsg )
   {
      return;
   }

   #ifdef HB_THREAD_SUPPORT
      HB_CRITICAL_LOCK( s_CriticalMutex );
   #endif

   if( sFile == NULL )
   {
      if( s_bEmpty )
      {
         s_bEmpty = FALSE;

         /* Empty the file if it exists. */
         hFile = fopen( LOG_NAME, "w" );
      }
      else
      {
         hFile = fopen( LOG_NAME, "a" );
      }
   }
   else
   {
      hFile = fopen( sFile, "a" );
   }

   if( hFile )
   {
      va_list ap;

      va_start( ap, sTraceMsg );
      vfprintf( hFile, sTraceMsg, ap );
      va_end( ap );

      vfprintf( hFile, "\n", NULL );
      fclose( hFile );
   }

   #ifdef HB_THREAD_SUPPORT
      HB_CRITICAL_UNLOCK( s_CriticalMutex );
   #endif
}
Пример #5
0
/* release a memory block allocated with hb_gcAlloc() */
void hb_gcFree( void *pBlock )
{
   HB_TRACE( HB_TR_DEBUG, ( "hb_gcFree(%p)", pBlock ) );

   if( hb_gc_bReleaseAll )
   {
      HB_TRACE( HB_TR_DEBUG, ( "Aborted - hb_gcFree(%p)", pBlock ) );
      return;
   }

   if( pBlock )
   {
      HB_GARBAGE_PTR pAlloc = ( HB_GARBAGE_PTR ) pBlock;
      --pAlloc;

      if( pAlloc->locked )
      {
         HB_TRACE( HB_TR_DEBUG, ( "hb_gcFree(%p) *LOCKED* %p", pBlock, pAlloc ) );

         HB_THREAD_GUARD( hb_garbageAllocMutex, hb_gcUnlink( &s_pLockedBlock, pAlloc ) );

         HB_GARBAGE_FREE( pAlloc );
      }
      else
      {
         // Might already be marked for deletion.
         HB_CRITICAL_LOCK( hb_garbageAllocMutex );
         if( ! ( pAlloc->used & HB_GC_DELETE ) )
         {
            s_uAllocated--;
            s_uAllocatedCnt--;
            hb_gcUnlink( &s_pCurrBlock, pAlloc );
            HB_GARBAGE_FREE( pAlloc );
         }
         HB_CRITICAL_UNLOCK( hb_garbageAllocMutex );
      }
   }
   else
   {
      hb_errInternal( HB_EI_XFREENULL, NULL, NULL, NULL );
   }
}
Пример #6
0
void hb_gcGripDrop( HB_ITEM_PTR pItem )
{

   HB_TRACE( HB_TR_DEBUG, ( "hb_gcGripDrop(%p)", pItem ) );

   if( hb_gc_bReleaseAll )
   {
      HB_TRACE( HB_TR_DEBUG, ( "Aborted - hb_gcGripDrop(%p)", pItem ) );
      return;
   }

   if( pItem )
   {
      HB_GARBAGE_PTR pAlloc = ( HB_GARBAGE_PTR ) pItem;
      --pAlloc;

      HB_TRACE( HB_TR_INFO, ( "Drop %p %p", pItem, pAlloc ) );

      if( pAlloc->pFunc == hb_gcGripRelease )
      {
         if( HB_IS_COMPLEX( pItem ) )
         {
            hb_itemClear( pItem );    /* clear value stored in this item */
         }
      }

      HB_CRITICAL_LOCK( hb_garbageAllocMutex );

      hb_gcUnlink( &s_pLockedBlock, pAlloc );

      HB_CRITICAL_UNLOCK( hb_garbageAllocMutex );

      HB_GARBAGE_FREE( pAlloc );
   }

}
Пример #7
0
//-------------------------------
// Manager of signals for windows
//
static LONG s_signalHandler( int type, int sig, PEXCEPTION_RECORD exc )
{
   PHB_ITEM pFunction, pExecArray, pRet;
   ULONG ulPos;
   UINT uiSig, uiMask;
   int iRet;

   // let's find the right signal handler.
   HB_CRITICAL_LOCK( s_ServiceMutex );

   // avoid working if PRG signal handling has been disabled
   if ( ! bSignalEnabled )
   {
      HB_CRITICAL_UNLOCK( s_ServiceMutex );
      return EXCEPTION_EXECUTE_HANDLER;
   }

   bSignalEnabled = FALSE;
   ulPos = hb_arrayLen( sp_hooks );
   // subsig not necessary
   uiSig = (UINT) s_translateSignal( (UINT)type, (UINT)sig );

   while( ulPos > 0 )
   {
      pFunction = hb_arrayGetItemPtr( sp_hooks, ulPos );
      uiMask = (UINT) hb_arrayGetNI( pFunction, 1 );
      if ( (uiMask & uiSig) == uiSig )
      {
         // we don't unlock the mutex now, even if it is
         // a little dangerous. But we are in a signal hander...
         // for now just 2 parameters
         pExecArray = hb_itemArrayNew( 3 );
         hb_arraySetForward( pExecArray, 1, hb_arrayGetItemPtr( pFunction, 2 ) );
         hb_arraySetNI( pExecArray, 2, uiSig );

         /* the third parameter is an array:
         * 1: low-level signal
         * 2: low-level subsignal
         * 3: low-level system error
         * 4: address that rised the signal
         * 5: process id of the signal riser
         * 6: UID of the riser
         */

         pRet = hb_arrayGetItemPtr( pExecArray, 3);
         hb_arrayNew( pRet, 6 );

         hb_arraySetNI( pRet, HB_SERVICE_OSSIGNAL, type );
         hb_arraySetNI( pRet, HB_SERVICE_OSSUBSIG, sig );
         //could be meaningless, but does not matter here
         hb_arraySetNI( pRet, HB_SERVICE_OSERROR, GetLastError() );

         if (type == 0 ) //exception
         {
            hb_arraySetPtr( pRet, HB_SERVICE_ADDRESS, ( void * ) exc->ExceptionAddress );
         }
         else
         {
            hb_arraySetPtr( pRet, HB_SERVICE_ADDRESS, NULL );
         }
         //TODO:
         hb_arraySetNI( pRet, HB_SERVICE_PROCESS, GetCurrentThreadId() );
         //TODO:
         hb_arraySetNI( pRet, HB_SERVICE_UID, 0 );

         pRet = hb_itemDo( pExecArray, 0 );
         iRet = hb_itemGetNI( pRet );
         hb_itemRelease( pRet );
         hb_itemRelease( pExecArray );

         switch( iRet )
         {
            case HB_SERVICE_HANDLED:
               bSignalEnabled = TRUE;
               HB_CRITICAL_UNLOCK( s_ServiceMutex );
               return EXCEPTION_CONTINUE_EXECUTION;

            case HB_SERVICE_QUIT:
               bSignalEnabled = FALSE;
               HB_CRITICAL_UNLOCK( s_ServiceMutex );
               hb_vmRequestQuit();
               #ifndef HB_THREAD_SUPPORT
                  hb_vmQuit();
                  exit(0);
               #else
                  hb_threadCancelInternal();
               #endif

         }
      }
      ulPos--;
   }

   bSignalEnabled = TRUE;
   return EXCEPTION_EXECUTE_HANDLER;
}
Пример #8
0
static void s_signalHandler( int sig, siginfo_t *info, void *v )
#endif
{
   UINT uiMask;
   UINT uiSig;
   PHB_ITEM pFunction, pExecArray, pRet;
   ULONG ulPos;
   int iRet;

   #if !( defined( HB_OS_OS2_GCC ) || defined( __WATCOMC__ ) )
   HB_SYMBOL_UNUSED(v);
   #endif

   // let's find the right signal handler.
   HB_CRITICAL_LOCK( s_ServiceMutex );

   // avoid working if PRG signal handling has been disabled
   if ( ! bSignalEnabled )
   {
      HB_CRITICAL_UNLOCK( s_ServiceMutex );
      return;
   }

   bSignalEnabled = FALSE;
   ulPos = hb_arrayLen( sp_hooks );
   // subsig not necessary
   uiSig = (UINT) s_translateSignal( (UINT)sig, 0 );

   while( ulPos > 0 )
   {
      pFunction = hb_arrayGetItemPtr( sp_hooks, ulPos );
      uiMask = (UINT) hb_arrayGetNI( pFunction, 1 );
      if ( uiMask & uiSig)
      {
         // we don't unlock the mutex now, even if it is
         // a little dangerous. But we are in a signal hander...
         // for now just 2 parameters
         pExecArray = hb_itemArrayNew( 3 );
         hb_arraySet( pExecArray, 1, hb_arrayGetItemPtr( pFunction, 2 ) );
         hb_arraySetNI( pExecArray, 2, uiSig );

         // the third parameter is an array:

         pRet = hb_arrayGetItemPtr( pExecArray, 3);
         #if defined( HB_OS_OS2_GCC ) || defined( __WATCOMC__ )
         hb_arrayNew( pRet, 1 );
         #elif defined( HB_OS_BSD )
         hb_arrayNew( pRet, info ? 6 : 1 );
         #else
         hb_arrayNew( pRet, 6 );
         #endif
         hb_arraySetNI( pRet, HB_SERVICE_OSSIGNAL, sig );
         #if !( defined( HB_OS_OS2_GCC ) || defined( __WATCOMC__ ) )
         #if defined( HB_OS_BSD )
         if (info)
         #endif
         {
            hb_arraySetNI( pRet, HB_SERVICE_OSSUBSIG, info->si_code );
            hb_arraySetNI( pRet, HB_SERVICE_OSERROR, info->si_errno );
            hb_arraySetPtr( pRet, HB_SERVICE_ADDRESS, (void *) info->si_addr );
            hb_arraySetNI( pRet, HB_SERVICE_PROCESS, info->si_pid );
            hb_arraySetNI( pRet, HB_SERVICE_UID, info->si_uid );
         }
         #endif

         pRet = hb_itemDo( pExecArray, 0 );
         iRet = hb_itemGetNI( pRet );
         hb_itemRelease( pRet );
         hb_itemRelease( pExecArray );

         switch( iRet )
         {
            case HB_SERVICE_HANDLED:
               bSignalEnabled = TRUE;
               HB_CRITICAL_UNLOCK( s_ServiceMutex );
               return;

            case HB_SERVICE_QUIT:
               bSignalEnabled = FALSE;
               HB_CRITICAL_UNLOCK( s_ServiceMutex );
               //TODO: A service cleanup routine
               hb_vmRequestQuit();
               #ifndef HB_THREAD_SUPPORT
                  hb_vmQuit();
                  exit(0);
               #else
                  /* Allow signals to go through pthreads */
                  s_serviceSetDflSig();
                  /* NOTICE: should be pthread_exit(0), but a bug in linuxthread prevents it:
                     calling pthread exit from a signal handler will cause infinite wait for
                     restart signal.
                     This solution is rude, while the other would allow clean VM termination...
                     but it works.
                  */
                  exit(0);
               #endif
         }
      }
      ulPos--;
   }

   bSignalEnabled = TRUE;
   /*s_serviceSetHBSig();*/

   /* TODO
   if ( uiSig != HB_SIGNAL_UNKNOWN )
   {
      if ( sa_oldAction[ sig ].sa_flags & SA_SIGINFO )
      {
         sa_oldAction[ sig ].sa_sigaction( sig, info, v );
      }
      else
      {
         sa_oldAction[ sig ].sa_handler( sig );
      }
   }*/
}
Пример #9
0
/* Check all memory blocks if they can be released
*/
void hb_gcCollectAll( BOOL bForce )
{
   HB_GARBAGE_PTR pAlloc, pDelete;

   HB_TRACE( HB_TR_INFO, ( "hb_gcCollectAll(%i), %p, %i", bForce, s_pCurrBlock, s_bCollecting ) );

   /* is anoter garbage in action? */
   #ifdef HB_THREAD_SUPPORT
      HB_CRITICAL_LOCK( hb_garbageAllocMutex );
      if ( s_pCurrBlock == NULL || ( bForce == FALSE && s_uAllocated < HB_GC_COLLECTION_JUSTIFIED ) )
      {
         HB_CRITICAL_UNLOCK( hb_garbageAllocMutex );
         return;
      }
      HB_CRITICAL_UNLOCK( hb_garbageAllocMutex );

      /* Force this thread to be an idle inspector: only this thread can run
         past this point; depending on settings, this thread may prevents others
         to regain control or just wait for a time where no thread is active. */
      hb_threadWaitForIdle();

   #else
      if ( s_bCollecting )  // note: 1) is volatile and 2) not very important if fails 1 time
      {
         return;
      }
      /* Even if not locked, a read only non-critical variable here
      should not be a problem */
      if( s_pCurrBlock == NULL || ( bForce == FALSE && s_uAllocated < HB_GC_COLLECTION_JUSTIFIED ) )
      {
         s_bCollecting = FALSE;
         return;
      }
   #endif

   /* By hypotesis, only one thread will be granted the right to be here;
   so cheching for consistency of s_pCurrBlock further is useless.*/

   /* Now that we are rightful owner of the GC process, we must
   * forbid all other threads from acting into the objects that
   * are going to be (in different times):
   * - scanned,
   * - freed (in their members)
   * - modified/released (in their strucure )
   *****/

   s_bCollecting = TRUE;
   s_uAllocated = 0;

   /* Step 1 - mark */
   /* All blocks are already marked because we are flipping
   * the used/unused flag
   */

   HB_TRACE( HB_TR_INFO, ( "Sweep Scan" ) );

   #ifdef TRACE_COLLECT
      TraceLog( NULL,  "Sweep Scan\n" );
   #endif

   /* Step 1 - MARK */
   /* check all known places for blocks they are referring */
   #ifdef HB_THREAD_SUPPORT
      hb_threadIsLocalRef();
   #else
      hb_vmIsLocalRef();
   #endif

   #ifdef TRACE_COLLECT
      TraceLog( NULL,  "After LocalRef\n" );
   #endif

   hb_vmIsStaticRef();
   #ifdef TRACE_COLLECT
      TraceLog( NULL,  "After StaticRef\n" );
   #endif

   hb_vmIsGlobalRef();
   #ifdef TRACE_COLLECT
      TraceLog( NULL,  "After Globals\n" );
   #endif

   #ifndef HB_THREAD_SUPPORT
   /* JC1: under MT, each threadIsLocalRef does its memvar reffing */
   hb_memvarsIsMemvarRef();
   #endif
   #ifdef TRACE_COLLECT
      TraceLog( NULL,  "After MemvarRef\n" );
   #endif

   hb_clsIsClassRef();
   #ifdef TRACE_COLLECT
      TraceLog( NULL,  "After ClassRef\n" );
   #endif

   if( HB_IS_GCITEM( &hb_vm_BreakBlock ) )
   {
      hb_gcItemRef( &hb_vm_BreakBlock );
   }
   #ifdef TRACE_COLLECT
      TraceLog( NULL,  "After BreakBlock\n" );
   #endif

   HB_TRACE( HB_TR_INFO, ( "Locked Scan" ) );

   /* check list of locked blocks for blocks referenced from
   * locked block
   */

   if( s_pLockedBlock )
   {
      pAlloc = s_pLockedBlock;

      do
      {
         /* it is not very elegant method but it works well */
         if( pAlloc->pFunc == hb_gcGripRelease )
         {
            hb_gcItemRef( ( HB_ITEM_PTR ) ( pAlloc + 1 ) );
         }
         else if( pAlloc->pFunc == hb_arrayReleaseGarbage )
         {
            HB_ITEM FakedItem;

            (&FakedItem)->type = HB_IT_ARRAY;
            (&FakedItem)->item.asArray.value = ( PHB_BASEARRAY )( pAlloc + 1 );

            hb_gcItemRef( &FakedItem );
         }
         else if( pAlloc->pFunc == hb_hashReleaseGarbage )
         {
            HB_ITEM FakedItem;

            (&FakedItem)->type = HB_IT_HASH;
            (&FakedItem)->item.asHash.value = ( PHB_BASEHASH )( pAlloc + 1 );

            hb_gcItemRef( &FakedItem );
         }
         else if( pAlloc->pFunc == hb_codeblockDeleteGarbage )
         {
            HB_ITEM FakedItem;

            (&FakedItem)->type = HB_IT_BLOCK;
            (&FakedItem)->item.asBlock.value = ( PHB_CODEBLOCK )( pAlloc + 1 );

            hb_gcItemRef( &FakedItem );
         }

         pAlloc = pAlloc->pNext;
      }
      while ( s_pLockedBlock != pAlloc );
   }
   #ifdef TRACE_COLLECT
      TraceLog( NULL,  "After Lock scan\n" );
   #endif

   HB_TRACE( HB_TR_INFO, ( "Cleanup Scan" ) );

   /* Step 3 - Call Cleanup Functions  */

   pAlloc = s_pCurrBlock;
   do
   {
      if( s_pCurrBlock->used == s_uUsedFlag )
      {
         s_pCurrBlock->used |= HB_GC_DELETE;

         /* call the cleanup function - now for NON Blosks. */
         if( s_pCurrBlock->pFunc )
         {
            HB_TRACE( HB_TR_INFO, ( "Cleanup, %p", s_pCurrBlock ) );
            ( s_pCurrBlock->pFunc )( ( void *)( s_pCurrBlock + 1 ) );
            HB_TRACE( HB_TR_INFO, ( "DONE Cleanup, %p", s_pCurrBlock ) );
         }
      }

      s_pCurrBlock = s_pCurrBlock->pNext;
   }
   while ( s_pCurrBlock && ( s_pCurrBlock != pAlloc ) );
   #ifdef TRACE_COLLECT
      TraceLog( NULL,  "After Cleanup scan\n" );
   #endif

   HB_TRACE( HB_TR_INFO, ( "Release Scan" ) );

   /* Step 4 - Release all blocks that are still marked as unused */
   pAlloc = s_pCurrBlock;
   do
   {
      NewTopBlock:

      if( s_pCurrBlock->used & HB_GC_DELETE )
      {
         HB_TRACE( HB_TR_INFO, ( "Delete, %p", s_pCurrBlock ) );

         pDelete = s_pCurrBlock;
         hb_gcUnlink( &s_pCurrBlock, s_pCurrBlock );

         /*
            Releasing the top block in the list, so we must mark the new top into pAlloc
            but we still need to process this new top. Without this goto, the while
            condition will immediatly fail. Using extra flags, and new conditions
            will adversly effect performance.
         */
         if( pDelete == pAlloc )
         {
            HB_TRACE( HB_TR_INFO, ( "New Top, %p", pDelete ) );

            pAlloc = s_pCurrBlock;
            HB_GARBAGE_FREE( pDelete );

            if( s_pCurrBlock )
            {
               goto NewTopBlock;
            }
         }
         else
         {
            HB_TRACE( HB_TR_INFO, ( "Free, %p", pDelete ) );
            HB_GARBAGE_FREE( pDelete );
            HB_TRACE( HB_TR_INFO, ( "DONE Free, %p", pDelete ) );
         }
      }
      else
      {
         s_pCurrBlock = s_pCurrBlock->pNext;
      }
   }
   while ( s_pCurrBlock && ( pAlloc != s_pCurrBlock ) );
   #ifdef TRACE_COLLECT
      TraceLog( NULL,  "After Release scan\n" );
   #endif

   s_pCurrBlock = pAlloc;

   /* Step 4 - flip flag */
   /* Reverse used/unused flag so we don't have to mark all blocks
   * during next collecting
   */
   s_uUsedFlag ^= HB_GC_USED_FLAG;

   /* Step 5: garbage requests will be now allowed again. */
   s_bCollecting = FALSE;

   /* Step 6: release all the locks on the scanned objects */
   /* Put itself back on machine execution count */

   #if defined( HB_THREAD_SUPPORT )
      hb_threadIdleEnd();
   #endif

}