home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Power-Programmierung
/
CD1.mdf
/
magazine
/
nan_news
/
toolkit
/
nwsem.prg
< prev
next >
Wrap
Text File
|
1991-08-17
|
16KB
|
510 lines
/*
* File......: NWSEM.PRG
* Author....: Glenn Scott
* CIS ID....: 71620,1521
* Date......: $Date: 17 Aug 1991 16:11:46 $
* Revision..: $Revision: 1.2 $
* Log file..: $Logfile: E:/nanfor/src/nwsem.prv $
*
* This is an original work by Glenn Scott and is placed in the
* public domain.
*
* Modification history:
* ---------------------
*
* $Log: E:/nanfor/src/nwsem.prv $
*
* Rev 1.2 17 Aug 1991 16:11:46 GLENN
* Oops, I forgot to comment out some test code.
*
* Rev 1.1 15 Aug 1991 23:05:34 GLENN
* Forest Belt proofread/edited/cleaned up doc
*
* Rev 1.0 28 Jun 1991 00:44:14 GLENN
* Initial revision.
*
*/
// --------------------------------------------------------------
// Semaphore Package for Novell NetWare
// --------------------------------------------------------------
#include "ftint86.ch"
#define INT21 33
#xcommand DEFAULT <v1> TO <x1> [, <vN> TO <xN> ];
=> IIF((<v1>)=NIL,<v1>:=<x1>,NIL) [; IF((<vN>)=NIL,<vN>:=<xN>,NIL)]
#define WAIT_SEMAPHORE 2
#define SIGNAL_SEMAPHORE 3
#define CLOSE_SEMAPHORE 4
// Sorry this test routine is pretty lame but it sort of gets
// the point across
#ifdef FT_TEST
#define INITIAL_SEMAPHORE_VALUE 2
#define WAIT_SECONDS 1
function main()
local nInitVal, nRc, nHandle, nValue, nOpenCnt
cls
nInitVal := INITIAL_SEMAPHORE_VALUE
FT_NWSEMOPEN( "TEST", nInitVal, @nHandle, @nOpenCnt )
qout( "Waiting ten seconds..." )
nRc := ft_nwSemWait( nHandle, 180 )
qout( "Final nRc value = " + STR( nRc ) )
inkey(0)
if nRc == 254
qout("Couldn't get the semaphore. Try again.")
quit
end
cls
@ 24, 0 say "Any key to exit"
@ 0, 0 say "Handle: " + str( nHandle )
ft_nwSemEx( nHandle, @nValue, @nOpenCnt )
while .t.
@ 23, 0 say "Semaphore test -> Open at [" + ;
alltrim(str(nOpenCnt)) + ;
"] stations, value is [" + ;
alltrim(str(nValue)) + "]"
if inkey( WAIT_SECONDS ) != 0
exit
endif
tone( nHandle,.5 )
ft_nwSemEx( nHandle, @nValue, @nOpenCnt )
end
qout( "Signal returns: " + str( ft_nwsemSig( nHandle ) ) )
qout( "Close returns: " + str( ft_nwsemClose( nHandle ) ) )
return nil
#endif
/* $DOC$
* $FUNCNAME$
* FT_NWSEMOPEN()
* $CATEGORY$
* NetWare
* $ONELINER$
* Open or create a NetWare semaphore
* $SYNTAX$
* FT_NWSEMOPEN( <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 FT_NWSEMOPEN().
* If the semaphore doesn't exist, NetWare will create it.
* FT_NWSEMOPEN() returns a handle that is used in other semaphore
* calls.
*
* Applications use FT_NWSEMWAIT() to wait for a semaphore to
* become available. FT_NWSEMWAIT() 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 FT_NWSEMSIG() to increment the value, and then
* FT_NWSEMCLOSE() to close the semaphore. When the semaphore's
* open count goes to 0, NetWare deletes it.
*
* FT_NWSEMEX() 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 := FT_NWSEMOPEN( "Semaphore Test", nInitVal, ;
* @nHandle, @nOpenCnt )
*
* IF nRc != 0
* QOUT =: "Error: " + STR( nRc ) )
* QUIT
* ENDIF
* $SEEALSO$
* FT_NWSEMEX() FT_NWSEMWAIT() FT_NWSEMSIG() FT_NWSEMCLOSE() FT_NWSEMLOCK()
* $END$
*/
function ft_nwSemOpen( 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
ft_int86( INT21, aRegs )
nHandle := bin2l( i2bin( aRegs[CX] ) + i2bin( aRegs[DX] ) )
nOpenCnt := lowbyte( aRegs[ BX ] )
nRet := lowbyte( aRegs[AX] )
return iif( nRet < 0, nRet + 256, nRet )
/* $DOC$
* $FUNCNAME$
* FT_NWSEMEX()
* $CATEGORY$
* NetWare
* $ONELINER$
* Examine a NetWare semaphore's value and open count
* $SYNTAX$
* FT_NWSEMEX( <nHandle>, <@nValue>, <@nOpenCnt> ) -> nRc
* $ARGUMENTS$
* <nHandle> is the semaphore handle, returned from a previous call
* to FT_NWSEMOPEN().
*
* <@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 FT_NWSEMOPEN().
* $EXAMPLES$
* nInitVal := 2
* nHandle := 0
* nOpenCnt := 0
*
* FT_NWSEMOPEN( "Semaphore Test", nInitVal, @nHandle, @nOpenCnt )
*
* nRc := FT_NWSEMWAIT( nHandle )
* IF nRc == 254
* QOUT( "All slots for this resource are currently in use" )
* QUIT
* ENDIF
*
* FT_NWSEMEX( nHandle, @nValue, @nOpenCnt )
* QOUT( "Semaphore test -> Open at [" + ;
* ALLTRIM(STR(nOpenCnt)) + ;
* "] stations, value is [" + ;
* ALLTRIM(STR(nValue)) + "]" )
* $SEEALSO$
* FT_NWSEMOPEN() FT_NWSEMWAIT() FT_NWSEMSIG() FT_NWSEMCLOSE() FT_NWSEMLOCK()
* $END$
*/
function ft_nwSemEx( nHandle, nValue, nOpenCnt )
local aRegs[ INT86_MAX_REGS ], nRet
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 )
#ifdef FT_TEST
@ 5, 1 say highbyte( aregs[CX] )
@ 6, 1 say lowbyte( aregs[CX ] )
#endif
nValue := aRegs[ CX ]
nOpenCnt := lowbyte( aRegs[ DX ] )
nRet := lowbyte( aRegs[ AX ] )
return iif( nRet < 0, nRet + 256, nRet )
/* $DOC$
* $FUNCNAME$
* FT_NWSEMWAIT()
* $CATEGORY$
* NetWare
* $ONELINER$
* Wait on a NetWare semaphore (decrement)
* $SYNTAX$
* FT_NWSEMWAIT( <nHandle> [, nTimeout ] ) -> nRc
* $ARGUMENTS$
* <nHandle> is the semaphore handle, returned from a previous call
* to FT_NWSEMOPEN().
*
* <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 FT_NWSEMOPEN() function.
* $EXAMPLES$
* FT_NWSEMOPEN( "Semaphore Test", nInitVal, @nHandle, @nOpenCnt )
*
* nRc := FT_NWSEMWAIT( nHandle )
* IF nRc == 254
* QOUT( "All slots for this resource are currently in use" )
* QUIT
* ENDIF
* $SEEALSO$
* FT_NWSEMOPEN() FT_NWSEMEX() FT_NWSEMSIG() FT_NWSEMCLOSE() FT_NWSEMLOCK()
* $END$
*/
function ft_nwSemWait( nHandle, nTimeout )
return _ftnwsem( WAIT_SEMAPHORE, nHandle, nTimeout )
/* $DOC$
* $FUNCNAME$
* FT_NWSEMSIG()
* $CATEGORY$
* NetWare
* $ONELINER$
* Signal a NetWare semaphore (increment)
* $SYNTAX$
* FT_NWSEMSIG( nHandle ) -> nRc
* $ARGUMENTS$
* <nHandle> is the semaphore handle, returned from a previous call
* to FT_NWSEMOPEN().
* $RETURNS$
* nRc, a numeric, as follows
*
* 0 - success
* 1 - semaphore overflow ( value > 127 )
* 255 - invalid semaphore handle
* $DESCRIPTION$
* Use FT_NWSEMSIG() 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 FT_NWSEMOPEN().
* $EXAMPLES$
* QOUT( "Signal returns: " + STR( FT_NWSEMSIG( nHandle ) ) )
* $SEEALSO$
* FT_NWSEMOPEN() FT_NWSEMEX() FT_NWSEMWAIT() FT_NWSEMCLOSE() FT_NWSEMLOCK()
* $END$
*/
function ft_nwSemSig( nHandle )
return _ftnwsem( SIGNAL_SEMAPHORE, nHandle )
/* $DOC$
* $FUNCNAME$
* FT_NWSEMCLOSE()
* $CATEGORY$
* NetWare
* $ONELINER$
* Close a NetWare semaphore
* $SYNTAX$
* FT_NWSEMCLOSE( <nHandle> ) -> nRc
* $ARGUMENTS$
* <nHandle> is the semaphore handle, returned from a previous call
* to FT_NWSEMOPEN().
* $RETURNS$
* nRc, a numeric, as follows:
*
* 0 - success
* 255 - invalid semaphore handle
* $DESCRIPTION$
* Call FT_NWSEMCLOSE() 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$
* FT_NWSEMOPEN() FT_NWSEMEX() FT_NWSEMWAIT() FT_NWSEMSIG() FT_NWSEMLOCK()
* $END$
*/
function ft_nwSemClose( nHandle )
return _ftnwsem( CLOSE_SEMAPHORE, nHandle )
// ---------------------------------------------------------
// _ftnwsem() - internal for the semaphore package
// ---------------------------------------------------------
static function _ftnwsem( nOp, nHandle, nTimeout )
local aRegs[ INT86_MAX_REGS ],;
nRet
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 )
nRet := lowbyte( aRegs[AX] )
nRet := iif( nRet < 0, nRet + 256, nRet )
return nRet
/* $DOC$
* $FUNCNAME$
* FT_NWSEMLOCK()
* $CATEGORY$
* NetWare
* $ONELINER$
* Perform a semaphore "lock"
* $SYNTAX$
* FT_NWSEMLOCK ( <cSemaphore> ) -> lRet
* $ARGUMENTS$
* <cSemaphore> is the name of a semaphore you want to "lock."
* $RETURNS$
* lRet == .t. if you get the lock, .f. if you don't.
* $DESCRIPTION$
* FT_NWSEMLOCK() uses the Nanforum Toolkit's NetWare Semaphore API functions
* in order to provide a general purpose "lock" you can use in
* a NetWare environment.
*
* An interesting byproduct of NetWare's semaphore functions is
* the "open count" which tells you how many connections have this
* semaphore open. This is different from the semaphore's _value_,
* which is set when the semaphore is opened and changed with
* signal() and wait().
*
* The point of semaphores is that you don't care how many users
* are using the resource; you merely wait on a semaphore until
* the resource becomes available or you give up. When you're done,
* you signal it and off you go.
*
* Back to the open count. FT_NWSEMLOCK() opens the semaphore
* as named in <cSemaphore>. After it is opened, the open count
* is checked. If it is anything other than 1, that means someone
* else has it (or you failed in your open) so the semaphore is
* closed and the "lock" is refused. If the value is 1, then your
* app is that 1 station so the "lock" is granted.
*
* You can use a semaphore lock to control access to anything
* that Clipper's RLOCK() and FLOCK() can't help you with, such
* as text files written with the low level file i/o functions,
* etc.
* $EXAMPLES$
* IF FT_NWSEMLOCK( "k:\apps\error.log" )
* // Note, you aren't actually LOCKING this file, you are
* // just locking a semaphore by the same name. As long as
* // all apps that might be using this file are cooperating
* // with the same kind of semaphore lock, you can effectively
* // control access to the file.
* ELSE
* QOUT("Couldn't lock file.")
* ENDIF
* $SEEALSO$
* FT_NWSEMOPEN() FT_NWSEMEX() FT_NWSEMWAIT() FT_NWSEMSIG()
* $END$
*/
function ft_nwSemLock( cSemaphore )
local nRc
local nHandle := 0
local nOpenCnt := 0
nRc := FT_NWSEMOPEN( cSemaphore, 0, @nHandle, @nOpenCnt )
if nRc == 0
if nOpenCnt != 1
ft_nwSemClose( nHandle )
endif
endif
return ( nOpenCnt == 1 )