Using a file as semaphore

[Autolink] Menu

 
/* sample code to ensure that a program does not run two or more      */
/* times at once. This code also handles program crashes!             */
/*                                                                    */
/* Note: Run this program in 2 or more windows at the same time!      */
/*                                                                    */
/* Description:                                                       */
/*                                                                    */
/* This program uses a file as semaphore. This is possible because    */
/* OS/2 REXX does not support shared files - only one REXX program    */
/* can have write access to a file at any time.                       */
/*                                                                    */
/* There are 3 cases to check at the start of the program             */
/*                                                                    */
/* 1. Another instance of the program is already running.             */
/*    In this case the semaphore file exists. The program cannot      */
/*    delete it because the other instance running has locked it.     */
/*                                                                    */
/* 2. No other instance of the program is running and the last        */
/*    call of the program ended without an error.                     */
/*    In this case the semaphore file does not exist. The program can */
/*    create and lock it.                                             */
/*                                                                    */
/* 3. No other instance of the program is running but the last call   */
/*    of the program crashed.                                         */
/*    In this case the semaphore file exists, but the program can     */
/*    delete it because there is no other program locking it.         */
/*    After that the program can create and lock the semaphore file.  */
/*                                                                    */
/*    Note that this algorithm works because OS/2 closes all open     */
/*    files if a program ends.                                        */
/*                                                                    */
/* Note that the new REXXUTIL introduced with Object-Oriented REXX    */
/* contains functions to use normal OS/2 semaphores in REXX programs. */
/*                                                                    */
/* (see also Simulate a semaphore and                                 */
/* Using REXX queues to simulate a semaphore)                         */
/*                                                                    */
/* (c) 1996 Bernd Schemmer, Germany, EMail: Bernd.Schemmer@gmx.de     */
/*                                                                    */

                        /* name of the semaphore file                 */
  SemFile = "C:\MySem"

  call CharOut , "Waiting for the semaphore ..."

  do forever
    i = TestAndSetSemaphor( semFile )
    select

      when i = 1 then
      do
        say "... ok. Semaphore set."
        leave
      end /* when i = 1 */

      when i = 2 then
      do
        say
        say " ... Ops: The last program call " || ,
            "died because of an accident!"
        say " now this instance has set the semaphore."
        leave
      end /* when i = 0 */

      otherwise
      do
                        /* semaphore is already in use - just wait    */
        call CharOut , "."
      end /* otherwise */

    end /* select */
  end /* do forever */

                        /* if we come to this part of the code, we    */
                        /* have set the semaphore                     */
  say "Enter I to simulate a program crash, or any other key to end  "
  say "the program normally ..."
  userKey = translate( left( strip( lineIn() ),1 ) )

  if userKey = "I" then
  do
                        /* simulate a program crash without deleting  */
                        /* the semaphore                              */
    say "Now simulating a program crash without " || ,
        "resetting the semaphore ..."
    exit 255
  end /* if userKey = "I" then */

                        /* normal program end - delete the semaphore  */
  say "Now deleting the semaphore and ending the program ..."
  call DeleteSemaphor semFile
exit 0

/* ------------------------------------------------------------------ */
/* Function: Test the semaphore and set it if it is free              */
/*                                                                    */
/* call:     TestAndSetSemaphor semaphorFileName                      */
/*                                                                    */
/* where:    semaphorFileName                                         */
/*              - fully qualified name of the semaphore file          */
/*                                                                    */
/* returns:  0 - error, semaphore is already set                      */
/*           1 - okay, semaphore set                                  */
/*           2 - okay, semaphore set, the last program call crashes   */
/*           else error setting the semaphore                         */
/*                                                                    */
TestAndSetSemaphor: PROCEDURE
  parse arg semaphorFileName .

                        /* init the return code                       */
  thisRC = -1

  if stream( semaphorFileName, "c", "QUERY EXISTS" ) <> "" then
  do
                        /* semaphore file exists                      */
                        /* -> either an instance of this program is   */
                        /*    already running or the last call of the */
                        /*    program crashed                         */

                        /* try to delete the semaphore file           */
    "@del " semaphorFileName "2>NUL 1>NUL"
    if rc = 0 then
    do
                        /* semaphore file deleted                     */
                        /* -> no other instance of this program is    */
                        /*    running but the last call crashes       */

                        /* try to set the semaphore                   */
      if stream( semaphorFileName, "c", "OPEN WRITE" ) = "READY:" then
      do
                        /* semaphore set                              */
        thisRC = 2
      end /* if stream( semaphorFileName, "c", "OPEN WRITE" ) = ...  */
      else
      do
                        /* something went wrong ...                   */
        thisRC = -1
      end /* else */
    end /* if rc = 0 */
    else
    do
                        /* we cannot delete the semaphore file        */
                        /* -> another instance of this program is     */
                        /*    already running                         */
      thisRC = 0
    end /* else */
  end /* if stream( semaphorFileName, "c", "QUERY EXISTS" ) <> "" then */
  else
  do
                    /* try to create and lock (!) the semaphore file  */
    if stream( semaphorFileName , "c", "OPEN WRITE" ) = "READY:" then
    do
                        /* ok, semaphore set                          */
      thisRC = 1
    end /* if */
    else
    do
                        /* something went wrong ...                   */
        thisRC = -1
    end /* else */
  end /* else */

RETURN thisRC

/* ------------------------------------------------------------------ */
/* Function: Delete a semaphore                                       */
/*                                                                    */
/* call:     DeleteSemaphor semaphorFileName                          */
/*                                                                    */
/* where:    semaphorFileName                                         */
/*              - fully qualified name of the semaphore file          */
/*                                                                    */
/* returns:  nothing                                                  */
/*                                                                    */
DeleteSemaphor: PROCEDURE
  parse arg semaphorFileName .

                        /* close the semaphore file                   */
  call stream semaphorFileName , "c", "CLOSE"

                        /* and delete the semaphore file              */
  "@del " semaphorFileName "2>NUL 1>NUL"
RETURN


[Back: Using REXX queues to simulate a semaphore]
[Next: REXX Wrapper for textmode programs]