/* 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