Files
harbour-core/src/rtl/idle.c
Przemysław Czerpak e150da6f93 2017-04-14 16:36 UTC+0200 Przemyslaw Czerpak (druzus/at/poczta.onet.pl)
* include/hbapifs.h
  * src/rtl/filesys.c
    + added new C functions for UNIX and DJGPP builds:
         int hb_fsPollFD( PHB_POLLFD pPollSet, int iCount,
                          HB_MAXINT nTimeOut );
         int hb_fsCanRead( HB_FHANDLE hFileHandle, HB_MAXINT nTimeOut );
         int hb_fsCanWrite( HB_FHANDLE hFileHandle, HB_MAXINT nTimeOut );
      These functions should be used instead of select() in C code to hide
      low level access to select()/poll() functionality in *nix builds
      (they are supported by DJGPP only to simplify existing code common
      for DJGPP and *nix builds). Maximum file handle value which can be
      used in select() is limited by FD_SETSIZE. Please note that it's
      file handle value not number of file handles in the set. It creates
      serious problem for applications which operate on great number of
      handles (i.e. servers which have to keep open many sockets, pipes,
      files, etc. for their clients) so the new file/socket/pipe/...
      handle value can easy exceed FD_SETSIZE limit and in such case
      cannot be used with select(). The modification on
         2016-04-05 21:24 UTC+0200 Przemyslaw Czerpak
      resolved the problem only for sockets and pipes in code which uses
      corresponding hb_socket*() and hb_fsPipe*() API but not for all
      other cases. This one is for POSIX compilant code which needs pure
      POSIX select()/poll() functionality.
      Please note that HB_POLLFD structure should is compatible with
      struct pollfd defined by POSIX.1-2001 anyhow not all platforms
      confirm this standard so portable Harbour code should always use
      HB_POLLFD and HB_POLL* constant values instead of POLL* ones.

  * include/hbdate.h
  * src/common/hbdate.c
    + added new C functions to calculate timeouts:
         HB_MAXUINT hb_timerGet( void );
         HB_MAXUINT hb_timerInit( HB_MAXINT nTimeOut );
         HB_MAXINT  hb_timerTest( HB_MAXINT nTimeOut, HB_MAXUINT * pnTimer );
      They are designed to be used instead of direct access to
      hb_dateMilliSeconds(). Now they internally use hb_dateMilliSeconds()
      but it can be easy replaced by any other system monotonic clock by
      one local modification inside hb_timerGet() function.

  * src/rtl/filesys.c
    * use hb_timer*() functions instead of hb_dateMilliSeconds()
    * use hb_fsCanRead()/hb_fsCanWrite() instead of select()/poll()
      It also fixed timeout processing inside hb_fsPipeIsData() and
      hb_fsPipeWrite() in builds using poll()

  * src/rtl/filesys.c
  * src/rtl/gtcrs/gtcrs.h
  * src/rtl/gtcrs/gtcrs.c
  * src/rtl/gtpca/gtpca.c
  * src/rtl/gtsln/gtsln.c
  * src/rtl/gtsln/mousesln.c
  * src/rtl/gtstd/gtstd.c
  * src/rtl/gttrm/gttrm.c
  * src/rtl/gtxwc/gtxwc.c
    * use hb_timer*() functions instead of hb_dateMilliSeconds()
    * use hb_fsCanRead()/hb_fsCanWrite() instead of select()/poll()

  * src/vm/thread.c:
  * src/rtl/gtwin/gtwin.c
  * src/rtl/hbcom.c
  * src/rtl/hbgtcore.c
  * src/rtl/hblpp.c
  * src/rtl/idle.c
  * contrib/hbnetio/netiosrv.c:
  * contrib/hbssl/ssl_sock.c:
    * use hb_timer*() functions instead of hb_dateMilliSeconds()

  * contrib/xhb/hboutdbg.c
    * use hb_fsCanWrite() instead of select()

  * src/rtl/hbsocket.c
    ! repeat select() interrupted by signal inside hb_socketSelect()
      when poll() function is not available

  * src/3rd/hbdossrl/serial.c
    ! fixed -Wshift-negative-value GCC warnings
2017-04-14 16:36:50 +02:00

