Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/openjdk-multiarch-jdk8u
Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/share/classes/sun/rmi/transport/Target.java
38831 views
1
/*
2
* Copyright (c) 1996, 2017, Oracle and/or its affiliates. All rights reserved.
3
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4
*
5
* This code is free software; you can redistribute it and/or modify it
6
* under the terms of the GNU General Public License version 2 only, as
7
* published by the Free Software Foundation. Oracle designates this
8
* particular file as subject to the "Classpath" exception as provided
9
* by Oracle in the LICENSE file that accompanied this code.
10
*
11
* This code is distributed in the hope that it will be useful, but WITHOUT
12
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14
* version 2 for more details (a copy is included in the LICENSE file that
15
* accompanied this code).
16
*
17
* You should have received a copy of the GNU General Public License version
18
* 2 along with this work; if not, write to the Free Software Foundation,
19
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20
*
21
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22
* or visit www.oracle.com if you need additional information or have any
23
* questions.
24
*/
25
package sun.rmi.transport;
26
27
import java.rmi.Remote;
28
import java.rmi.NoSuchObjectException;
29
import java.rmi.dgc.VMID;
30
import java.rmi.server.ObjID;
31
import java.rmi.server.Unreferenced;
32
import java.security.AccessControlContext;
33
import java.security.AccessController;
34
import java.security.PrivilegedAction;
35
import java.util.*;
36
import sun.rmi.runtime.Log;
37
import sun.rmi.runtime.NewThreadAction;
38
import sun.rmi.server.Dispatcher;
39
40
/**
41
* A target contains information pertaining to a remote object that
42
* resides in this address space. Targets are located via the
43
* ObjectTable.
44
*/
45
public final class Target {
46
/** object id for target */
47
private final ObjID id;
48
/** flag indicating whether target is subject to collection */
49
private final boolean permanent;
50
/** weak reference to remote object implementation */
51
private final WeakRef weakImpl;
52
/** dispatcher for remote object */
53
private volatile Dispatcher disp;
54
/** stub for remote object */
55
private final Remote stub;
56
/** set of clients that hold references to this target */
57
private final Vector<VMID> refSet = new Vector<>();
58
/** table that maps client endpoints to sequence numbers */
59
private final Hashtable<VMID, SequenceEntry> sequenceTable =
60
new Hashtable<>(5);
61
/** access control context in which target was created */
62
private final AccessControlContext acc;
63
/** context class loader in which target was created */
64
private final ClassLoader ccl;
65
/** number of pending/executing calls */
66
private int callCount = 0;
67
/** true if this target has been removed from the object table */
68
private boolean removed = false;
69
/**
70
* the transport through which this target was exported and
71
* through which remote calls will be allowed
72
*/
73
private volatile Transport exportedTransport = null;
74
75
/** number to identify next callback thread created here */
76
private static int nextThreadNum = 0;
77
78
/**
79
* Construct a Target for a remote object "impl" with
80
* a specific object id.
81
*
82
* If "permanent" is true, then the impl is pinned permanently
83
* (the impl will not be collected via distributed and/or local
84
* GC). If "on" is false, than the impl is subject to
85
* collection. Permanent objects do not keep a server from
86
* exiting.
87
*/
88
public Target(Remote impl, Dispatcher disp, Remote stub, ObjID id,
89
boolean permanent)
90
{
91
this.weakImpl = new WeakRef(impl, ObjectTable.reapQueue);
92
this.disp = disp;
93
this.stub = stub;
94
this.id = id;
95
this.acc = AccessController.getContext();
96
97
/*
98
* Fix for 4149366: so that downloaded parameter types unmarshalled
99
* for this impl will be compatible with types known only to the
100
* impl class's class loader (when it's not identical to the
101
* exporting thread's context class loader), mark the impl's class
102
* loader as the loader to use as the context class loader in the
103
* server's dispatch thread while a call to this impl is being
104
* processed (unless this exporting thread's context class loader is
105
* a child of the impl's class loader, such as when a registry is
106
* exported by an application, in which case this thread's context
107
* class loader is preferred).
108
*/
109
ClassLoader threadContextLoader =
110
Thread.currentThread().getContextClassLoader();
111
ClassLoader serverLoader = impl.getClass().getClassLoader();
112
if (checkLoaderAncestry(threadContextLoader, serverLoader)) {
113
this.ccl = threadContextLoader;
114
} else {
115
this.ccl = serverLoader;
116
}
117
118
this.permanent = permanent;
119
if (permanent) {
120
pinImpl();
121
}
122
}
123
124
/**
125
* Return true if the first class loader is a child of (or identical
126
* to) the second class loader. Either loader may be "null", which is
127
* considered to be the parent of any non-null class loader.
128
*
129
* (utility method added for the 1.2beta4 fix for 4149366)
130
*/
131
private static boolean checkLoaderAncestry(ClassLoader child,
132
ClassLoader ancestor)
133
{
134
if (ancestor == null) {
135
return true;
136
} else if (child == null) {
137
return false;
138
} else {
139
for (ClassLoader parent = child;
140
parent != null;
141
parent = parent.getParent())
142
{
143
if (parent == ancestor) {
144
return true;
145
}
146
}
147
return false;
148
}
149
}
150
151
/** Get the stub (proxy) object for this target
152
*/
153
public Remote getStub() {
154
return stub;
155
}
156
157
/**
158
* Returns the object endpoint for the target.
159
*/
160
ObjectEndpoint getObjectEndpoint() {
161
return new ObjectEndpoint(id, exportedTransport);
162
}
163
164
/**
165
* Get the weak reference for the Impl of this target.
166
*/
167
WeakRef getWeakImpl() {
168
return weakImpl;
169
}
170
171
/**
172
* Returns the dispatcher for this remote object target.
173
*/
174
Dispatcher getDispatcher() {
175
return disp;
176
}
177
178
AccessControlContext getAccessControlContext() {
179
return acc;
180
}
181
182
ClassLoader getContextClassLoader() {
183
return ccl;
184
}
185
186
/**
187
* Get the impl for this target.
188
* Note: this may return null if the impl has been garbage collected.
189
* (currently, there is no need to make this method public)
190
*/
191
Remote getImpl() {
192
return (Remote)weakImpl.get();
193
}
194
195
/**
196
* Returns true if the target is permanent.
197
*/
198
boolean isPermanent() {
199
return permanent;
200
}
201
202
/**
203
* Pin impl in target. Pin the WeakRef object so it holds a strong
204
* reference to the object to it will not be garbage collected locally.
205
* This way there is a single object responsible for the weak ref
206
* mechanism.
207
*/
208
synchronized void pinImpl() {
209
weakImpl.pin();
210
}
211
212
/**
213
* Unpin impl in target. Weaken the reference to impl so that it
214
* can be garbage collected locally. But only if there the refSet
215
* is empty. All of the weak/strong handling is in WeakRef
216
*/
217
synchronized void unpinImpl() {
218
/* only unpin if:
219
* a) impl is not permanent, and
220
* b) impl is not already unpinned, and
221
* c) there are no external references (outside this
222
* address space) for the impl
223
*/
224
if (!permanent && refSet.isEmpty()) {
225
weakImpl.unpin();
226
}
227
}
228
229
/**
230
* Enable the transport through which remote calls to this target
231
* are allowed to be set if it has not already been set.
232
*/
233
void setExportedTransport(Transport exportedTransport) {
234
if (this.exportedTransport == null) {
235
this.exportedTransport = exportedTransport;
236
}
237
}
238
239
/**
240
* Add an endpoint to the remembered set. Also adds a notifier
241
* to call back if the address space associated with the endpoint
242
* dies.
243
*/
244
synchronized void referenced(long sequenceNum, VMID vmid) {
245
// check sequence number for vmid
246
SequenceEntry entry = sequenceTable.get(vmid);
247
if (entry == null) {
248
sequenceTable.put(vmid, new SequenceEntry(sequenceNum));
249
} else if (entry.sequenceNum < sequenceNum) {
250
entry.update(sequenceNum);
251
} else {
252
// late dirty call; ignore.
253
return;
254
}
255
256
if (!refSet.contains(vmid)) {
257
/*
258
* A Target must be pinned while its refSet is not empty. It may
259
* have become unpinned if external LiveRefs only existed in
260
* serialized form for some period of time, or if a client failed
261
* to renew its lease due to a transient network failure. So,
262
* make sure that it is pinned here; this fixes bugid 4069644.
263
*/
264
pinImpl();
265
if (getImpl() == null) // too late if impl was collected
266
return;
267
268
if (DGCImpl.dgcLog.isLoggable(Log.VERBOSE)) {
269
DGCImpl.dgcLog.log(Log.VERBOSE, "add to dirty set: " + vmid);
270
}
271
272
refSet.addElement(vmid);
273
274
DGCImpl.getDGCImpl().registerTarget(vmid, this);
275
}
276
}
277
278
/**
279
* Remove endpoint from remembered set. If set becomes empty,
280
* remove server from Transport's object table.
281
*/
282
synchronized void unreferenced(long sequenceNum, VMID vmid, boolean strong)
283
{
284
// check sequence number for vmid
285
SequenceEntry entry = sequenceTable.get(vmid);
286
if (entry == null || entry.sequenceNum > sequenceNum) {
287
// late clean call; ignore
288
return;
289
} else if (strong) {
290
// strong clean call; retain sequenceNum
291
entry.retain(sequenceNum);
292
} else if (entry.keep == false) {
293
// get rid of sequence number
294
sequenceTable.remove(vmid);
295
}
296
297
if (DGCImpl.dgcLog.isLoggable(Log.VERBOSE)) {
298
DGCImpl.dgcLog.log(Log.VERBOSE, "remove from dirty set: " + vmid);
299
}
300
301
refSetRemove(vmid);
302
}
303
304
/**
305
* Remove endpoint from the reference set.
306
*/
307
synchronized private void refSetRemove(VMID vmid) {
308
// remove notification request
309
DGCImpl.getDGCImpl().unregisterTarget(vmid, this);
310
311
if (refSet.removeElement(vmid) && refSet.isEmpty()) {
312
// reference set is empty, so server can be garbage collected.
313
// remove object from table.
314
if (DGCImpl.dgcLog.isLoggable(Log.VERBOSE)) {
315
DGCImpl.dgcLog.log(Log.VERBOSE,
316
"reference set is empty: target = " + this);
317
}
318
319
/*
320
* If the remote object implements the Unreferenced interface,
321
* invoke its unreferenced callback in a separate thread.
322
*/
323
Remote obj = getImpl();
324
if (obj instanceof Unreferenced) {
325
final Unreferenced unrefObj = (Unreferenced) obj;
326
AccessController.doPrivileged(
327
new NewThreadAction(() -> {
328
Thread.currentThread().setContextClassLoader(ccl);
329
AccessController.doPrivileged((PrivilegedAction<Void>) () -> {
330
unrefObj.unreferenced();
331
return null;
332
}, acc);
333
}, "Unreferenced-" + nextThreadNum++, false, true)).start();
334
// REMIND: access to nextThreadNum not synchronized; you care?
335
}
336
337
unpinImpl();
338
}
339
}
340
341
/**
342
* Mark this target as not accepting new calls if any of the
343
* following conditions exist: a) the force parameter is true,
344
* b) the target's call count is zero, or c) the object is already
345
* not accepting calls. Returns true if target is marked as not
346
* accepting new calls; returns false otherwise.
347
*/
348
synchronized boolean unexport(boolean force) {
349
350
if ((force == true) || (callCount == 0) || (disp == null)) {
351
disp = null;
352
/*
353
* Fix for 4331349: unpin object so that it may be gc'd.
354
* Also, unregister all vmids referencing this target
355
* so target can be gc'd.
356
*/
357
unpinImpl();
358
DGCImpl dgc = DGCImpl.getDGCImpl();
359
Enumeration<VMID> enum_ = refSet.elements();
360
while (enum_.hasMoreElements()) {
361
VMID vmid = enum_.nextElement();
362
dgc.unregisterTarget(vmid, this);
363
}
364
return true;
365
} else {
366
return false;
367
}
368
}
369
370
/**
371
* Mark this target as having been removed from the object table.
372
*/
373
synchronized void markRemoved() {
374
if (!(!removed)) { throw new AssertionError(); }
375
376
removed = true;
377
if (!permanent && callCount == 0) {
378
ObjectTable.decrementKeepAliveCount();
379
}
380
381
if (exportedTransport != null) {
382
exportedTransport.targetUnexported();
383
}
384
}
385
386
/**
387
* Increment call count.
388
*/
389
synchronized void incrementCallCount() throws NoSuchObjectException {
390
391
if (disp != null) {
392
callCount ++;
393
} else {
394
throw new NoSuchObjectException("object not accepting new calls");
395
}
396
}
397
398
/**
399
* Decrement call count.
400
*/
401
synchronized void decrementCallCount() {
402
403
if (--callCount < 0) {
404
throw new Error("internal error: call count less than zero");
405
}
406
407
/*
408
* The "keep-alive count" is the number of non-permanent remote
409
* objects that are either in the object table or still have calls
410
* in progress. Therefore, this state change may affect the
411
* keep-alive count: if this target is for a non-permanent remote
412
* object that has been removed from the object table and now has a
413
* call count of zero, it needs to be decremented.
414
*/
415
if (!permanent && removed && callCount == 0) {
416
ObjectTable.decrementKeepAliveCount();
417
}
418
}
419
420
/**
421
* Returns true if remembered set is empty; otherwise returns
422
* false
423
*/
424
boolean isEmpty() {
425
return refSet.isEmpty();
426
}
427
428
/**
429
* This method is called if the address space associated with the
430
* vmid dies. In that case, the vmid should be removed
431
* from the reference set.
432
*/
433
synchronized public void vmidDead(VMID vmid) {
434
if (DGCImpl.dgcLog.isLoggable(Log.BRIEF)) {
435
DGCImpl.dgcLog.log(Log.BRIEF, "removing endpoint " +
436
vmid + " from reference set");
437
}
438
439
sequenceTable.remove(vmid);
440
refSetRemove(vmid);
441
}
442
}
443
444
class SequenceEntry {
445
long sequenceNum;
446
boolean keep;
447
448
SequenceEntry(long sequenceNum) {
449
this.sequenceNum = sequenceNum;
450
keep = false;
451
}
452
453
void retain(long sequenceNum) {
454
this.sequenceNum = sequenceNum;
455
keep = true;
456
}
457
458
void update(long sequenceNum) {
459
this.sequenceNum = sequenceNum;
460
}
461
}
462
463