6649594: Intermittent IOExceptions during dynamic attach on linux and solaris
Reviewed-by: dcubed, dholmes
This commit is contained in:
parent
a20650acd0
commit
640336ebe6
@ -32,11 +32,15 @@
|
|||||||
#include <sys/un.h>
|
#include <sys/un.h>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
|
|
||||||
|
#ifndef UNIX_PATH_MAX
|
||||||
|
#define UNIX_PATH_MAX sizeof(((struct sockaddr_un *)0)->sun_path)
|
||||||
|
#endif
|
||||||
|
|
||||||
// The attach mechanism on Linux uses a UNIX domain socket. An attach listener
|
// The attach mechanism on Linux uses a UNIX domain socket. An attach listener
|
||||||
// thread is created at startup or is created on-demand via a signal from
|
// thread is created at startup or is created on-demand via a signal from
|
||||||
// the client tool. The attach listener creates a socket and binds it to a file
|
// the client tool. The attach listener creates a socket and binds it to a file
|
||||||
// in the filesystem. The attach listener then acts as a simple (single-
|
// in the filesystem. The attach listener then acts as a simple (single-
|
||||||
// threaded) server - tt waits for a client to connect, reads the request,
|
// threaded) server - it waits for a client to connect, reads the request,
|
||||||
// executes it, and returns the response to the client via the socket
|
// executes it, and returns the response to the client via the socket
|
||||||
// connection.
|
// connection.
|
||||||
//
|
//
|
||||||
@ -54,7 +58,7 @@ class LinuxAttachOperation;
|
|||||||
class LinuxAttachListener: AllStatic {
|
class LinuxAttachListener: AllStatic {
|
||||||
private:
|
private:
|
||||||
// the path to which we bind the UNIX domain socket
|
// the path to which we bind the UNIX domain socket
|
||||||
static char _path[PATH_MAX+1];
|
static char _path[UNIX_PATH_MAX];
|
||||||
static bool _has_path;
|
static bool _has_path;
|
||||||
|
|
||||||
// the file descriptor for the listening socket
|
// the file descriptor for the listening socket
|
||||||
@ -64,8 +68,8 @@ class LinuxAttachListener: AllStatic {
|
|||||||
if (path == NULL) {
|
if (path == NULL) {
|
||||||
_has_path = false;
|
_has_path = false;
|
||||||
} else {
|
} else {
|
||||||
strncpy(_path, path, PATH_MAX);
|
strncpy(_path, path, UNIX_PATH_MAX);
|
||||||
_path[PATH_MAX] = '\0';
|
_path[UNIX_PATH_MAX-1] = '\0';
|
||||||
_has_path = true;
|
_has_path = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -113,7 +117,7 @@ class LinuxAttachOperation: public AttachOperation {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// statics
|
// statics
|
||||||
char LinuxAttachListener::_path[PATH_MAX+1];
|
char LinuxAttachListener::_path[UNIX_PATH_MAX];
|
||||||
bool LinuxAttachListener::_has_path;
|
bool LinuxAttachListener::_has_path;
|
||||||
int LinuxAttachListener::_listener = -1;
|
int LinuxAttachListener::_listener = -1;
|
||||||
|
|
||||||
@ -163,54 +167,53 @@ extern "C" {
|
|||||||
// Initialization - create a listener socket and bind it to a file
|
// Initialization - create a listener socket and bind it to a file
|
||||||
|
|
||||||
int LinuxAttachListener::init() {
|
int LinuxAttachListener::init() {
|
||||||
char path[PATH_MAX+1]; // socket file
|
char path[UNIX_PATH_MAX]; // socket file
|
||||||
|
char initial_path[UNIX_PATH_MAX]; // socket file during setup
|
||||||
int listener; // listener socket (file descriptor)
|
int listener; // listener socket (file descriptor)
|
||||||
|
|
||||||
// register function to cleanup
|
// register function to cleanup
|
||||||
::atexit(listener_cleanup);
|
::atexit(listener_cleanup);
|
||||||
|
|
||||||
|
int n = snprintf(path, UNIX_PATH_MAX, "%s/.java_pid%d",
|
||||||
|
os::get_temp_directory(), os::current_process_id());
|
||||||
|
if (n <= (int)UNIX_PATH_MAX) {
|
||||||
|
n = snprintf(initial_path, UNIX_PATH_MAX, "%s.tmp", path);
|
||||||
|
}
|
||||||
|
if (n > (int)UNIX_PATH_MAX) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
// create the listener socket
|
// create the listener socket
|
||||||
listener = ::socket(PF_UNIX, SOCK_STREAM, 0);
|
listener = ::socket(PF_UNIX, SOCK_STREAM, 0);
|
||||||
if (listener == -1) {
|
if (listener == -1) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int res = -1;
|
// bind socket
|
||||||
struct sockaddr_un addr;
|
struct sockaddr_un addr;
|
||||||
addr.sun_family = AF_UNIX;
|
addr.sun_family = AF_UNIX;
|
||||||
|
strcpy(addr.sun_path, initial_path);
|
||||||
// FIXME: Prior to b39 the tool-side API expected to find the well
|
::unlink(initial_path);
|
||||||
// known file in the working directory. To allow this libjvm.so work with
|
int res = ::bind(listener, (struct sockaddr*)&addr, sizeof(addr));
|
||||||
// a pre-b39 SDK we create it in the working directory if
|
|
||||||
// +StartAttachListener is used is used. All unit tests for this feature
|
|
||||||
// currently used this flag. Once b39 SDK has been promoted we can remove
|
|
||||||
// this code.
|
|
||||||
if (StartAttachListener) {
|
|
||||||
sprintf(path, ".java_pid%d", os::current_process_id());
|
|
||||||
strcpy(addr.sun_path, path);
|
|
||||||
::unlink(path);
|
|
||||||
res = ::bind(listener, (struct sockaddr*)&addr, sizeof(addr));
|
|
||||||
}
|
|
||||||
if (res == -1) {
|
if (res == -1) {
|
||||||
snprintf(path, PATH_MAX+1, "%s/.java_pid%d",
|
RESTARTABLE(::close(listener), res);
|
||||||
os::get_temp_directory(), os::current_process_id());
|
return -1;
|
||||||
strcpy(addr.sun_path, path);
|
}
|
||||||
::unlink(path);
|
|
||||||
res = ::bind(listener, (struct sockaddr*)&addr, sizeof(addr));
|
// put in listen mode, set permissions, and rename into place
|
||||||
|
res = ::listen(listener, 5);
|
||||||
|
if (res == 0) {
|
||||||
|
RESTARTABLE(::chmod(initial_path, S_IREAD|S_IWRITE), res);
|
||||||
|
if (res == 0) {
|
||||||
|
res = ::rename(initial_path, path);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (res == -1) {
|
if (res == -1) {
|
||||||
RESTARTABLE(::close(listener), res);
|
RESTARTABLE(::close(listener), res);
|
||||||
|
::unlink(initial_path);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
set_path(path);
|
set_path(path);
|
||||||
|
|
||||||
// put in listen mode and set permission
|
|
||||||
if ((::listen(listener, 5) == -1) || (::chmod(path, S_IREAD|S_IWRITE) == -1)) {
|
|
||||||
RESTARTABLE(::close(listener), res);
|
|
||||||
::unlink(path);
|
|
||||||
set_path(NULL);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
set_listener(listener);
|
set_listener(listener);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -364,6 +364,7 @@ extern "C" {
|
|||||||
// Create the door
|
// Create the door
|
||||||
int SolarisAttachListener::create_door() {
|
int SolarisAttachListener::create_door() {
|
||||||
char door_path[PATH_MAX+1];
|
char door_path[PATH_MAX+1];
|
||||||
|
char initial_path[PATH_MAX+1];
|
||||||
int fd, res;
|
int fd, res;
|
||||||
|
|
||||||
// register exit function
|
// register exit function
|
||||||
@ -375,36 +376,46 @@ int SolarisAttachListener::create_door() {
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// create initial file to attach door descriptor
|
||||||
snprintf(door_path, sizeof(door_path), "%s/.java_pid%d",
|
snprintf(door_path, sizeof(door_path), "%s/.java_pid%d",
|
||||||
os::get_temp_directory(), os::current_process_id());
|
os::get_temp_directory(), os::current_process_id());
|
||||||
RESTARTABLE(::creat(door_path, S_IRUSR | S_IWUSR), fd);
|
snprintf(initial_path, sizeof(initial_path), "%s.tmp", door_path);
|
||||||
|
RESTARTABLE(::creat(initial_path, S_IRUSR | S_IWUSR), fd);
|
||||||
if (fd == -1) {
|
if (fd == -1) {
|
||||||
debug_only(warning("attempt to create %s failed", door_path));
|
debug_only(warning("attempt to create %s failed", initial_path));
|
||||||
|
::door_revoke(dd);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
assert(fd >= 0, "bad file descriptor");
|
assert(fd >= 0, "bad file descriptor");
|
||||||
set_door_path(door_path);
|
|
||||||
RESTARTABLE(::close(fd), res);
|
RESTARTABLE(::close(fd), res);
|
||||||
|
|
||||||
// attach the door descriptor to the file
|
// attach the door descriptor to the file
|
||||||
if ((res = ::fattach(dd, door_path)) == -1) {
|
if ((res = ::fattach(dd, initial_path)) == -1) {
|
||||||
// if busy then detach and try again
|
// if busy then detach and try again
|
||||||
if (errno == EBUSY) {
|
if (errno == EBUSY) {
|
||||||
::fdetach(door_path);
|
::fdetach(initial_path);
|
||||||
res = ::fattach(dd, door_path);
|
res = ::fattach(dd, initial_path);
|
||||||
}
|
}
|
||||||
if (res == -1) {
|
if (res == -1) {
|
||||||
::door_revoke(dd);
|
::door_revoke(dd);
|
||||||
dd = -1;
|
dd = -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// rename file so that clients can attach
|
||||||
|
if (dd >= 0) {
|
||||||
|
if (::rename(initial_path, door_path) == -1) {
|
||||||
|
RESTARTABLE(::close(dd), res);
|
||||||
|
::fdetach(initial_path);
|
||||||
|
dd = -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
if (dd >= 0) {
|
if (dd >= 0) {
|
||||||
set_door_descriptor(dd);
|
set_door_descriptor(dd);
|
||||||
|
set_door_path(door_path);
|
||||||
} else {
|
} else {
|
||||||
// unable to create door or attach it to the file
|
// unable to create door, attach it to file, or rename file into place
|
||||||
::unlink(door_path);
|
::unlink(initial_path);
|
||||||
set_door_path(NULL);
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user