home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / pmos2002.zip / SRC / SEMAPHOR.MOD < prev    next >
Text File  |  1997-05-11  |  9KB  |  261 lines

  1. IMPLEMENTATION MODULE Semaphores;
  2.  
  3.         (********************************************************)
  4.         (*                                                      *)
  5.         (*      Implements the Wait and Signal operations on    *)
  6.         (*      semaphores.                                     *)
  7.         (*                                                      *)
  8.         (*      Programmer:     P. Moylan                       *)
  9.         (*      Last edited:    11 May 1997                     *)
  10.         (*      Status:         OK                              *)
  11.         (*                   Still contains debugging code      *)
  12.         (*                                                      *)
  13.         (*      Observation: the kernel overheads in semaphore  *)
  14.         (*      and Lock operations are somewhat higher than    *)
  15.         (*      in the original PMOS, largely due to the        *)
  16.         (*      repeated calculation of the current task ID.    *)
  17.         (*      I should look at ways to improve this.          *)
  18.         (*                                                      *)
  19.         (********************************************************)
  20.  
  21. FROM Storage IMPORT
  22.     (* proc *)  ALLOCATE, DEALLOCATE;
  23.  
  24. FROM FinalExit IMPORT
  25.     (* proc *)  Crash;
  26.  
  27. FROM TaskControl IMPORT
  28.     (* type *)  Lock, TaskID,
  29.     (* proc *)  CreateLock, DestroyLock, Obtain, Release,
  30.                 CurrentTaskID, SuspendMe, ResumeTask;
  31.  
  32. FROM OS2 IMPORT
  33.     (* const *) SEM_INDEFINITE_WAIT;
  34.  
  35. (************************************************************************)
  36.  
  37. TYPE
  38.     BlockedListPointer = POINTER TO
  39.                              RECORD
  40.                                  ThreadID: TaskID;
  41.                                  next: BlockedListPointer;
  42.                              END;
  43.  
  44.     Semaphore = POINTER TO
  45.                     RECORD
  46.                         value: INTEGER;
  47.                         access: Lock;
  48.                         holder: TaskID;
  49.                         BlockedList: RECORD
  50.                                          head, tail: BlockedListPointer;
  51.                                      END (*RECORD*);
  52.                     END (*RECORD*);
  53.  
  54. (************************************************************************)
  55.  
  56. (*
  57. PROCEDURE DumpSemaphoreState (s: Semaphore);
  58.  
  59.     (* Writes information about s to the dump file. *)
  60.  
  61.     VAR p: BlockedListPointer;
  62.  
  63.     BEGIN
  64.         DumpString ("Semaphore value ");
  65.         IF s^.value < 0 THEN
  66.             DumpString ("-");  DumpCard (-s^.value);
  67.         ELSE
  68.             DumpCard (s^.value);
  69.         END (*IF*);
  70.         IF s^.holder <> 0 THEN
  71.             DumpString (", holder ");  DumpCard (s^.holder);
  72.         END (*IF*);
  73.         p := s^.BlockedList.head;
  74.         IF p <> NIL THEN
  75.             DumpString (", blocked list");
  76.             WHILE p <> NIL DO
  77.                 DumpString ("  ");  DumpCard (p^.ThreadID);
  78.                 p := p^.next;
  79.             END (*WHILE*);
  80.         END (*IF*);
  81.         DumpEOL;
  82.     END DumpSemaphoreState;
  83. *)
  84.  
  85. (************************************************************************)
  86.  
  87. PROCEDURE CreateSemaphore (VAR (*OUT*) s: Semaphore;
  88.                                         InitialValue: CARDINAL);
  89.  
  90.     (* Creates semaphore s, with the given initial value and an empty   *)
  91.     (* queue.                                                           *)
  92.  
  93.     BEGIN
  94.         NEW(s);
  95.         WITH s^ DO
  96.             CreateLock (access);
  97.             value := InitialValue;
  98.             IF value > 0 THEN holder := 0 ELSE holder := CurrentTaskID()  END(*IF*);
  99.             WITH BlockedList DO
  100.                 head := NIL;  tail := NIL;
  101.             END (*WITH*);
  102.         END (*WITH*);
  103.     END CreateSemaphore;
  104.  
  105. (************************************************************************)
  106.  
  107. PROCEDURE DestroySemaphore (VAR (*INOUT*) s: Semaphore);
  108.  
  109.     (* Reclaims any space used by semaphore s.  Remark:  It is not at   *)
  110.     (* all obvious what should be done with any tasks which happen to   *)
  111.     (* be blocked on this semaphore (should they be unblocked, or       *)
  112.     (* killed?).  At present we take the easy way out and assume that   *)
  113.     (* there are no pending operations on s at the time that it is      *)
  114.     (* destroyed.                                                       *)
  115.  
  116.     BEGIN
  117.         WITH s^ DO
  118.             DestroyLock (access);
  119.         END (*WITH*);
  120.         DISPOSE (s);
  121.     END DestroySemaphore;
  122.  
  123. (************************************************************************)
  124.  
  125. PROCEDURE Wait (s: Semaphore);
  126.  
  127.     (* Decrements the semaphore value.  If the value goes negative, the *)
  128.     (* calling task is blocked and there is a task switch.              *)
  129.  
  130.     VAR p: BlockedListPointer;  ThreadID: TaskID;
  131.  
  132.     BEGIN
  133.         IF s = NIL THEN Crash ("Wait on nonexistent semaphore"); END(*IF*);
  134.         ThreadID := CurrentTaskID();
  135.         WITH s^ DO
  136.             Obtain (access);
  137.             DEC (value);
  138.             IF value < 0 THEN
  139.                 NEW (p);
  140.                 p^.next := NIL;  p^.ThreadID := ThreadID;
  141.                 WITH BlockedList DO
  142.                     IF tail = NIL THEN
  143.                         head := p;
  144.                     ELSE
  145.                         tail^.next := p;
  146.                     END (*IF*);
  147.                     tail := p;
  148.                 END (*WITH*);
  149.                 Release (access);
  150.                 IF SuspendMe (ThreadID, SEM_INDEFINITE_WAIT) THEN
  151.                     Crash ("Semaphore Wait failure");
  152.                 END (*IF*);
  153.                 Obtain (access);
  154.             END (*IF*);
  155.             holder := ThreadID;
  156.             Release (access);
  157.         END (*WITH*);
  158.     END Wait;
  159.  
  160. (************************************************************************)
  161.  
  162. PROCEDURE TimedWaitT (s: Semaphore;  TimeLimit: INTEGER;
  163.                         VAR (*OUT*) TimedOut: BOOLEAN);
  164.  
  165.     (* Like procedure Wait, except that it returns with TimedOut TRUE   *)
  166.     (* if the corresponding Signal does not occur within TimeLimit      *)
  167.     (* clock ticks.                                                     *)
  168.  
  169.     VAR p: BlockedListPointer;  ThreadID: TaskID;
  170.  
  171.     BEGIN
  172.         IF TimeLimit <= 0 THEN TimeLimit := 1; END(*IF*);
  173.  
  174.         (* Possible OS/2 bug: I'm not sure that the case TimeLimit=0    *)
  175.         (* works correctly; but changing 0 to 1 should have little      *)
  176.         (* impact on most tasks.                                        *)
  177.  
  178.         IF s = NIL THEN Crash ("Wait on nonexistent semaphore"); END(*IF*);
  179.         ThreadID := CurrentTaskID();
  180.         WITH s^ DO
  181.             Obtain (access);
  182.             DEC (value);
  183.             IF value < 0 THEN
  184.                 NEW (p);
  185.                 p^.next := NIL;  p^.ThreadID := ThreadID;
  186.                 WITH BlockedList DO
  187.                     IF tail = NIL THEN
  188.                         head := p;
  189.                     ELSE
  190.                         tail^.next := p;
  191.                     END (*IF*);
  192.                     tail := p;
  193.                 END (*WITH*);
  194.                 Release (access);
  195.                 TimedOut := SuspendMe (ThreadID, TimeLimit);
  196.                 Obtain (access);
  197.                 IF TimedOut THEN
  198.                     INC(value);
  199.                 ELSE
  200.                     holder := ThreadID;
  201.                 END (*IF*);
  202.             ELSE                     (* value >= 0 *)
  203.                 TimedOut := FALSE;
  204.                 holder := ThreadID;
  205.             END (*IF*);
  206.             Release (access);
  207.         END (*WITH*);
  208.     END TimedWaitT;
  209.  
  210. (************************************************************************)
  211.  
  212. PROCEDURE Signal (s: Semaphore);
  213.  
  214.     (* Increments the semaphore value.  Unblocks one task, if there was *)
  215.     (* one waiting on this semaphore.                                   *)
  216.  
  217.     VAR p: BlockedListPointer;  ThreadToUnblock: TaskID;
  218.  
  219.     BEGIN
  220.         IF s = NIL THEN Crash ("Signal on nonexistent semaphore"); END(*IF*);
  221.         WITH s^ DO
  222.             Obtain (access);
  223.             INC (value);
  224.             holder := 0;
  225.             IF value <= 0 THEN
  226.                 WITH BlockedList DO
  227.                     p := head;  head := p^.next;
  228.                     IF head = NIL THEN tail := NIL END(*IF*);
  229.                     ThreadToUnblock := p^.ThreadID;
  230.                     DISPOSE (p);
  231.                 END (*WITH*);
  232.                 Release (access);
  233.  
  234.                 (* The recursion below is to handle the possibility     *)
  235.                 (* that we're trying to resume a task that no longer    *)
  236.                 (* exists.  This is not a common situation, but it      *)
  237.                 (* does occur during program shutdown.                  *)
  238.  
  239.                 IF NOT ResumeTask (ThreadToUnblock) THEN
  240.                     Signal (s);
  241.                 END (*IF*);
  242.             ELSE
  243.                 Release (access);
  244.             END (*IF*);
  245.         END (*WITH*);
  246.     END Signal;
  247.  
  248. (************************************************************************)
  249.  
  250. PROCEDURE SemaphoreHolder (s: Semaphore): TaskID;
  251.  
  252.     (* Returns the Task ID of the current holder of s.  The result is   *)
  253.     (* 0 if there is no current holder.                                 *)
  254.  
  255.     BEGIN
  256.         RETURN s^.holder;
  257.     END SemaphoreHolder;
  258.  
  259. END Semaphores.
  260.  
  261.