256 lines
7.7 KiB
C

/*
* The idle state collector
*
* Copyright 1999 Ryszard Glab <rglab@imid.med.pl>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this software; see the file COPYING.txt. If not, write to
* the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
* Boston, MA 02111-1307 USA (or visit the web site https://www.gnu.org/).
*
* As a special exception, the Harbour Project gives permission for
* additional uses of the text contained in its release of Harbour.
*
* The exception is that, if you link the Harbour libraries with other
* files to produce an executable, this does not by itself cause the
* resulting executable to be covered by the GNU General Public License.
* Your use of that executable is in no way restricted on account of
* linking the Harbour library code into it.
*
* This exception does not however invalidate any other reasons why
* the executable file might be covered by the GNU General Public License.
*
* This exception applies only to the code released by the Harbour
* Project under the name Harbour. If you copy code from other
* Harbour Project or Free Software Foundation releases into a copy of
* Harbour, as the General Public License permits, the exception does
* not apply to the code that you add in this way. To avoid misleading
* anyone as to the status of such modified files, you must delete
* this exception notice from them.
*
* If you write modifications of your own for Harbour, it is your choice
* whether to permit this exception to apply to your modifications.
* If you do not wish that, delete this exception notice.
*
*/
/*
* The following parts are Copyright of the individual authors.
*
* Copyright 1999 David G. Holm <dholm@jsd-llc.com>
* hb_ReleaseCPU()
*
* See COPYING.txt for licensing terms.
*
*/
#include "hbapi.h"
#include "hbapiitm.h"
#include "hbset.h"
#include "hbvm.h"
#include "hbstack.h"
#include "hbthread.h"
#include "hbdate.h"
#include "error.ch"
typedef struct
{
HB_BOOL fCollectGarbage; /* flag to force GC activation in idle state */
HB_BOOL fIamIdle; /* flag to prevent recursive calls of hb_idleState() */
int iIdleTask; /* current task to be executed */
int iIdleMaxTask; /* number of tasks in the list */
PHB_ITEM * pIdleTasks; /* list of background tasks */
} HB_IDLEDATA, * PHB_IDLEDATA;
static void hb_idleDataRelease( void * Cargo )
{
PHB_IDLEDATA pIdleData = ( PHB_IDLEDATA ) Cargo;
if( pIdleData->pIdleTasks )
{
do
{
hb_itemRelease( pIdleData->pIdleTasks[ --pIdleData->iIdleMaxTask ] );
}
while( pIdleData->iIdleMaxTask );
hb_xfree( pIdleData->pIdleTasks );
}
}
static HB_TSD_NEW( s_idleData, sizeof( HB_IDLEDATA ), NULL, hb_idleDataRelease );
void hb_releaseCPU( void )
{
HB_TRACE( HB_TR_DEBUG, ( "hb_releaseCPU()" ) );
hb_threadReleaseCPU();
}
/* performs all tasks defined for idle state */
void hb_idleState( void )
{
PHB_IDLEDATA pIdleData = ( PHB_IDLEDATA ) hb_stackGetTSD( &s_idleData );
if( ! pIdleData->fIamIdle )
{
pIdleData->fIamIdle = HB_TRUE;
hb_releaseCPU();
if( hb_vmRequestQuery() == 0 )
{
if( pIdleData->fCollectGarbage )
{
hb_gcCollectAll( HB_FALSE );
pIdleData->fCollectGarbage = HB_FALSE;
}
if( pIdleData->pIdleTasks && pIdleData->iIdleTask < pIdleData->iIdleMaxTask )
{
hb_itemRelease( hb_itemDo( pIdleData->pIdleTasks[ pIdleData->iIdleTask ], 0 ) );
++pIdleData->iIdleTask;
if( pIdleData->iIdleTask == pIdleData->iIdleMaxTask && hb_setGetIdleRepeat() )
{
pIdleData->iIdleTask = 0; /* restart processing of idle tasks */
pIdleData->fCollectGarbage = HB_TRUE;
}
}
}
pIdleData->fIamIdle = HB_FALSE;
}
}
void hb_idleReset( void )
{
PHB_IDLEDATA pIdleData = ( PHB_IDLEDATA ) hb_stackGetTSD( &s_idleData );
if( pIdleData->iIdleTask == pIdleData->iIdleMaxTask && ! hb_setGetIdleRepeat() )
pIdleData->iIdleTask = 0;
pIdleData->fCollectGarbage = HB_TRUE;
}
void hb_idleSleep( double dSeconds )
{
if( dSeconds >= 0 )
{
HB_MAXINT timeout = dSeconds > 0 ? ( HB_MAXINT ) ( dSeconds * 1000 ) : 0;
HB_MAXUINT timer = hb_timerInit( timeout );
do
{
hb_idleState();
}
while( ( timeout = hb_timerTest( timeout, &timer ) ) != 0 &&
hb_vmRequestQuery() == 0 );
hb_idleReset();
}
}
/* signal that the user code is in idle state */
HB_FUNC( HB_IDLESTATE )
{
PHB_IDLEDATA pIdleData = ( PHB_IDLEDATA ) hb_stackGetTSD( &s_idleData );
pIdleData->fCollectGarbage = HB_TRUE;
hb_idleState();
}
/* call from user code to reset idle state */
HB_FUNC( HB_IDLERESET )
{
hb_idleReset();
}
/* call from user code to stay in idle state for given period */
HB_FUNC( HB_IDLESLEEP )
{
hb_idleSleep( hb_parnd( 1 ) );
}
/* add a new background task and return its handle */
HB_FUNC( HB_IDLEADD )
{
PHB_ITEM pBlock = hb_param( 1, HB_IT_EVALITEM );
if( pBlock )
{
PHB_IDLEDATA pIdleData = ( PHB_IDLEDATA ) hb_stackGetTSD( &s_idleData );
++pIdleData->iIdleMaxTask;
if( ! pIdleData->pIdleTasks )
pIdleData->pIdleTasks = ( PHB_ITEM * ) hb_xgrab( sizeof( PHB_ITEM ) );
else
pIdleData->pIdleTasks = ( PHB_ITEM * ) hb_xrealloc( pIdleData->pIdleTasks, sizeof( PHB_ITEM ) * pIdleData->iIdleMaxTask );
/* store a copy of passed codeblock
*/
pIdleData->pIdleTasks[ pIdleData->iIdleMaxTask - 1 ] = hb_itemNew( pBlock );
/* return a pointer as a handle to this idle task
*/
hb_retptr( ( void * ) hb_codeblockId( pBlock ) ); /* TODO: access to pointers from harbour code */
}
}
/* Delete a task with given handle and return a codeblock with this task */
HB_FUNC( HB_IDLEDEL )
{
PHB_IDLEDATA pIdleData = ( PHB_IDLEDATA ) hb_stackTestTSD( &s_idleData );
void * pID = hb_parptr( 1 );
if( pID && pIdleData && pIdleData->pIdleTasks )
{
int iTask = 0;
while( iTask < pIdleData->iIdleMaxTask )
{
PHB_ITEM pItem = pIdleData->pIdleTasks[ iTask ];
if( pID == hb_codeblockId( pItem ) )
{
hb_itemClear( hb_itemReturn( pItem ) ); /* return a codeblock */
hb_itemRelease( pItem );
--pIdleData->iIdleMaxTask;
if( pIdleData->iIdleMaxTask )
{
if( iTask != pIdleData->iIdleMaxTask )
{
memmove( &pIdleData->pIdleTasks[ iTask ], &pIdleData->pIdleTasks[ iTask + 1 ],
sizeof( PHB_ITEM ) * ( pIdleData->iIdleMaxTask - iTask ) );
}
pIdleData->pIdleTasks = ( PHB_ITEM * ) hb_xrealloc( pIdleData->pIdleTasks, sizeof( PHB_ITEM ) * pIdleData->iIdleMaxTask );
if( pIdleData->iIdleTask >= pIdleData->iIdleMaxTask )
pIdleData->iIdleTask = 0;
}
else
{
hb_xfree( pIdleData->pIdleTasks );
pIdleData->pIdleTasks = NULL;
pIdleData->iIdleTask = 0;
}
break;
}
++iTask;
}
}
}
/* Release a CPU time slice */
HB_FUNC( HB_RELEASECPU )
{
hb_releaseCPU();
}