001    /*
002     * cs101 Graphical Counting Semaphore utility
003     * $Id: GCS.java,v 1.1.1.1 2002/06/05 21:56:32 root Exp $
004     *
005     * Developed for "Rethinking CS101", a project of Lynn Andrea Stein's AP Group.
006     * For more information, see <a href="http://www.ai.mit.edu/projects/cs101/">the
007     * CS101 homepage</a> or email <las@ai.mit.edu>.
008     *
009     * Copyright (C) 1996 Massachusetts Institute of Technology.
010     * Please do not redistribute without obtaining permission.
011     */
012    
013    package cs101.util.semaphore;
014    
015    import java.awt.*;
016    import cs101.awt.ColorField;
017    
018    /**
019     * cs101.util.GCS implements a counting semaphore of arbitrary size
020     * in java. <br>
021     * Interface is gcs.request(), gcs.release(). <br>
022     * It also provides a graphical display of the semaphores status.
023     * <p>
024     * The general design of this utility was influenced by the 
025     * design of the cs101.util.BS (wrote by Lynn Stein).
026     * <br>
027     * Copyright 1996 Massachusetts Institute of Technology
028     *
029     * @author  Todd C. Parnell, tparnell@ai.mit.edu
030     * @author  Joshua R. Brown, reuben@ai.mit.edu 
031     * @version $Id: GCS.java,v 1.1.1.1 2002/06/05 21:56:32 root Exp $
032     *
033     */
034    public class GCS extends GraphicalSemaphore {
035      /** the length of the semaphore */
036      private int size;   
037      /** how much of the semaphore is in use */
038      private int busy;       // i <= busy are busy 
039                              // ( ie if busy=size-1 then all busy )
040      private ColorField[] fields;  
041     
042      //  GCS( int, int, String )
043      /**
044       * Constructs a counting semaphore with the size and initial value 
045       * passed in.  
046       * Uses the String past in to identfy the semaphore in the display.
047       *
048       * @param size     The length of the semaphore (Probably the length 
049       *                 of the buffer that it is associated with).
050       * @param busy     The number of intially busy blocks in the semaphore
051       *                 (ie all busy = size, all free = 0).
052       * @param label    An identfying string of text for the semaphore.
053       */
054      public GCS (int size, int busy, String label) {
055        super(label);
056        this.size = size;
057        this.busy = busy-1;  // adjust for ease of use
058    
059        // make sure busy < size
060        if (this.busy >= this.size) 
061          this.busy = this.size-1;
062    
063        // make sure busy >= -1
064        if (this.busy < -1)
065          this.busy = -1;
066    
067        // now that everything is initialized setup the GUI
068        this.setupGUI();
069    
070      }
071    
072      /**
073       * Does all of the graphical setup on this level
074       * then calls the superclasses method to finish the setup.
075       *
076       * This method is primarly responsible for setting up the 
077       * display Panel.
078       */
079      protected void setupGUI() {
080    
081        // do setup on this level
082        this.fields = new ColorField[this.size];
083      
084        display = new Panel();
085        GridBagLayout layout = new GridBagLayout();
086        display.setLayout(layout);
087      
088        GridBagConstraints con = new GridBagConstraints();
089        con.gridwidth = 1; con.gridheight=1;
090        con.fill = GridBagConstraints.VERTICAL;
091        con.weightx = 0; con.weighty = 1/this.size;
092    
093        for (int i = 0; i < this.size; i++) {
094          if (i <= this.busy)
095            this.fields[i] = new ColorField(true, new Dimension(25,10),
096                                         Color.red, Color.green);
097          else 
098            this.fields[i] = new ColorField(false, new Dimension(25,10),
099                                         Color.red, Color.green);
100          con.gridx = 0; con.gridy = i;
101          layout.setConstraints(this.fields[i], con);
102          display.add(this.fields[i]);
103    
104        }
105        
106        // now that GUI setup on this level is finished
107        // call super-class method
108        super.setupGUI();
109    
110      }
111    
112      /**
113       * Requests the semaphore.  If all of the locks in the semaphore are
114       * currently busy, causes the requesting process to wait() until
115       * the semaphore is release()d.
116       * Unlike java.lang.Object.wait(), the requesting process is not
117       * suspended if the semaphore is currently free.
118       *
119       * @see #release
120       * @see java.lang.Object#wait
121       */
122      synchronized public void request() {
123        while (this.busy == this.size-1) {
124          try {this.wait();} catch (InterruptedException e) {}
125        }
126        this.busy++;
127        this.showStatus();
128      }
129    
130      /**
131       * Releases a lock of the semaphore (if any are currently busy).
132       * Any objects currently wait()ing on the
133       * semaphore are notify()d (and one of them will be granted the
134       * semaphore).  Unlike java.lang.Object.notify(), the semaphore is
135       * also freed so that if there are no wait()ing objects, the next
136       * object to request() the semaphore will receive it.
137       *
138       * @see #request
139       * @see java.lang.Object#notifyAll()
140       */
141      synchronized public void release () {
142        if (this.busy >= 0) {
143          this.busy--;
144          this.notifyAll();
145          this.showStatus();
146        }
147      }
148    
149      /**
150       * Prints out the current state of the semaphore.
151       * Changes the graphical display.
152       */
153      protected void showStatus() {      
154        // tab over an approprate amount
155        for (int i = 0; i<this.myNumber; i++) 
156          System.out.print("               ");
157        
158        // now print the status 
159        System.out.print(this.label.getText()+": ");
160        System.out.println(this.busy+1);
161    
162        // update the status fields
163        for (int i = 0; i < this.size; i++) {
164          if (i <= this.busy)
165            this.fields[i] .changeState(true);
166          else 
167            this.fields[i].changeState(false);
168        }
169    
170      }
171    
172    }
173    
174    /* Comments:
175     *
176     * History:
177     *     $Log: GCS.java,v $
178     *     Revision 1.1.1.1  2002/06/05 21:56:32  root
179     *     CS101 comes to Olin finally.
180     *
181     *     Revision 1.1  2000/04/24 22:17:22  nathanw
182     *     Bulk reorganization
183     *
184     *     Revision 1.4  1998/07/24 17:19:27  tparnell
185     *     Placate new javadoc behavior
186     *
187     *     Revision 1.3  1998/07/22 18:18:56  tparnell
188     *     migration from cs101.util to cs101.*
189     *
190     *     Revision 1.2  1998/06/03 19:43:36  tparnell
191     *     update from Java 1.0 to 1.1
192     *
193     *     Revision 1.1  1998/03/13 22:18:13  tparnell
194     *     Import from server crash.  I think the src and class files match up.
195     *
196     *     Revision 1.4  1996/08/01 18:26:24  reuben
197     *     More javadoc tweaking (hopefully the final pass)
198     *
199     *     Revision 1.3  1996/07/25 18:27:42  reuben
200     *     Added all kinds of comments.
201     *     Compiled and tested.
202     *
203     */