comparison src/main/gov/nasa/jpf/vm/FinalizerThreadInfo.java @ 0:61d41facf527

initial v8 import (history reset)
author Peter Mehlitz <Peter.C.Mehlitz@nasa.gov>
date Fri, 23 Jan 2015 10:14:01 -0800
parents
children
comparison
equal deleted inserted replaced
-1:000000000000 0:61d41facf527
1 /*
2 * Copyright (C) 2014, United States Government, as represented by the
3 * Administrator of the National Aeronautics and Space Administration.
4 * All rights reserved.
5 *
6 * The Java Pathfinder core (jpf-core) platform is licensed under the
7 * Apache License, Version 2.0 (the "License"); you may not use this file except
8 * in compliance with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0.
11 *
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
17 */
18 package gov.nasa.jpf.vm;
19
20 import gov.nasa.jpf.vm.choice.BreakGenerator;
21 import java.util.ArrayList;
22 import java.util.List;
23
24 /**
25 * @author Nastaran Shafiei <nastaran.shafiei@gmail.com>
26 *
27 * This class represents the finalizer thread in VM which is responsible for
28 * executing finalize() methods upon garbage collection of finalizable objects.
29 * By a finalizable object, we mean an object, the class of which overrides the
30 * Object.finalize() method. By default, we do not allow for processing finalizers,
31 * to enforce that one needs to set the property "vm.process_finalizers" to true.
32 *
33 * If "vm.process_finalizers" is set to true, during vm initialization we create
34 * a FinalizerThreadInfo object per process. ApplicationContext keeps a reference
35 * to FinalizerThreadInfo of the process. This thread is alive during the entire
36 * process execution. The finalizer thread is "always" waiting on an internal
37 * private lock. The JPF Thread object corresponding to the FinalizerThreadInfo
38 * is encapsulated by the model class gov.nasa.jpf.FinalizerThread. The thread
39 * encapsulated by FinalizerThread has a queue of objects called "finalizeQueue"
40 * which is kept at the SUT level. This queue is initially empty, and it is
41 * populated during the sweep() phase of the garbage collection. During sweep(),
42 * before removing unmark objects from the heap, any unmark finalizable object is
43 * marked and added to finalizeQueue.
44 *
45 * In VM.forward(), after each garbage collection, VM checks if finalizeQueue of
46 * the current process finalizer thread is not empty. If so, VM schedules the
47 * finalizer thread to execute next, i.e. finalizer thread stops waiting and its
48 * state becomes runnable. To accomplish that, VM replaces the next choiceGenerator
49 * with a new choice generator from which only finalizer thread can proceed.
50 *
51 * After finalizer thread processes the finalize() methods of all objects in
52 * finalizeQueue, the queue becomes empty and the thread waits on its internal lock
53 * again. After the process terminates, we still keep the finalizer thread to be
54 * processed after the last garbage collection involving the process. The runnable
55 * finalizer thread terminates itself when it has processed its finalizeQueue and
56 * there is no other alive thread in the process.
57 */
58 public class FinalizerThreadInfo extends ThreadInfo {
59
60 static final String FINALIZER_NAME = "finalizer";
61
62 ChoiceGenerator<?> replacedCG;
63
64 protected FinalizerThreadInfo (VM vm, ApplicationContext appCtx, int id) {
65 super(vm, id, appCtx);
66
67 ci = appCtx.getSystemClassLoader().getResolvedClassInfo("gov.nasa.jpf.FinalizerThread");
68 threadData.name = FINALIZER_NAME;
69
70 tempFinalizeQueue = new ArrayList<ElementInfo>();
71 }
72
73 protected void createFinalizerThreadObject (SystemClassLoaderInfo sysCl){
74 Heap heap = getHeap();
75
76 ElementInfo eiThread = heap.newObject( ci, this);
77 objRef = eiThread.getObjectRef();
78
79 ElementInfo eiName = heap.newString(FINALIZER_NAME, this);
80 int nameRef = eiName.getObjectRef();
81 eiThread.setReferenceField("name", nameRef);
82
83 // Since we create FinalizerThread upon VM initialization, they are assigned to the
84 // same group as the main thread
85 int grpRef = ThreadInfo.getCurrentThread().getThreadGroupRef();
86 eiThread.setReferenceField("group", grpRef);
87
88 eiThread.setIntField("priority", Thread.MAX_PRIORITY-2);
89
90 ClassInfo ciPermit = sysCl.getResolvedClassInfo("java.lang.Thread$Permit");
91 ElementInfo eiPermit = heap.newObject( ciPermit, this);
92 eiPermit.setBooleanField("blockPark", true);
93 eiThread.setReferenceField("permit", eiPermit.getObjectRef());
94
95 addToThreadGroup(getElementInfo(grpRef));
96
97 addId( objRef, id);
98
99 threadData.name = FINALIZER_NAME;
100
101 // start the thread by pushing Thread.run()
102 startFinalizerThread();
103
104 eiThread.setBooleanField("done", false);
105 ElementInfo finalizeQueue = getHeap().newArray("Ljava/lang/Object;", 0, this);
106 eiThread.setReferenceField("finalizeQueue", finalizeQueue.getObjectRef());
107
108 // create an internal private lock used for lock-free wait
109 ElementInfo lock = getHeap().newObject(appCtx.getSystemClassLoader().objectClassInfo, this);
110 eiThread.setReferenceField("semaphore", lock.getObjectRef());
111
112 // make it wait on the internal private lock until its finalizeQueue is populated. This way,
113 // we avoid scheduling points from including FinalizerThreads
114 waitOnSemaphore();
115
116 assert this.isWaiting();
117 }
118
119 /**
120 * Pushes a frame corresponding to Thread.run() into the finalizer thread stack to
121 * start the thread.
122 */
123 protected void startFinalizerThread() {
124 MethodInfo mi = ci.getMethod("run()V", false);
125 DirectCallStackFrame frame = mi.createDirectCallStackFrame(this, 0);
126 frame.setReferenceArgument(0, objRef, frame);
127 pushFrame(frame);
128 }
129
130 public boolean hasQueuedFinalizers() {
131 ElementInfo queue = getFinalizeQueue();
132 return (queue!=null && queue.asReferenceArray().length>0);
133 }
134
135 public ElementInfo getFinalizeQueue() {
136 ElementInfo ei = vm.getModifiableElementInfo(objRef);
137 ElementInfo queue = null;
138
139 if(ei!=null) {
140 int queueRef = ei.getReferenceField("finalizeQueue");
141 queue = vm.getModifiableElementInfo(queueRef);
142 return queue;
143 }
144
145 return queue;
146 }
147
148 // all finalizable objects collected during garbage collection are temporarily added to this list
149 // when VM schedule the finalizer thread, it add all elements to FinalizerThread.finalizeQueue at
150 // the SUT level.
151 List<ElementInfo> tempFinalizeQueue;
152
153 /**
154 * This method is invoked by the sweep() phase of the garbage collection process (GenericHeap.sweep()).
155 * It adds a given finalizable object to the finalizeQueue array of gov.nasa.jpf.FinalizerThread.
156 *
157 * NOTE: this might return a new ElementInfo since we have to modify it (setting the finalized flag)
158 */
159 public ElementInfo getFinalizerQueuedInstance(ElementInfo ei) {
160 ei = ei.getModifiableInstance();
161
162 // make sure we process this object finalizer only once
163 ei.setFinalized();
164
165 tempFinalizeQueue.add(ei);
166
167 return ei;
168 }
169
170 /**
171 * This method adds all finalizable objects observed during the last garbage collection
172 * to finalizeQueue of FinalizerThread corresponding to this thread
173 */
174 void processNewFinalizables() {
175 if(!tempFinalizeQueue.isEmpty()) {
176
177 ElementInfo oldQueue = getFinalizeQueue();
178 int[] oldValues = oldQueue.asReferenceArray();
179 int len = oldValues.length;
180
181 int n = tempFinalizeQueue.size();
182
183 ElementInfo newQueue = getHeap().newArray("Ljava/lang/Object;", len+n, this);
184 int[] newValues = newQueue.asReferenceArray();
185
186 System.arraycopy(oldValues, 0, newValues, 0, len);
187
188 for(ElementInfo ei: tempFinalizeQueue) {
189 newValues[len++] = ei.getObjectRef();
190 }
191
192 vm.getModifiableElementInfo(objRef).setReferenceField("finalizeQueue", newQueue.getObjectRef());
193 tempFinalizeQueue.clear();
194
195 assert hasQueuedFinalizers();
196 }
197 }
198
199 public boolean scheduleFinalizer() {
200 if(hasQueuedFinalizers() && !isRunnable()) {
201 SystemState ss = vm.getSystemState();
202 replacedCG = ss.getNextChoiceGenerator();
203
204 // NOTE - before we get here we have already made sure that nextCg is not Cascaded.
205 // we have to set nextCg to null before setting the nextCG, otherwise, the new CG is
206 // mistakenly considered as "Cascaded"
207 ss.nextCg = null;
208
209 // this doesn't have any choice (we need to run the finalizer), and since we don't have
210 // anything to re-execute (this is called from VM.forward()), we need to be in control of
211 // type and registration of the CG, hence this doesn't go through the Scheduler/SyncPolicy
212 ss.setNextChoiceGenerator(new BreakGenerator("finalize", this, false));
213 checkNextChoiceGeneratorSet("no transition break prior to finalize");
214
215 // stop waiting and process finalizers
216 notifyOnSemaphore();
217 assert this.isRunnable();
218
219 return true;
220 }
221
222 return false;
223 }
224
225 protected void waitOnSemaphore() {
226 int lockRef = vm.getElementInfo(objRef).getReferenceField("semaphore");
227 ElementInfo lock = vm.getModifiableElementInfo(lockRef);
228
229 lock.wait(this, 0, false);
230 }
231
232 protected void notifyOnSemaphore() {
233 int lockRef = vm.getElementInfo(objRef).getReferenceField("semaphore");
234 ElementInfo lock = vm.getModifiableElementInfo(lockRef);
235
236 lock.notifies(vm.getSystemState(), this, false);
237 }
238
239 // It returns true if the finalizer thread is waiting and do not have any object to
240 // process
241 protected boolean isIdle() {
242 if(this.isWaiting()) {
243 if(this.lockRef == vm.getElementInfo(objRef).getReferenceField("semaphore")) {
244 return true;
245 }
246 }
247 return false;
248 }
249
250 @Override
251 public boolean isSystemThread() {
252 return true;
253 }
254 }