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.mmtk.utility.heap;
014
015 import org.mmtk.plan.Plan;
016 import org.mmtk.policy.Space;
017 import org.mmtk.utility.Constants;
018 import org.mmtk.utility.options.ProtectOnRelease;
019 import org.mmtk.utility.options.Options;
020
021 import org.mmtk.vm.Lock;
022 import org.mmtk.vm.VM;
023
024 import org.vmmagic.pragma.*;
025 import org.vmmagic.unboxed.*;
026
027 /**
028 * This class manages the allocation of pages for a space. When a
029 * page is requested by the space both a page budget and the use of
030 * virtual address space are checked. If the request for space can't
031 * be satisfied (for either reason) a GC may be triggered.<p>
032 *
033 * This class is abstract, and is subclassed with monotone and
034 * freelist variants, which reflect monotonic and ad hoc space usage
035 * respectively. Monotonic use is easier to manage, but is obviously
036 * more restrictive (useful for copying collectors which allocate
037 * monotonically before freeing the entire space and starting over).
038 */
039 @Uninterruptible
040 public abstract class PageResource implements Constants {
041
042 /****************************************************************************
043 *
044 * Class variables
045 */
046 protected static final boolean ZERO_ON_RELEASE = false; // debugging
047
048 private static final Lock classLock;
049 private static long cumulativeCommitted = 0;
050
051
052 /****************************************************************************
053 *
054 * Instance variables
055 */
056
057 // page budgeting
058 protected int reserved;
059 protected int committed;
060 protected int required;
061 private final int pageBudget;
062
063 protected final boolean contiguous;
064 protected final Space space;
065 protected Address start; // only for contiguous
066
067 // locking
068 private final Lock gcLock; // used during GC
069 private final Lock mutatorLock; // used by mutators
070
071 /****************************************************************************
072 *
073 * Initialization
074 */
075 static {
076 classLock = VM.newLock("PageResource");
077 Options.protectOnRelease = new ProtectOnRelease();
078 }
079
080 /**
081 * Constructor
082 *
083 * @param pageBudget The budget of pages available to this memory
084 * manager before it must poll the collector.
085 * @param space The space to which this resource is attached
086 */
087 private PageResource(int pageBudget, Space space, boolean contiguous) {
088 this.pageBudget = pageBudget;
089 this.contiguous = contiguous;
090 this.space = space;
091 gcLock = VM.newLock(space.getName() + ".gcLock");
092 mutatorLock = VM.newLock(space.getName() + ".mutatorLock");
093 }
094
095 /**
096 * Constructor for discontiguous spaces
097 *
098 * @param pageBudget The budget of pages available to this memory
099 * manager before it must poll the collector.
100 * @param space The space to which this resource is attached
101 */
102 PageResource(int pageBudget, Space space) {
103 this(pageBudget, space, false);
104 }
105
106 /**
107 * Constructor for contiguous spaces
108 *
109 * @param pageBudget The budget of pages available to this memory
110 * manager before it must poll the collector.
111 * @param space The space to which this resource is attached
112 */
113 PageResource(int pageBudget, Space space, Address start) {
114 this(pageBudget, space, true);
115 this.start = start;
116 }
117
118 /**
119 * Return the number of available physical pages for this resource.
120 *
121 * Note: This just considers physical pages (ie virtual memory pages
122 * allocated for use by this resource). This calculation is orthogonal
123 * to and does not consider any restrictions on the number of pages
124 * this resource may actually use at any time (ie the number of
125 * committed and reserved pages).<p>
126 *
127 * Note: The calculation is made on the assumption that all space that
128 * could be assigned to this resource would be assigned to this resource
129 * (ie the unused discontiguous space could just as likely be assigned
130 * to another competing resource).
131 *
132 * @return The number of available physical pages for this resource.
133 */
134 public abstract int getAvailablePhysicalPages();
135
136 /**
137 * Reserve pages.<p>
138 *
139 * The role of reserving pages is that it allows the request to be
140 * noted as pending (the difference between committed and reserved
141 * indicates pending requests). If the request would exceed the
142 * page budget then the caller must poll in case a GC is necessary.
143 *
144 * @param pages The number of pages requested
145 * @return True if the page budget could satisfy the request.
146 */
147 @Inline
148 public final boolean reservePages(int pages) {
149 lock();
150 required += adjustForMetaData(pages);
151 reserved = committed + required;
152 boolean satisfied = reserved <= pageBudget;
153 unlock();
154 return satisfied;
155 }
156
157 /**
158 * Remove a request to the space.
159 *
160 * @param pages The number of pages in the request.
161 */
162 @Inline
163 public final void clearRequest(int pages) {
164 lock();
165 required -= adjustForMetaData(pages);
166 unlock();
167 }
168
169 /**
170 * Reserve pages unconditionally.<p>
171 *
172 * An example of where this is useful is in cases where it is
173 * desirable to put some space aside as head-room. By
174 * unconditionally reserving the pages, the pages are counted
175 * against the collectors budget. When the space is actually
176 * needed, the pages can be unconditionally released, freeing
177 * the pages for other purposes.
178 *
179 * @param pages The number of pages to be unconditionally
180 * reserved.
181 */
182 public final void unconditionallyReservePages(int pages) {
183 lock();
184 committed += pages;
185 reserved += pages;
186 unlock();
187 }
188
189 /**
190 * Release pages unconditionally.<p>
191 *
192 * This call allows pages to be unconditionally removed from
193 * the collectors page budget.
194 *
195 * @see #unconditionallyReservePages
196 * @param pages The number of pages to be unconditionally
197 * released.
198 */
199 public final void unconditionallyReleasePages(int pages) {
200 lock();
201 committed -= pages;
202 reserved -= pages;
203 unlock();
204 }
205
206 abstract Address allocPages(int pages);
207
208 /**
209 * Adjust a page request to include metadata requirements for a request
210 * of the given size. This must be a pure function, that is it does not
211 * depend on the state of the PageResource.
212 *
213 * @param pages The size of the pending allocation in pages
214 * @return The number of required pages, inclusive of any metadata
215 */
216 public abstract int adjustForMetaData(int pages);
217
218 /**
219 * Allocate pages in virtual memory, returning zero on failure.<p>
220 *
221 * If the request cannot be satisfied, zero is returned and it
222 * falls to the caller to trigger the GC.
223 *
224 * Call <code>allocPages</code> (subclass) to find the pages in
225 * virtual memory. If successful then commit the pending page
226 * request and return the address of the first page.
227 *
228 * @param pages The number of pages requested
229 * @return The address of the first of <code>pages</code> pages, or
230 * zero on failure.
231 */
232 @Inline
233 public final Address getNewPages(int pages) {
234 return allocPages(pages);
235 }
236
237 /**
238 * Commit pages to the page budget. This is called after
239 * successfully determining that the request can be satisfied by
240 * both the page budget and virtual memory. This simply accounts
241 * for the descrepency between <code>committed</code> and
242 * <code>reserved</code> while the request was pending.
243 *
244 * This *MUST* be called by each PageResource during the
245 * allocPages, and the caller must hold the lock.
246 *
247 * @param requestedPages The number of pages from this request
248 * @param totalPages The number of pages
249 */
250 protected void commitPages(int requestedPages, int totalPages) {
251 int predictedPages = adjustForMetaData(requestedPages);
252 int delta = totalPages - predictedPages;
253 required -= predictedPages;
254 reserved += delta;
255 committed += totalPages;
256 if (!Plan.gcInProgress())
257 addToCommitted(totalPages); // only count mutator pages
258 }
259
260 /**
261 * Return the number of reserved pages
262 *
263 * @return The number of reserved pages.
264 */
265 public final int reservedPages() { return reserved; }
266
267 /**
268 * Return the number of committed pages
269 *
270 * @return The number of committed pages.
271 */
272 public final int committedPages() { return committed; }
273
274 /**
275 * Return the number of required pages
276 *
277 * @return The number of required pages.
278 */
279 public final int requiredPages() { return required; }
280
281 /**
282 * Return the cumulative number of committed pages
283 *
284 * @return The cumulative number of committed pages.
285 */
286 public static long cumulativeCommittedPages() { return cumulativeCommitted; }
287
288 /**
289 * Add to the total cumulative committed page count.
290 *
291 * @param pages The number of pages to be added.
292 */
293 private static void addToCommitted(int pages) {
294 classLock.acquire();
295 cumulativeCommitted += pages;
296 classLock.release();
297 }
298
299 /**
300 * Acquire the appropriate lock depending on whether the context is
301 * GC or mutator.
302 */
303 protected final void lock() {
304 if (Plan.gcInProgress())
305 gcLock.acquire();
306 else
307 mutatorLock.acquire();
308 }
309
310 /**
311 * Release the appropriate lock depending on whether the context is
312 * GC or mutator.
313 */
314 protected final void unlock() {
315 if (Plan.gcInProgress())
316 gcLock.release();
317 else
318 mutatorLock.release();
319 }
320 }