Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mobile
Path: blob/master/test/jdk/java/net/ServerSocket/UnreferencedSockets.java
41152 views
1
/*
2
* Copyright (c) 2017, 2019, 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.
8
*
9
* This code is distributed in the hope that it will be useful, but WITHOUT
10
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12
* version 2 for more details (a copy is included in the LICENSE file that
13
* accompanied this code).
14
*
15
* You should have received a copy of the GNU General Public License version
16
* 2 along with this work; if not, write to the Free Software Foundation,
17
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18
*
19
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20
* or visit www.oracle.com if you need additional information or have any
21
* questions.
22
*/
23
24
/**
25
* @test
26
* @library /test/lib
27
* @modules java.management java.base/java.io:+open java.base/java.net:+open
28
* @run main/othervm UnreferencedSockets
29
* @run main/othervm -Djava.net.preferIPv4Stack=true UnreferencedSockets
30
* @run main/othervm -Djdk.net.usePlainSocketImpl UnreferencedSockets
31
* @summary Check that unreferenced sockets are closed
32
*/
33
34
import java.io.FileDescriptor;
35
import java.io.InputStream;
36
import java.io.OutputStream;
37
import java.lang.management.ManagementFactory;
38
import java.lang.management.OperatingSystemMXBean;
39
import java.lang.ref.ReferenceQueue;
40
import java.lang.ref.WeakReference;
41
import java.lang.reflect.Field;
42
import java.io.IOException;
43
import java.net.InetAddress;
44
import java.net.ServerSocket;
45
import java.net.Socket;
46
import java.net.SocketImpl;
47
import java.nio.file.Files;
48
import java.nio.file.Path;
49
import java.nio.file.Paths;
50
import java.util.ArrayDeque;
51
import java.util.List;
52
import java.util.Optional;
53
import java.util.concurrent.TimeUnit;
54
55
import com.sun.management.UnixOperatingSystemMXBean;
56
57
import jdk.test.lib.net.IPSupport;
58
59
public class UnreferencedSockets {
60
61
/**
62
* The set of sockets we have to check up on.
63
*/
64
final static ArrayDeque<NamedWeak> pendingSockets = new ArrayDeque<>(100);
65
66
/**
67
* Queued sockets when they are unreferenced.
68
*/
69
final static ReferenceQueue<Object> pendingQueue = new ReferenceQueue<>();
70
71
// Server to echo a stream
72
static class Server implements Runnable {
73
74
ServerSocket ss;
75
76
Server(InetAddress address) throws IOException {
77
ss = new ServerSocket(0, 0, address);
78
pendingSockets.add(new NamedWeak(ss, pendingQueue, "serverSocket"));
79
extractRefs(ss, "serverSocket");
80
}
81
82
public int localPort() {
83
return ss.getLocalPort();
84
}
85
86
public void run() {
87
try {
88
Socket s = ss.accept();
89
pendingSockets.add(new NamedWeak(s, pendingQueue, "acceptedSocket"));
90
extractRefs(s, "acceptedSocket");
91
92
InputStream in = s.getInputStream();
93
int b = in.read();
94
OutputStream out = s.getOutputStream();
95
out.write(b);
96
// do NOT close but 'forget' the socket reference
97
out = null;
98
in = null;
99
s = null;
100
} catch (Exception ioe) {
101
ioe.printStackTrace();
102
} finally {
103
try {
104
ss.close();
105
ss = null;
106
} catch (IOException x) {
107
x.printStackTrace();
108
}
109
}
110
}
111
}
112
113
public static void main(String args[]) throws Exception {
114
IPSupport.throwSkippedExceptionIfNonOperational();
115
InetAddress lba = InetAddress.getLoopbackAddress();
116
// Create and close a ServerSocket to warm up the FD count for side effects.
117
try (ServerSocket s = new ServerSocket(0, 0, lba)) {
118
// no-op; close immediately
119
s.getLocalPort(); // no-op
120
}
121
122
long fdCount0 = getFdCount();
123
listProcFD();
124
125
// start a server
126
Server svr = new Server(lba);
127
Thread thr = new Thread(svr);
128
thr.start();
129
130
Socket s = new Socket(lba, svr.localPort());
131
pendingSockets.add(new NamedWeak(s, pendingQueue, "clientSocket"));
132
extractRefs(s, "clientSocket");
133
134
OutputStream out = s.getOutputStream();
135
out.write('x');
136
out.flush();
137
InputStream in = s.getInputStream();
138
int b = in.read(); // wait for it back
139
System.out.printf(" data sent and received%n");
140
// Do NOT close the Socket; forget it
141
142
Object ref;
143
int loops = 20;
144
while (!pendingSockets.isEmpty() && loops-- > 0) {
145
ref = pendingQueue.remove(1000L);
146
if (ref != null) {
147
pendingSockets.remove(ref);
148
System.out.printf(" ref queued: %s, remaining: %d%n", ref, pendingSockets.size());
149
} else {
150
s = null;
151
out = null;
152
in = null;
153
System.gc();
154
}
155
}
156
157
thr.join();
158
159
// List the open file descriptors
160
long fdCount = getFdCount();
161
System.out.printf("Initial fdCount: %d, final fdCount: %d%n", fdCount0, fdCount);
162
listProcFD();
163
164
if (loops == 0) {
165
throw new AssertionError("Not all references reclaimed");
166
}
167
}
168
169
// Get the count of open file descriptors, or -1 if not available
170
private static long getFdCount() {
171
OperatingSystemMXBean mxBean = ManagementFactory.getOperatingSystemMXBean();
172
return (mxBean instanceof UnixOperatingSystemMXBean)
173
? ((UnixOperatingSystemMXBean) mxBean).getOpenFileDescriptorCount()
174
: -1L;
175
}
176
177
// Reflect to find references in the socket implementation that will be gc'd
178
private static void extractRefs(Socket s, String name) {
179
try {
180
181
Field socketImplField = Socket.class.getDeclaredField("impl");
182
socketImplField.setAccessible(true);
183
Object socketImpl = socketImplField.get(s);
184
185
Field fileDescriptorField = SocketImpl.class.getDeclaredField("fd");
186
fileDescriptorField.setAccessible(true);
187
FileDescriptor fileDescriptor = (FileDescriptor) fileDescriptorField.get(socketImpl);
188
extractRefs(fileDescriptor, name);
189
190
Class<?> socketImplClass = socketImpl.getClass();
191
System.out.printf("socketImplClass: %s%n", socketImplClass);
192
if (socketImplClass.getClass().getName().equals("java.net.TwoStacksPlainSocketImpl")) {
193
Field fileDescriptor1Field = socketImplClass.getDeclaredField("fd1");
194
fileDescriptor1Field.setAccessible(true);
195
FileDescriptor fileDescriptor1 = (FileDescriptor) fileDescriptor1Field.get(socketImpl);
196
extractRefs(fileDescriptor1, name + "::twoStacksFd1");
197
198
}
199
} catch (NoSuchFieldException | IllegalAccessException ex) {
200
ex.printStackTrace();
201
throw new AssertionError("missing field", ex);
202
}
203
}
204
205
private static void extractRefs(FileDescriptor fileDescriptor, String name) {
206
Object cleanup = null;
207
int rawfd = -1;
208
try {
209
if (fileDescriptor != null) {
210
Field fd1Field = FileDescriptor.class.getDeclaredField("fd");
211
fd1Field.setAccessible(true);
212
rawfd = fd1Field.getInt(fileDescriptor);
213
214
Field cleanupfdField = FileDescriptor.class.getDeclaredField("cleanup");
215
cleanupfdField.setAccessible(true);
216
cleanup = cleanupfdField.get(fileDescriptor);
217
pendingSockets.add(new NamedWeak(fileDescriptor, pendingQueue,
218
name + "::fileDescriptor: " + rawfd));
219
pendingSockets.add(new NamedWeak(cleanup, pendingQueue, name + "::fdCleanup: " + rawfd));
220
221
}
222
} catch (NoSuchFieldException | IllegalAccessException ex) {
223
ex.printStackTrace();
224
throw new AssertionError("missing field", ex);
225
} finally {
226
System.out.print(String.format(" fd: %s, fd: %d, cleanup: %s%n",
227
fileDescriptor, rawfd, cleanup));
228
}
229
}
230
231
private static void extractRefs(ServerSocket s, String name) {
232
try {
233
234
Field socketImplField = ServerSocket.class.getDeclaredField("impl");
235
socketImplField.setAccessible(true);
236
Object socketImpl = socketImplField.get(s);
237
238
Field fileDescriptorField = SocketImpl.class.getDeclaredField("fd");
239
fileDescriptorField.setAccessible(true);
240
FileDescriptor fileDescriptor = (FileDescriptor) fileDescriptorField.get(socketImpl);
241
242
Field fdField = FileDescriptor.class.getDeclaredField("fd");
243
fdField.setAccessible(true);
244
int rawfd = fdField.getInt(fileDescriptor);
245
246
Field cleanupField = FileDescriptor.class.getDeclaredField("cleanup");
247
cleanupField.setAccessible(true);
248
Object cleanup = cleanupField.get(fileDescriptor);
249
250
System.out.print(String.format(" fd: %s, fd: %d, cleanup: %s, socket: %s%n",
251
fileDescriptor, rawfd, cleanup, s));
252
253
pendingSockets.add(new NamedWeak(fileDescriptor, pendingQueue,
254
name + "::fileDescriptor: " + rawfd));
255
pendingSockets.add(new NamedWeak(cleanup, pendingQueue, name + "::fdCleanup: " + rawfd));
256
257
} catch (NoSuchFieldException | IllegalAccessException ex) {
258
ex.printStackTrace();
259
throw new AssertionError("missing field", ex);
260
}
261
}
262
263
/**
264
* Method to list the open file descriptors (if supported by the 'lsof' command).
265
*/
266
static void listProcFD() {
267
List<String> lsofDirs = List.of("/usr/bin", "/usr/sbin");
268
Optional<Path> lsof = lsofDirs.stream()
269
.map(s -> Paths.get(s, "lsof"))
270
.filter(f -> Files.isExecutable(f))
271
.findFirst();
272
lsof.ifPresent(exe -> {
273
try {
274
System.out.printf("Open File Descriptors:%n");
275
long pid = ProcessHandle.current().pid();
276
ProcessBuilder pb = new ProcessBuilder(exe.toString(), "-p", Integer.toString((int) pid));
277
pb.inheritIO();
278
Process p = pb.start();
279
p.waitFor(10, TimeUnit.SECONDS);
280
} catch (IOException | InterruptedException ie) {
281
ie.printStackTrace();
282
}
283
});
284
}
285
286
// Simple class to identify which refs have been queued
287
static class NamedWeak extends WeakReference<Object> {
288
private final String name;
289
290
NamedWeak(Object o, ReferenceQueue<Object> queue, String name) {
291
super(o, queue);
292
this.name = name;
293
}
294
295
public String toString() {
296
return name + "; " + super.toString();
297
}
298
}
299
}
300
301