home *** CD-ROM | disk | FTP | other *** search
/ Monster Media 1993 #2 / Image.iso / clipper / nettos11.zip / SYNCHRO / SEMA.PRG < prev   
Text File  |  1993-04-01  |  11KB  |  400 lines

  1. /*
  2.  * File......: SEMA.PRG
  3.  * Author....: Glenn Scott
  4.  * CIS ID....: 71620,1521
  5.  * Date......: $Date$
  6.  * Revision..: $Revision$
  7.  * Log file..: $Logfile$
  8.  * 
  9.  * This is an original work by Glenn Scott and is placed in the
  10.  * public domain.
  11.  *
  12.  * Modification history:
  13.  * ---------------------
  14.  *
  15.  * $Log$
  16.  *
  17.  */
  18.  
  19. #include "netto.ch"
  20. #include "ftint86.ch"
  21.  
  22. #define    WAIT_SEMAPHORE    2
  23. #define    SIGNAL_SEMAPHORE  3
  24. #define    CLOSE_SEMAPHORE   4
  25.  
  26.  
  27. /*  $DOC$
  28.  *  $FUNCNAME$
  29.  *      fn_semOpen()
  30.  *  $CATEGORY$
  31.  *      Synchronization
  32.  *  $ONELINER$
  33.  *      Open or create a semaphore
  34.  *  $SYNTAX$
  35.  *
  36.  *      fn_semOpen( <cName>, <nInitVal>, <@nHandle>, <@nOpenCnt> ) -> nRc
  37.  *
  38.  *  $ARGUMENTS$
  39.  *
  40.  *      <cName> is the semaphore name, maximum length is 127 characters.
  41.  *
  42.  *      <nInitVal> is the initial value for the semaphore.  It must start
  43.  *      as a positive number, to a maximum of 127.
  44.  *
  45.  *      <@nHandle> is the semaphore handle.  THIS MUST BE PASSED BY 
  46.  *      REFERENCE!  On exit, <nHandle> will contain a numeric value that
  47.  *      refers to the opened semaphore.  You will need it to pass to 
  48.  *      other semaphore functions!  PASS IT BY REFERENCE!
  49.  *
  50.  *      <@nOpenCnt> is the number of stations that have opened the 
  51.  *      semaphore.  THIS MUST BE PASSED BY REFERENCE! On exit, <nOpenCnt>
  52.  *      will contain a numeric value.
  53.  *
  54.  *  $RETURNS$
  55.  *
  56.  *      nRc, a numeric result code, as follows:
  57.  *
  58.  *            0 - success
  59.  *          254 - Invalid semaphore name length
  60.  *          255 - Invalid semaphore value
  61.  *     
  62.  *      <nHandle> will contain the semaphore handle, and 
  63.  *      <nOpenCnt> will contain the number of stations that have opened
  64.  *      the semaphore.
  65.  *
  66.  *  $DESCRIPTION$
  67.  *
  68.  *      A semaphore is simply a label that indirectly controls network
  69.  *      activity.  There is a semaphore name, which can be up to 127
  70.  *      characters, and an associated value, which can range from 0 to
  71.  *      127.
  72.  *
  73.  *      A semaphore can be used for many things, but is most often used
  74.  *      to limit the number of users in an application, and to control
  75.  *      access to a network resource.
  76.  *
  77.  *      A semaphore essentially allows you to place locks on resources
  78.  *      other than files.  
  79.  *
  80.  *      An application begins the process by calling fn_semOpen().
  81.  *      If the semaphore doesn't exist, NetWare will create it.  
  82.  *      fn_semOpen() returns a handle that is used in other semaphore
  83.  *      calls.
  84.  *
  85.  *      Applications use fn_semWait() to wait for a semaphore to 
  86.  *      become available.  fn_semWait() decrements the semaphore's
  87.  *      value by 1.  If the value > 0, then the application should 
  88.  *      be allowed to access the semaphore's resource.  If the value 
  89.  *      goes negative, then the application is placed in a queue.
  90.  *      How long your app is in the queue is determined by how you 
  91.  *      set the timeout parameter.  If you can't get the resource in 
  92.  *      the time you allot, you're let out of the queue and the 
  93.  *      value increments by 1 again.
  94.  *
  95.  *      When an application finishes with a semaphore, it should 
  96.  *      call fn_semSig() to increment the value, and then 
  97.  *      fn_semClos() to close the semaphore.  When the semaphore's
  98.  *      open count goes to 0, NetWare deletes it.
  99.  *
  100.  *      fn_semEx() can be used to examine the value and open count
  101.  *      without affecting them.
  102.  *
  103.  *      For an interesting discussion on the operating system aspects
  104.  *      of semaphores, check "Operating Systems Design and Implementation"
  105.  *      by A. Tanenbaum, page 60.  For more details on NetWare's 
  106.  *      semaphore facilities, refer to Charles Rose's "Programmer's 
  107.  *      Guide to NetWare".  The "Programmer's Guide" will make an 
  108.  *      excellent companion guide to the source code for all NetWare
  109.  *      functions in the Nanforum Toolkit.
  110.  *
  111.  *  $EXAMPLES$
  112.  *
  113.  *      LOCAL nInitVal, nRc, nHandle, nOpenCnt
  114.  *
  115.  *      nInitVal := 2
  116.  *      nRc      := fn_semOpen( "Semaphore Test", nInitVal, ;
  117.  *                                @nHandle, @nOpenCnt )
  118.  *
  119.  *      IF nRc != 0
  120.  *        QOUT =: "Error: " + STR( nRc ) )
  121.  *        QUIT
  122.  *      ENDIF
  123.  *
  124.  *  $SEEALSO$
  125.  *      FN_SEMEX() FN_SEMWAIT() FN_SEMSIG() FN_SEMCLOS() 
  126.  *  $END$
  127.  */
  128.  
  129. function fn_semOpen( cName, nInitVal, nHandle, nOpenCnt )
  130.   local aRegs[ INT86_MAX_REGS ], cRequest, nRet
  131.  
  132.   default cName    to "",   ;
  133.           nInitVal to 0,    ;
  134.           nHandle  to 0,    ;
  135.           nOpenCnt to 0
  136.  
  137.  
  138.   cName    := iif( len( cName ) > 127, substr( cName, 1, 127 ), cName )
  139.   cRequest := chr( len( cName ) ) + cName
  140.  
  141.   aRegs[ AX ]      := makehi( 197 )                       // C5h
  142.   aRegs[ DS ]      := cRequest
  143.   aRegs[ DX ]      := REG_DS
  144.   aRegs[ CX ]      := nInitVal
  145.  
  146.   _fnSetErr( iif( !ft_int86( INT21, aRegs ), EINT86, lowbyte( aRegs[AX] ) ) )
  147.  
  148.   nHandle  := _fnReg2l( aRegs[ CX ], aRegs[ DX ] )
  149.   nOpenCnt := lowbyte( aRegs[ BX ] )
  150.  
  151.   return lowbyte( aRegs[AX] )
  152.  
  153.  
  154.  
  155.  
  156. /*  $DOC$
  157.  *  $FUNCNAME$
  158.  *      fn_semEx()
  159.  *  $CATEGORY$
  160.  *      Synchronization
  161.  *  $ONELINER$
  162.  *      Examine a semaphore's value and open count
  163.  *  $SYNTAX$
  164.  *
  165.  *      fn_semEx( <nHandle>, <@nValue>, <@nOpenCnt> ) -> nRc
  166.  *
  167.  *  $ARGUMENTS$
  168.  *
  169.  *      <nHandle> is the semaphore handle, returned from a previous call
  170.  *      to fn_semOpen().
  171.  *
  172.  *      <@nValue> will get the current semaphore value.  THIS NUMERIC
  173.  *      ARGUMENT MUST BE PASSED BY REFERENCE!
  174.  *
  175.  *      <@nOpenCnt> will get the current number of workstations 
  176.  *      that have opened the semaphore.  THIS NUMERIC ARGUMENT MUST BE
  177.  *      PASSED BY REFERENCE!
  178.  *
  179.  *  $RETURNS$
  180.  *
  181.  *      nRc, a numeric, as follows:
  182.  *
  183.  *            0 - success
  184.  *          255 - invalid semaphore handle
  185.  *
  186.  *      In addition, nValue will be set to the semaphore's current value,
  187.  *      and nOpenCnt will be set to the number of stations that have 
  188.  *      opened the semaphore.
  189.  *
  190.  *  $DESCRIPTION$
  191.  *
  192.  *      See the description for fn_semOpen().
  193.  *
  194.  *  $EXAMPLES$
  195.  *
  196.  *    nInitVal := 2
  197.  *    nHandle  := 0
  198.  *    nOpenCnt := 0
  199.  *
  200.  *    fn_semOpen( "Semaphore Test", nInitVal, @nHandle, @nOpenCnt )
  201.  *
  202.  *    nRc := fn_semWait( nHandle )
  203.  *        IF nRc == 254
  204.  *       QOUT( "All slots for this resource are currently in use" )
  205.  *       QUIT
  206.  *    ENDIF
  207.  *
  208.  *    fn_semEx( nHandle, @nValue, @nOpenCnt )
  209.  *    QOUT( "Semaphore test -> Open at [" + ;
  210.  *          ALLTRIM(STR(nOpenCnt))        + ;
  211.  *          "] stations, value is ["      + ;
  212.  *          ALLTRIM(STR(nValue)) + "]" )
  213.  *  $SEEALSO$
  214.  *      FN_SEMOPEN() FN_SEMWAIT() FN_SEMSIG() FN_SEMCLOS()
  215.  *  $END$
  216.  */
  217.  
  218.  
  219. function fn_semEx( nHandle, nValue, nOpenCnt )
  220.   local aRegs[ INT86_MAX_REGS ]
  221.  
  222.   default nHandle  to 0,  ;
  223.           nValue   to 0,  ;
  224.           nOpenCnt to 0
  225.  
  226.   aRegs[ AX ] :=  makehi( 197 ) + 1                         // C5h, 01h
  227.   aRegs[ CX ] :=  bin2i( substr( l2bin( nHandle ), 1, 2 ) )
  228.   aRegs[ DX ] :=  bin2i( substr( l2bin( nHandle ), 3, 2 ) )
  229.  
  230.   ft_int86( INT21, aRegs )
  231.  
  232.   nValue   := aRegs[ CX ]
  233.   nOpenCnt := lowbyte( aRegs[ DX ] ) 
  234.  
  235.   return lowbyte( aRegs[ AX ] ) 
  236.  
  237.  
  238. /*  $DOC$
  239.  *  $FUNCNAME$
  240.  *     FN_SEMWAIT()
  241.  *  $CATEGORY$
  242.  *     Synchronization
  243.  *  $ONELINER$
  244.  *     Wait on a semaphore (decrement)
  245.  *  $SYNTAX$
  246.  *
  247.  *     fn_semWait( <nHandle> [, nTimeout ] ) -> nRc
  248.  *
  249.  *  $ARGUMENTS$
  250.  *
  251.  *     <nHandle> is the semaphore handle, returned from a previous call
  252.  *     to fn_semOpen().
  253.  *
  254.  *     <nTimeOut> is an optional parameter telling how long you wish to
  255.  *     wait on this semaphore.  This is a numeric indicating the number
  256.  *     of clock ticks (approx 1/18 sec ) to wait.  A zero (the default)
  257.  *     means "don't wait."
  258.  *
  259.  *  $RETURNS$
  260.  *
  261.  *     nRc, a numeric, as follows:
  262.  *
  263.  *           0 - success
  264.  *         254 - timeout failure
  265.  *         255 - invalid semaphore handle
  266.  *
  267.  *  $DESCRIPTION$
  268.  *
  269.  *     See the description for the fn_semOpen() function.
  270.  *
  271.  *  $EXAMPLES$
  272.  *
  273.  *    fn_semOpen( "Semaphore Test", nInitVal, @nHandle, @nOpenCnt )
  274.  *
  275.  *    nRc := fn_semWait( nHandle )
  276.  *    IF nRc == 254
  277.  *       QOUT( "All slots for this resource are currently in use" )
  278.  *       QUIT
  279.  *    ENDIF
  280.  *
  281.  *  $SEEALSO$
  282.  *      FN_SEMOPEN() FN_SEMEX() FN_SEMSIG() FN_SEMCLOS()
  283.  *  $END$
  284.  */
  285.  
  286.  
  287.  
  288. function fn_semWait( nHandle, nTimeout )
  289.   return  _fnsem( WAIT_SEMAPHORE, nHandle, nTimeout )
  290.  
  291.  
  292.  
  293. /*  $DOC$
  294.  *  $FUNCNAME$
  295.  *     FN_SEMSIG()
  296.  *  $CATEGORY$
  297.  *     Synchronization
  298.  *  $ONELINER$
  299.  *     Signal a semaphore (increment)
  300.  *  $SYNTAX$
  301.  *
  302.  *     fn_semSig( <nHandle> ) -> nRc
  303.  *
  304.  *  $ARGUMENTS$
  305.  *
  306.  *     <nHandle> is the semaphore handle, returned from a previous call
  307.  *     to fn_semOpen().
  308.  *
  309.  *  $RETURNS$
  310.  *
  311.  *     nRc, a numeric, as follows
  312.  *
  313.  *          0 - success
  314.  *          1 - semaphore overflow ( value > 127 )
  315.  *        255 - invalid semaphore handle
  316.  *
  317.  *  $DESCRIPTION$
  318.  *
  319.  *      Use fn_semSig() when your app has finished with the resource
  320.  *      locked by a semaphore.  This will increase the value (thus
  321.  *      making a slot available to another app).
  322.  *
  323.  *      For more information, see the description under fn_semOpen().
  324.  *
  325.  *  $EXAMPLES$
  326.  *
  327.  *      QOUT( "Signal returns: " + STR( fn_semSig( nHandle ) ) )
  328.  *
  329.  *  $SEEALSO$
  330.  *      FN_SEMOPEN() FN_SEMEX() FN_SEMWAIT() FN_SEMCLOS()
  331.  *  $END$
  332.  */
  333.  
  334.  
  335. function fn_semSig( nHandle )
  336.   return  _fnsem( SIGNAL_SEMAPHORE, nHandle )
  337.  
  338.  
  339. /*  $DOC$
  340.  *  $FUNCNAME$
  341.  *     FN_SEMCLOS()
  342.  *  $CATEGORY$
  343.  *     Synchronization
  344.  *  $ONELINER$
  345.  *     Close a semaphore
  346.  *  $SYNTAX$
  347.  *
  348.  *     fn_semClos( <nHandle> )  -> nRc
  349.  *
  350.  *  $ARGUMENTS$
  351.  *
  352.  *     <nHandle> is the semaphore handle, returned from a previous call
  353.  *     to fn_semOpen().
  354.  *
  355.  *  $RETURNS$
  356.  *
  357.  *     nRc, a numeric, as follows:
  358.  *
  359.  *            0 - success
  360.  *          255 - invalid semaphore handle
  361.  *
  362.  *  $DESCRIPTION$
  363.  *
  364.  *     Call fn_semClos() when the app is finished.  This decrements
  365.  *     the open count for the semaphore.  If the open count hits zero,
  366.  *     the semaphore is deleted by NetWare.
  367.  *
  368.  *  $EXAMPLES$
  369.  *
  370.  *     QOUT( "Close returns:  " + STR( FT_NWSEMCLOSE( nHandle ) ) )
  371.  *
  372.  *  $SEEALSO$
  373.  *     FN_SEMOPEN() FN_SEMEX() FN_SEMWAIT() FN_SEMSIG() 
  374.  *  $END$
  375.  */
  376.  
  377. function fn_semClos( nHandle )
  378.   return  _fnsem( CLOSE_SEMAPHORE, nHandle )
  379.  
  380.  
  381. // ---------------------------------------------------------
  382. // _fnsem() - internal for the semaphore package
  383. // ---------------------------------------------------------
  384.  
  385. static function _fnsem( nOp, nHandle, nTimeout )
  386.   local aRegs[ INT86_MAX_REGS ]
  387.  
  388.   default nOp      to SIGNAL_SEMAPHORE, ;
  389.           nHandle  to 0,                ;
  390.           nTimeout to 0
  391.  
  392.   aRegs[ AX ] :=  makehi( 197 ) + nOp
  393.   aRegs[ CX ] :=  bin2i( substr( l2bin( nHandle ), 1, 2 ) )
  394.   aRegs[ DX ] :=  bin2i( substr( l2bin( nHandle ), 3, 2 ) )
  395.   aRegs[ BP ] :=  nTimeout
  396.  
  397.  
  398.   ft_int86( INT21, aRegs )
  399.   return lowbyte( aRegs[AX] )
  400.