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