home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
PC Press 1997 July
/
Sezamfile97_1.iso
/
msdos
/
clipper
/
nettos11.a01
/
SYNCHRO
/
SEMA.PRG
< prev
Wrap
Text File
|
1993-04-01
|
11KB
|
400 lines
/*
* File......: SEMA.PRG
* Author....: Glenn Scott
* CIS ID....: 71620,1521
* Date......: $Date$
* Revision..: $Revision$
* Log file..: $Logfile$
*
* This is an original work by Glenn Scott and is placed in the
* public domain.
*
* Modification history:
* ---------------------
*
* $Log$
*
*/
#include "netto.ch"
#include "ftint86.ch"
#define WAIT_SEMAPHORE 2
#define SIGNAL_SEMAPHORE 3
#define CLOSE_SEMAPHORE 4
/* $DOC$
* $FUNCNAME$
* fn_semOpen()
* $CATEGORY$
* Synchronization
* $ONELINER$
* Open or create a semaphore
* $SYNTAX$
*
* fn_semOpen( <cName>, <nInitVal>, <@nHandle>, <@nOpenCnt> ) -> nRc
*
* $ARGUMENTS$
*
* <cName> is the semaphore name, maximum length is 127 characters.
*
* <nInitVal> is the initial value for the semaphore. It must start
* as a positive number, to a maximum of 127.
*
* <@nHandle> is the semaphore handle. THIS MUST BE PASSED BY
* REFERENCE! On exit, <nHandle> will contain a numeric value that
* refers to the opened semaphore. You will need it to pass to
* other semaphore functions! PASS IT BY REFERENCE!
*
* <@nOpenCnt> is the number of stations that have opened the
* semaphore. THIS MUST BE PASSED BY REFERENCE! On exit, <nOpenCnt>
* will contain a numeric value.
*
* $RETURNS$
*
* nRc, a numeric result code, as follows:
*
* 0 - success
* 254 - Invalid semaphore name length
* 255 - Invalid semaphore value
*
* <nHandle> will contain the semaphore handle, and
* <nOpenCnt> will contain the number of stations that have opened
* the semaphore.
*
* $DESCRIPTION$
*
* A semaphore is simply a label that indirectly controls network
* activity. There is a semaphore name, which can be up to 127
* characters, and an associated value, which can range from 0 to
* 127.
*
* A semaphore can be used for many things, but is most often used
* to limit the number of users in an application, and to control
* access to a network resource.
*
* A semaphore essentially allows you to place locks on resources
* other than files.
*
* An application begins the process by calling fn_semOpen().
* If the semaphore doesn't exist, NetWare will create it.
* fn_semOpen() returns a handle that is used in other semaphore
* calls.
*
* Applications use fn_semWait() to wait for a semaphore to
* become available. fn_semWait() decrements the semaphore's
* value by 1. If the value > 0, then the application should
* be allowed to access the semaphore's resource. If the value
* goes negative, then the application is placed in a queue.
* How long your app is in the queue is determined by how you
* set the timeout parameter. If you can't get the resource in
* the time you allot, you're let out of the queue and the
* value increments by 1 again.
*
* When an application finishes with a semaphore, it should
* call fn_semSig() to increment the value, and then
* fn_semClos() to close the semaphore. When the semaphore's
* open count goes to 0, NetWare deletes it.
*
* fn_semEx() can be used to examine the value and open count
* without affecting them.
*
* For an interesting discussion on the operating system aspects
* of semaphores, check "Operating Systems Design and Implementation"
* by A. Tanenbaum, page 60. For more details on NetWare's
* semaphore facilities, refer to Charles Rose's "Programmer's
* Guide to NetWare". The "Programmer's Guide" will make an
* excellent companion guide to the source code for all NetWare
* functions in the Nanforum Toolkit.
*
* $EXAMPLES$
*
* LOCAL nInitVal, nRc, nHandle, nOpenCnt
*
* nInitVal := 2
* nRc := fn_semOpen( "Semaphore Test", nInitVal, ;
* @nHandle, @nOpenCnt )
*
* IF nRc != 0
* QOUT =: "Error: " + STR( nRc ) )
* QUIT
* ENDIF
*
* $SEEALSO$
* FN_SEMEX() FN_SEMWAIT() FN_SEMSIG() FN_SEMCLOS()
* $END$
*/
function fn_semOpen( cName, nInitVal, nHandle, nOpenCnt )
local aRegs[ INT86_MAX_REGS ], cRequest, nRet
default cName to "", ;
nInitVal to 0, ;
nHandle to 0, ;
nOpenCnt to 0
cName := iif( len( cName ) > 127, substr( cName, 1, 127 ), cName )
cRequest := chr( len( cName ) ) + cName
aRegs[ AX ] := makehi( 197 ) // C5h
aRegs[ DS ] := cRequest
aRegs[ DX ] := REG_DS
aRegs[ CX ] := nInitVal
_fnSetErr( iif( !ft_int86( INT21, aRegs ), EINT86, lowbyte( aRegs[AX] ) ) )
nHandle := _fnReg2l( aRegs[ CX ], aRegs[ DX ] )
nOpenCnt := lowbyte( aRegs[ BX ] )
return lowbyte( aRegs[AX] )
/* $DOC$
* $FUNCNAME$
* fn_semEx()
* $CATEGORY$
* Synchronization
* $ONELINER$
* Examine a semaphore's value and open count
* $SYNTAX$
*
* fn_semEx( <nHandle>, <@nValue>, <@nOpenCnt> ) -> nRc
*
* $ARGUMENTS$
*
* <nHandle> is the semaphore handle, returned from a previous call
* to fn_semOpen().
*
* <@nValue> will get the current semaphore value. THIS NUMERIC
* ARGUMENT MUST BE PASSED BY REFERENCE!
*
* <@nOpenCnt> will get the current number of workstations
* that have opened the semaphore. THIS NUMERIC ARGUMENT MUST BE
* PASSED BY REFERENCE!
*
* $RETURNS$
*
* nRc, a numeric, as follows:
*
* 0 - success
* 255 - invalid semaphore handle
*
* In addition, nValue will be set to the semaphore's current value,
* and nOpenCnt will be set to the number of stations that have
* opened the semaphore.
*
* $DESCRIPTION$
*
* See the description for fn_semOpen().
*
* $EXAMPLES$
*
* nInitVal := 2
* nHandle := 0
* nOpenCnt := 0
*
* fn_semOpen( "Semaphore Test", nInitVal, @nHandle, @nOpenCnt )
*
* nRc := fn_semWait( nHandle )
* IF nRc == 254
* QOUT( "All slots for this resource are currently in use" )
* QUIT
* ENDIF
*
* fn_semEx( nHandle, @nValue, @nOpenCnt )
* QOUT( "Semaphore test -> Open at [" + ;
* ALLTRIM(STR(nOpenCnt)) + ;
* "] stations, value is [" + ;
* ALLTRIM(STR(nValue)) + "]" )
* $SEEALSO$
* FN_SEMOPEN() FN_SEMWAIT() FN_SEMSIG() FN_SEMCLOS()
* $END$
*/
function fn_semEx( nHandle, nValue, nOpenCnt )
local aRegs[ INT86_MAX_REGS ]
default nHandle to 0, ;
nValue to 0, ;
nOpenCnt to 0
aRegs[ AX ] := makehi( 197 ) + 1 // C5h, 01h
aRegs[ CX ] := bin2i( substr( l2bin( nHandle ), 1, 2 ) )
aRegs[ DX ] := bin2i( substr( l2bin( nHandle ), 3, 2 ) )
ft_int86( INT21, aRegs )
nValue := aRegs[ CX ]
nOpenCnt := lowbyte( aRegs[ DX ] )
return lowbyte( aRegs[ AX ] )
/* $DOC$
* $FUNCNAME$
* FN_SEMWAIT()
* $CATEGORY$
* Synchronization
* $ONELINER$
* Wait on a semaphore (decrement)
* $SYNTAX$
*
* fn_semWait( <nHandle> [, nTimeout ] ) -> nRc
*
* $ARGUMENTS$
*
* <nHandle> is the semaphore handle, returned from a previous call
* to fn_semOpen().
*
* <nTimeOut> is an optional parameter telling how long you wish to
* wait on this semaphore. This is a numeric indicating the number
* of clock ticks (approx 1/18 sec ) to wait. A zero (the default)
* means "don't wait."
*
* $RETURNS$
*
* nRc, a numeric, as follows:
*
* 0 - success
* 254 - timeout failure
* 255 - invalid semaphore handle
*
* $DESCRIPTION$
*
* See the description for the fn_semOpen() function.
*
* $EXAMPLES$
*
* fn_semOpen( "Semaphore Test", nInitVal, @nHandle, @nOpenCnt )
*
* nRc := fn_semWait( nHandle )
* IF nRc == 254
* QOUT( "All slots for this resource are currently in use" )
* QUIT
* ENDIF
*
* $SEEALSO$
* FN_SEMOPEN() FN_SEMEX() FN_SEMSIG() FN_SEMCLOS()
* $END$
*/
function fn_semWait( nHandle, nTimeout )
return _fnsem( WAIT_SEMAPHORE, nHandle, nTimeout )
/* $DOC$
* $FUNCNAME$
* FN_SEMSIG()
* $CATEGORY$
* Synchronization
* $ONELINER$
* Signal a semaphore (increment)
* $SYNTAX$
*
* fn_semSig( <nHandle> ) -> nRc
*
* $ARGUMENTS$
*
* <nHandle> is the semaphore handle, returned from a previous call
* to fn_semOpen().
*
* $RETURNS$
*
* nRc, a numeric, as follows
*
* 0 - success
* 1 - semaphore overflow ( value > 127 )
* 255 - invalid semaphore handle
*
* $DESCRIPTION$
*
* Use fn_semSig() when your app has finished with the resource
* locked by a semaphore. This will increase the value (thus
* making a slot available to another app).
*
* For more information, see the description under fn_semOpen().
*
* $EXAMPLES$
*
* QOUT( "Signal returns: " + STR( fn_semSig( nHandle ) ) )
*
* $SEEALSO$
* FN_SEMOPEN() FN_SEMEX() FN_SEMWAIT() FN_SEMCLOS()
* $END$
*/
function fn_semSig( nHandle )
return _fnsem( SIGNAL_SEMAPHORE, nHandle )
/* $DOC$
* $FUNCNAME$
* FN_SEMCLOS()
* $CATEGORY$
* Synchronization
* $ONELINER$
* Close a semaphore
* $SYNTAX$
*
* fn_semClos( <nHandle> ) -> nRc
*
* $ARGUMENTS$
*
* <nHandle> is the semaphore handle, returned from a previous call
* to fn_semOpen().
*
* $RETURNS$
*
* nRc, a numeric, as follows:
*
* 0 - success
* 255 - invalid semaphore handle
*
* $DESCRIPTION$
*
* Call fn_semClos() when the app is finished. This decrements
* the open count for the semaphore. If the open count hits zero,
* the semaphore is deleted by NetWare.
*
* $EXAMPLES$
*
* QOUT( "Close returns: " + STR( FT_NWSEMCLOSE( nHandle ) ) )
*
* $SEEALSO$
* FN_SEMOPEN() FN_SEMEX() FN_SEMWAIT() FN_SEMSIG()
* $END$
*/
function fn_semClos( nHandle )
return _fnsem( CLOSE_SEMAPHORE, nHandle )
// ---------------------------------------------------------
// _fnsem() - internal for the semaphore package
// ---------------------------------------------------------
static function _fnsem( nOp, nHandle, nTimeout )
local aRegs[ INT86_MAX_REGS ]
default nOp to SIGNAL_SEMAPHORE, ;
nHandle to 0, ;
nTimeout to 0
aRegs[ AX ] := makehi( 197 ) + nOp
aRegs[ CX ] := bin2i( substr( l2bin( nHandle ), 1, 2 ) )
aRegs[ DX ] := bin2i( substr( l2bin( nHandle ), 3, 2 ) )
aRegs[ BP ] := nTimeout
ft_int86( INT21, aRegs )
return lowbyte( aRegs[AX] )