Mercurial > hg > Members > kono > jpf-core
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 } |