8225690: Multiple AttachListener threads can be created

Reviewed-by: sspitsyn, cjplummer
This commit is contained in:
Yasumasa Suenaga 2019-07-16 07:29:12 +09:00
parent 5b05ea5a02
commit 2870c9d55e
10 changed files with 475 additions and 102 deletions

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2005, 2018, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2005, 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2012, 2018 SAP SE. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
@ -71,17 +71,7 @@ class AixAttachListener: AllStatic {
// the file descriptor for the listening socket
static int _listener;
static void set_path(char* path) {
if (path == NULL) {
_has_path = false;
} else {
strncpy(_path, path, UNIX_PATH_MAX);
_path[UNIX_PATH_MAX-1] = '\0';
_has_path = true;
}
}
static void set_listener(int s) { _listener = s; }
static bool _atexit_registered;
// reads a request from the given connected socket
static AixAttachOperation* read_request(int s);
@ -94,6 +84,19 @@ class AixAttachListener: AllStatic {
ATTACH_ERROR_BADVERSION = 101 // error codes
};
static void set_path(char* path) {
if (path == NULL) {
_path[0] = '\0';
_has_path = false;
} else {
strncpy(_path, path, UNIX_PATH_MAX);
_path[UNIX_PATH_MAX-1] = '\0';
_has_path = true;
}
}
static void set_listener(int s) { _listener = s; }
// initialize the listener, returns 0 if okay
static int init();
@ -130,6 +133,7 @@ class AixAttachOperation: public AttachOperation {
char AixAttachListener::_path[UNIX_PATH_MAX];
bool AixAttachListener::_has_path;
int AixAttachListener::_listener = -1;
bool AixAttachListener::_atexit_registered = false;
// Shutdown marker to prevent accept blocking during clean-up
bool AixAttachListener::_shutdown = false;
@ -177,17 +181,15 @@ class ArgumentIterator : public StackObj {
// should be sufficient for cleanup.
extern "C" {
static void listener_cleanup() {
static int cleanup_done;
if (!cleanup_done) {
cleanup_done = 1;
AixAttachListener::set_shutdown(true);
int s = AixAttachListener::listener();
if (s != -1) {
::shutdown(s, 2);
}
if (AixAttachListener::has_path()) {
::unlink(AixAttachListener::path());
}
AixAttachListener::set_shutdown(true);
int s = AixAttachListener::listener();
if (s != -1) {
AixAttachListener::set_listener(-1);
::shutdown(s, 2);
}
if (AixAttachListener::has_path()) {
::unlink(AixAttachListener::path());
AixAttachListener::set_path(NULL);
}
}
}
@ -200,7 +202,10 @@ int AixAttachListener::init() {
int listener; // listener socket (file descriptor)
// register function to cleanup
::atexit(listener_cleanup);
if (!_atexit_registered) {
_atexit_registered = true;
::atexit(listener_cleanup);
}
int n = snprintf(path, UNIX_PATH_MAX, "%s/.java_pid%d",
os::get_temp_directory(), os::current_process_id());
@ -515,6 +520,26 @@ int AttachListener::pd_init() {
return ret_code;
}
bool AttachListener::check_socket_file() {
int ret;
struct stat64 st;
ret = stat64(AixAttachListener::path(), &st);
if (ret == -1) { // need to restart attach listener.
log_debug(attach)("Socket file %s does not exist - Restart Attach Listener",
AixAttachListener::path());
listener_cleanup();
// wait to terminate current attach listener instance...
while (AttachListener::transit_state(AL_INITIALIZING,
AL_NOT_INITIALIZED) != AL_NOT_INITIALIZED) {
os::naked_yield();
}
return is_init_trigger();
}
return false;
}
// Attach Listener is started lazily except in the case when
// +ReduseSignalUsage is used
bool AttachListener::init_at_startup() {

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2005, 2018, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2005, 2019, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -68,17 +68,7 @@ class BsdAttachListener: AllStatic {
// the file descriptor for the listening socket
static int _listener;
static void set_path(char* path) {
if (path == NULL) {
_has_path = false;
} else {
strncpy(_path, path, UNIX_PATH_MAX);
_path[UNIX_PATH_MAX-1] = '\0';
_has_path = true;
}
}
static void set_listener(int s) { _listener = s; }
static bool _atexit_registered;
// reads a request from the given connected socket
static BsdAttachOperation* read_request(int s);
@ -91,6 +81,19 @@ class BsdAttachListener: AllStatic {
ATTACH_ERROR_BADVERSION = 101 // error codes
};
static void set_path(char* path) {
if (path == NULL) {
_path[0] = '\0';
_has_path = false;
} else {
strncpy(_path, path, UNIX_PATH_MAX);
_path[UNIX_PATH_MAX-1] = '\0';
_has_path = true;
}
}
static void set_listener(int s) { _listener = s; }
// initialize the listener, returns 0 if okay
static int init();
@ -124,6 +127,7 @@ class BsdAttachOperation: public AttachOperation {
char BsdAttachListener::_path[UNIX_PATH_MAX];
bool BsdAttachListener::_has_path;
int BsdAttachListener::_listener = -1;
bool BsdAttachListener::_atexit_registered = false;
// Supporting class to help split a buffer into individual components
class ArgumentIterator : public StackObj {
@ -158,16 +162,15 @@ class ArgumentIterator : public StackObj {
// bound too.
extern "C" {
static void listener_cleanup() {
static int cleanup_done;
if (!cleanup_done) {
cleanup_done = 1;
int s = BsdAttachListener::listener();
if (s != -1) {
::close(s);
}
if (BsdAttachListener::has_path()) {
::unlink(BsdAttachListener::path());
}
int s = BsdAttachListener::listener();
if (s != -1) {
BsdAttachListener::set_listener(-1);
::shutdown(s, SHUT_RDWR);
::close(s);
}
if (BsdAttachListener::has_path()) {
::unlink(BsdAttachListener::path());
BsdAttachListener::set_path(NULL);
}
}
}
@ -180,7 +183,10 @@ int BsdAttachListener::init() {
int listener; // listener socket (file descriptor)
// register function to cleanup
::atexit(listener_cleanup);
if (!_atexit_registered) {
_atexit_registered = true;
::atexit(listener_cleanup);
}
int n = snprintf(path, UNIX_PATH_MAX, "%s/.java_pid%d",
os::get_temp_directory(), os::current_process_id());
@ -485,6 +491,28 @@ int AttachListener::pd_init() {
return ret_code;
}
bool AttachListener::check_socket_file() {
int ret;
struct stat st;
ret = stat(BsdAttachListener::path(), &st);
if (ret == -1) { // need to restart attach listener.
log_debug(attach)("Socket file %s does not exist - Restart Attach Listener",
BsdAttachListener::path());
listener_cleanup();
// wait to terminate current attach listener instance...
while (AttachListener::transit_state(AL_INITIALIZING,
AL_NOT_INITIALIZED) != AL_NOT_INITIALIZED) {
os::naked_yield();
}
return is_init_trigger();
}
return false;
}
// Attach Listener is started lazily except in the case when
// +ReduseSignalUsage is used
bool AttachListener::init_at_startup() {

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2005, 2018, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2005, 2019, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -69,17 +69,7 @@ class LinuxAttachListener: AllStatic {
// the file descriptor for the listening socket
static int _listener;
static void set_path(char* path) {
if (path == NULL) {
_has_path = false;
} else {
strncpy(_path, path, UNIX_PATH_MAX);
_path[UNIX_PATH_MAX-1] = '\0';
_has_path = true;
}
}
static void set_listener(int s) { _listener = s; }
static bool _atexit_registered;
// reads a request from the given connected socket
static LinuxAttachOperation* read_request(int s);
@ -92,6 +82,19 @@ class LinuxAttachListener: AllStatic {
ATTACH_ERROR_BADVERSION = 101 // error codes
};
static void set_path(char* path) {
if (path == NULL) {
_path[0] = '\0';
_has_path = false;
} else {
strncpy(_path, path, UNIX_PATH_MAX);
_path[UNIX_PATH_MAX-1] = '\0';
_has_path = true;
}
}
static void set_listener(int s) { _listener = s; }
// initialize the listener, returns 0 if okay
static int init();
@ -125,6 +128,7 @@ class LinuxAttachOperation: public AttachOperation {
char LinuxAttachListener::_path[UNIX_PATH_MAX];
bool LinuxAttachListener::_has_path;
int LinuxAttachListener::_listener = -1;
bool LinuxAttachListener::_atexit_registered = false;
// Supporting class to help split a buffer into individual components
class ArgumentIterator : public StackObj {
@ -159,16 +163,15 @@ class ArgumentIterator : public StackObj {
// bound too.
extern "C" {
static void listener_cleanup() {
static int cleanup_done;
if (!cleanup_done) {
cleanup_done = 1;
int s = LinuxAttachListener::listener();
if (s != -1) {
::close(s);
}
if (LinuxAttachListener::has_path()) {
::unlink(LinuxAttachListener::path());
}
int s = LinuxAttachListener::listener();
if (s != -1) {
LinuxAttachListener::set_listener(-1);
::shutdown(s, SHUT_RDWR);
::close(s);
}
if (LinuxAttachListener::has_path()) {
::unlink(LinuxAttachListener::path());
LinuxAttachListener::set_path(NULL);
}
}
}
@ -181,7 +184,10 @@ int LinuxAttachListener::init() {
int listener; // listener socket (file descriptor)
// register function to cleanup
::atexit(listener_cleanup);
if (!_atexit_registered) {
_atexit_registered = true;
::atexit(listener_cleanup);
}
int n = snprintf(path, UNIX_PATH_MAX, "%s/.java_pid%d",
os::get_temp_directory(), os::current_process_id());
@ -485,6 +491,26 @@ int AttachListener::pd_init() {
return ret_code;
}
bool AttachListener::check_socket_file() {
int ret;
struct stat64 st;
ret = stat64(LinuxAttachListener::path(), &st);
if (ret == -1) { // need to restart attach listener.
log_debug(attach)("Socket file %s does not exist - Restart Attach Listener",
LinuxAttachListener::path());
listener_cleanup();
// wait to terminate current attach listener instance...
while (AttachListener::transit_state(AL_INITIALIZING,
AL_NOT_INITIALIZED) != AL_NOT_INITIALIZED) {
os::naked_yield();
}
return is_init_trigger();
}
return false;
}
// Attach Listener is started lazily except in the case when
// +ReduseSignalUsage is used
bool AttachListener::init_at_startup() {

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2005, 2018, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2005, 2019, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -75,17 +75,7 @@ class SolarisAttachListener: AllStatic {
// door descriptor returned by door_create
static int _door_descriptor;
static void set_door_path(char* path) {
if (path == NULL) {
_has_door_path = false;
} else {
strncpy(_door_path, path, PATH_MAX);
_door_path[PATH_MAX] = '\0'; // ensure it's nul terminated
_has_door_path = true;
}
}
static void set_door_descriptor(int dd) { _door_descriptor = dd; }
static bool _atexit_registered;
// mutex to protect operation list
static mutex_t _mutex;
@ -121,6 +111,19 @@ class SolarisAttachListener: AllStatic {
ATTACH_ERROR_DENIED = 104
};
static void set_door_path(char* path) {
if (path == NULL) {
_door_path[0] = '\0';
_has_door_path = false;
} else {
strncpy(_door_path, path, PATH_MAX);
_door_path[PATH_MAX] = '\0'; // ensure it's nul terminated
_has_door_path = true;
}
}
static void set_door_descriptor(int dd) { _door_descriptor = dd; }
// initialize the listener
static int init();
@ -169,6 +172,7 @@ class SolarisAttachOperation: public AttachOperation {
char SolarisAttachListener::_door_path[PATH_MAX+1];
volatile bool SolarisAttachListener::_has_door_path;
int SolarisAttachListener::_door_descriptor = -1;
bool SolarisAttachListener::_atexit_registered = false;
mutex_t SolarisAttachListener::_mutex;
sema_t SolarisAttachListener::_wakeup;
SolarisAttachOperation* SolarisAttachListener::_head = NULL;
@ -364,18 +368,16 @@ extern "C" {
// atexit hook to detach the door and remove the file
extern "C" {
static void listener_cleanup() {
static int cleanup_done;
if (!cleanup_done) {
cleanup_done = 1;
int dd = SolarisAttachListener::door_descriptor();
if (dd >= 0) {
::close(dd);
}
if (SolarisAttachListener::has_door_path()) {
char* path = SolarisAttachListener::door_path();
::fdetach(path);
::unlink(path);
}
int dd = SolarisAttachListener::door_descriptor();
if (dd >= 0) {
SolarisAttachListener::set_door_descriptor(-1);
::close(dd);
}
if (SolarisAttachListener::has_door_path()) {
char* path = SolarisAttachListener::door_path();
::fdetach(path);
::unlink(path);
SolarisAttachListener::set_door_path(NULL);
}
}
}
@ -387,7 +389,10 @@ int SolarisAttachListener::create_door() {
int fd, res;
// register exit function
::atexit(listener_cleanup);
if (!_atexit_registered) {
_atexit_registered = true;
::atexit(listener_cleanup);
}
// create the door descriptor
int dd = ::door_create(enqueue_proc, NULL, 0);
@ -643,6 +648,26 @@ bool AttachListener::init_at_startup() {
}
}
bool AttachListener::check_socket_file() {
int ret;
struct stat64 st;
ret = stat64(SolarisAttachListener::door_path(), &st);
if (ret == -1) { // need to restart attach listener.
log_debug(attach)("Door file %s does not exist - Restart Attach Listener",
SolarisAttachListener::door_path());
listener_cleanup();
// wait to terminate current attach listener instance...
while (AttachListener::transit_state(AL_INITIALIZING,
AL_NOT_INITIALIZED) != AL_NOT_INITIALIZED) {
os::naked_yield();
}
return is_init_trigger();
}
return false;
}
// If the file .attach_pid<pid> exists in the working directory
// or /tmp then this is the trigger to start the attach mechanism
bool AttachListener::is_init_trigger() {

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2005, 2018, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2005, 2019, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -383,6 +383,12 @@ int AttachListener::pd_init() {
return Win32AttachListener::init();
}
// This function is used for Un*x OSes only.
// We need not to implement it for Windows.
bool AttachListener::check_socket_file() {
return false;
}
bool AttachListener::init_at_startup() {
return true;
}

View File

@ -362,8 +362,25 @@ static void signal_thread_entry(JavaThread* thread, TRAPS) {
case SIGBREAK: {
// Check if the signal is a trigger to start the Attach Listener - in that
// case don't print stack traces.
if (!DisableAttachMechanism && AttachListener::is_init_trigger()) {
continue;
if (!DisableAttachMechanism) {
// Attempt to transit state to AL_INITIALIZING.
AttachListenerState cur_state = AttachListener::transit_state(AL_INITIALIZING, AL_NOT_INITIALIZED);
if (cur_state == AL_INITIALIZING) {
// Attach Listener has been started to initialize. Ignore this signal.
continue;
} else if (cur_state == AL_NOT_INITIALIZED) {
// Start to initialize.
if (!AttachListener::is_init_trigger()) {
// Attach Listener could not be started.
// So we need to transit the state to AL_NOT_INITIALIZED.
AttachListener::set_state(AL_NOT_INITIALIZED);
}
continue;
} else if (AttachListener::check_socket_file()) {
// Attach Listener has been started, but unix domain socket file
// does not exist. So restart Attach Listener.
continue;
}
}
// Print stack traces
// Any SIGBREAK operations added here should make sure to flush

View File

@ -45,7 +45,7 @@
#include "utilities/debug.hpp"
#include "utilities/formatBuffer.hpp"
volatile bool AttachListener::_initialized;
volatile AttachListenerState AttachListener::_state = AL_NOT_INITIALIZED;
// Implementation of "properties" command.
//
@ -372,6 +372,7 @@ static void attach_listener_thread_entry(JavaThread* thread, TRAPS) {
"Should already be setup");
if (AttachListener::pd_init() != 0) {
AttachListener::set_state(AL_NOT_INITIALIZED);
return;
}
AttachListener::set_initialized();
@ -379,6 +380,7 @@ static void attach_listener_thread_entry(JavaThread* thread, TRAPS) {
for (;;) {
AttachOperation* op = AttachListener::dequeue();
if (op == NULL) {
AttachListener::set_state(AL_NOT_INITIALIZED);
return; // dequeue failed or shutdown
}
@ -422,6 +424,8 @@ static void attach_listener_thread_entry(JavaThread* thread, TRAPS) {
// operation complete - send result and output to client
op->complete(res, &st);
}
ShouldNotReachHere();
}
bool AttachListener::has_init_error(TRAPS) {
@ -445,6 +449,7 @@ void AttachListener::init() {
const char thread_name[] = "Attach Listener";
Handle string = java_lang_String::create_from_str(thread_name, THREAD);
if (has_init_error(THREAD)) {
set_state(AL_NOT_INITIALIZED);
return;
}
@ -456,6 +461,7 @@ void AttachListener::init() {
string,
THREAD);
if (has_init_error(THREAD)) {
set_state(AL_NOT_INITIALIZED);
return;
}
@ -469,6 +475,7 @@ void AttachListener::init() {
thread_oop,
THREAD);
if (has_init_error(THREAD)) {
set_state(AL_NOT_INITIALIZED);
return;
}

View File

@ -26,6 +26,8 @@
#define SHARE_SERVICES_ATTACHLISTENER_HPP
#include "memory/allocation.hpp"
#include "metaprogramming/isRegisteredEnum.hpp"
#include "runtime/atomic.hpp"
#include "utilities/debug.hpp"
#include "utilities/globalDefinitions.hpp"
#include "utilities/macros.hpp"
@ -49,6 +51,14 @@ struct AttachOperationFunctionInfo {
AttachOperationFunction func;
};
enum AttachListenerState {
AL_NOT_INITIALIZED,
AL_INITIALIZING,
AL_INITIALIZED
};
template<> struct IsRegisteredEnum<AttachListenerState> : public TrueType {};
class AttachListener: AllStatic {
public:
static void vm_start() NOT_SERVICES_RETURN;
@ -58,6 +68,9 @@ class AttachListener: AllStatic {
// invoke to perform clean-up tasks when all clients detach
static void detachall() NOT_SERVICES_RETURN;
// check unix domain socket file on filesystem
static bool check_socket_file() NOT_SERVICES_RETURN_(false);
// indicates if the Attach Listener needs to be created at startup
static bool init_at_startup() NOT_SERVICES_RETURN_(false);
@ -67,12 +80,31 @@ class AttachListener: AllStatic {
#if !INCLUDE_SERVICES
static bool is_attach_supported() { return false; }
#else
private:
static volatile bool _initialized;
static volatile AttachListenerState _state;
public:
static bool is_initialized() { return _initialized; }
static void set_initialized() { _initialized = true; }
static void set_state(AttachListenerState new_state) {
Atomic::store(new_state, &_state);
}
static AttachListenerState get_state() {
return Atomic::load(&_state);
}
static AttachListenerState transit_state(AttachListenerState new_state,
AttachListenerState cmp_state) {
return Atomic::cmpxchg(new_state, &_state, cmp_state);
}
static bool is_initialized() {
return Atomic::load(&_state) == AL_INITIALIZED;
}
static void set_initialized() {
Atomic::store(AL_INITIALIZED, &_state);
}
// indicates if this VM supports attach-on-demand
static bool is_attach_supported() { return !DisableAttachMechanism; }

View File

@ -0,0 +1,126 @@
/*
* Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 8225690
* @requires os.family != "windows"
* @library /test/lib
* @modules jdk.attach/com.sun.tools.attach
* @run main ConcAttachTest
*/
import java.io.IOException;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Executors;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.TimeUnit;
import com.sun.tools.attach.VirtualMachine;
import com.sun.tools.attach.AttachNotSupportedException;
import jdk.test.lib.apps.LingeredApp;
import jdk.test.lib.Asserts;
import jdk.test.lib.JDKToolLauncher;
import jdk.test.lib.process.OutputAnalyzer;
public class ConcAttachTest implements Runnable {
private static final int NUM_CONC_REQUESTS = 100;
private static final int THREAD_POOL_TIMEOUT_IN_SEC = 30;
private static CountDownLatch latch;
private static String strPID;
// Attach to LingeredApp concurrently.
public void run() {
VirtualMachine vm = null;
try {
latch.countDown();
latch.await();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
try {
vm = VirtualMachine.attach(strPID);
} catch (AttachNotSupportedException | IOException e) {
throw new RuntimeException(e);
} finally {
try {
vm.detach();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
private static void checkAttachListenerThread() throws InterruptedException, IOException {
JDKToolLauncher jcmd = JDKToolLauncher.createUsingTestJDK("jcmd");
jcmd.addToolArg(strPID);
jcmd.addToolArg("Thread.print");
ProcessBuilder pb = new ProcessBuilder(jcmd.getCommand());
Process jcmdProc = pb.start();
OutputAnalyzer out = new OutputAnalyzer(jcmdProc);
jcmdProc.waitFor();
System.out.println(out.getStdout());
System.err.println(out.getStderr());
long numOfAttachListener = out.asLines()
.stream()
.filter(l -> l.contains("Attach Listener"))
.count();
Asserts.assertEquals(1L, numOfAttachListener, "AttachListener should exist only 1 thread.");
}
public static void main(String... args) throws Exception {
LingeredApp app = null;
latch = new CountDownLatch(NUM_CONC_REQUESTS);
ExecutorService pool = Executors.newFixedThreadPool(NUM_CONC_REQUESTS);
try {
app = LingeredApp.startApp();
strPID = Long.toString(app.getPid());
for (int i = 0; i < NUM_CONC_REQUESTS; i++) {
pool.submit(new ConcAttachTest());
}
pool.shutdown();
pool.awaitTermination(THREAD_POOL_TIMEOUT_IN_SEC, TimeUnit.SECONDS);
checkAttachListenerThread();
} finally {
LingeredApp.stopApp(app);
}
}
}

View File

@ -0,0 +1,81 @@
/*
* Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 8225193
* @requires os.family != "windows"
* @library /test/lib
* @run main RemovingUnixDomainSocketTest
*/
import java.io.IOException;
import java.nio.file.Path;
import jdk.test.lib.apps.LingeredApp;
import jdk.test.lib.JDKToolLauncher;
import jdk.test.lib.process.OutputAnalyzer;
public class RemovingUnixDomainSocketTest {
private static void runJCmd(long pid) throws InterruptedException, IOException {
JDKToolLauncher jcmd = JDKToolLauncher.createUsingTestJDK("jcmd");
jcmd.addToolArg(Long.toString(pid));
jcmd.addToolArg("VM.version");
ProcessBuilder pb = new ProcessBuilder(jcmd.getCommand());
Process jcmdProc = pb.start();
OutputAnalyzer out = new OutputAnalyzer(jcmdProc);
jcmdProc.waitFor();
System.out.println(out.getStdout());
System.err.println(out.getStderr());
out.stderrShouldBeEmpty();
}
public static void main(String... args) throws Exception {
LingeredApp app = null;
try {
app = LingeredApp.startApp();
// Access to Attach Listener
runJCmd(app.getPid());
// Remove unix domain socket file
var sockFile = Path.of(System.getProperty("java.io.tmpdir"),
".java_pid" + app.getPid())
.toFile();
System.out.println("Remove " + sockFile.toString());
sockFile.delete();
// Access to Attach Listener again
runJCmd(app.getPid());
} finally {
LingeredApp.stopApp(app);
}
}
}