home *** CD-ROM | disk | FTP | other *** search
- /*
- * 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 )
-