001    /*
002     *  This file is part of the Jikes RVM project (http://jikesrvm.org).
003     *
004     *  This file is licensed to You under the Eclipse Public License (EPL);
005     *  You may not use this file except in compliance with the License. You
006     *  may obtain a copy of the License at
007     *
008     *      http://www.opensource.org/licenses/eclipse-1.0.php
009     *
010     *  See the COPYRIGHT.txt file distributed with this work for information
011     *  regarding copyright ownership.
012     */
013    package org.jikesrvm.scheduler;
014    
015    import org.jikesrvm.VM;
016    import org.vmmagic.pragma.NonMoving;
017    import org.vmmagic.pragma.Uninterruptible;
018    import org.vmmagic.pragma.Untraced;
019    import org.jikesrvm.runtime.Magic;
020    
021    /**
022     * An unsynchronized queue data structure for Threads. The current uses are all
023     * where there is some other lock that already protects the queue.
024     */
025    @Uninterruptible
026    @NonMoving
027    public class ThreadQueue {
028      protected static final boolean trace = false;
029    
030      @Untraced RVMThread head;
031    
032      @Untraced RVMThread tail;
033    
034      public ThreadQueue() {
035      }
036    
037      public boolean isEmpty() {
038        return head == null;
039      }
040    
041      public void enqueue(RVMThread t) {
042        if (trace) {
043          VM.sysWriteln("enqueueing ", t.getThreadSlot(), " onto ",
044              Magic.objectAsAddress(this));
045        }
046        if (VM.VerifyAssertions)
047          VM._assert(t.queuedOn == null);
048        t.next = null;
049        if (tail == null) {
050          head = t;
051        } else {
052          tail.next = t;
053        }
054        tail = t;
055        t.queuedOn = this;
056      }
057    
058      public RVMThread peek() {
059        return head;
060      }
061    
062      public RVMThread dequeue() {
063        RVMThread result = head;
064        if (result != null) {
065          head = result.next;
066          if (head == null) {
067            tail = null;
068          }
069          if (VM.VerifyAssertions)
070            VM._assert(result.queuedOn == this);
071          result.next = null;
072          result.queuedOn = null;
073        }
074        if (trace) {
075          if (result == null) {
076            VM.sysWriteln("dequeueing null from ", Magic.objectAsAddress(this));
077          } else {
078            VM.sysWriteln("dequeueing ", result.getThreadSlot(), " from ",
079                Magic.objectAsAddress(this));
080          }
081        }
082        return result;
083      }
084    
085      /**
086       * Private helper. Gets the next pointer of cur unless cur is {@code null}, in which
087       * case it returns head.
088       */
089      private RVMThread getNext(RVMThread cur) {
090        if (cur == null) {
091          return head;
092        } else {
093          return cur.next;
094        }
095      }
096    
097      /**
098       * Private helper. Sets the next pointer of cur to value unless cur is {@code null},
099       * in which case it sets head. Also sets tail as appropriate.
100       */
101      private void setNext(RVMThread cur, RVMThread value) {
102        if (cur == null) {
103          if (tail == head) {
104            tail = value;
105          }
106          head = value;
107        } else {
108          if (cur == tail) {
109            tail = value;
110          }
111          cur.next = value;
112        }
113      }
114    
115      /**
116       * Remove the given thread from the queue if the thread is still on the queue.
117       * Does nothing (and returns in O(1)) if the thread is not on the queue. Also
118       * does nothing (and returns in O(1)) if the thread is on a different queue.
119       */
120      public boolean remove(RVMThread t) {
121        if (t.queuedOn != this)
122          return false;
123        if (trace) {
124          VM.sysWriteln("removing ", t.getThreadSlot(), " from ",
125              Magic.objectAsAddress(this));
126        }
127        for (RVMThread cur = null; cur != tail; cur = getNext(cur)) {
128          if (getNext(cur) == t) {
129            if (trace) {
130              VM.sysWriteln("found!  before:");
131              dump();
132            }
133            setNext(cur, t.next);
134            if (tail == t) {
135              tail = cur;
136            }
137            if (trace) {
138              VM.sysWriteln("after:");
139              dump();
140            }
141            t.next = null;
142            t.queuedOn = null;
143            return true;
144          }
145        }
146        VM.sysWriteln("Could not remove Thread #", t.getThreadSlot(),
147            " from queue!");
148        dump();
149        if (VM.VerifyAssertions) VM._assert(VM.NOT_REACHED);
150        return false; // make javac happy
151      }
152    
153      public boolean isQueued(RVMThread t) {
154        return t.queuedOn == this;
155      }
156    
157      public void dump() {
158        boolean pastFirst = false;
159        for (RVMThread t = head; t != null; t = t.next) {
160          if (pastFirst) {
161            VM.sysWrite(" ");
162          }
163          t.dump();
164          pastFirst = true;
165        }
166        VM.sysWrite("\n");
167        if (head != null) {
168          VM.sysWriteln("head: ", head.getThreadSlot());
169        } else {
170          VM.sysWriteln("head: null");
171        }
172        if (tail != null) {
173          VM.sysWriteln("tail: ", tail.getThreadSlot());
174        } else {
175          VM.sysWriteln("tail: null");
176        }
177      }
178    }