* 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
256 lines
7.7 KiB
C
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();
|
|
}
|