comparison src/os/linux/vm/attachListener_linux.cpp @ 1675:a81afd9c293c

6649594: Intermittent IOExceptions during dynamic attach on linux and solaris Reviewed-by: dcubed, dholmes
author alanb
date Fri, 16 Jul 2010 13:14:03 +0100
parents c18cbe5936b8
children 3dc12ef8735e
comparison
equal deleted inserted replaced
1642:0e7d2a08b605 1675:a81afd9c293c
30 #include <sys/types.h> 30 #include <sys/types.h>
31 #include <sys/socket.h> 31 #include <sys/socket.h>
32 #include <sys/un.h> 32 #include <sys/un.h>
33 #include <sys/stat.h> 33 #include <sys/stat.h>
34 34
35 #ifndef UNIX_PATH_MAX
36 #define UNIX_PATH_MAX sizeof(((struct sockaddr_un *)0)->sun_path)
37 #endif
38
35 // The attach mechanism on Linux uses a UNIX domain socket. An attach listener 39 // The attach mechanism on Linux uses a UNIX domain socket. An attach listener
36 // thread is created at startup or is created on-demand via a signal from 40 // thread is created at startup or is created on-demand via a signal from
37 // the client tool. The attach listener creates a socket and binds it to a file 41 // the client tool. The attach listener creates a socket and binds it to a file
38 // in the filesystem. The attach listener then acts as a simple (single- 42 // in the filesystem. The attach listener then acts as a simple (single-
39 // threaded) server - tt waits for a client to connect, reads the request, 43 // threaded) server - it waits for a client to connect, reads the request,
40 // executes it, and returns the response to the client via the socket 44 // executes it, and returns the response to the client via the socket
41 // connection. 45 // connection.
42 // 46 //
43 // As the socket is a UNIX domain socket it means that only clients on the 47 // As the socket is a UNIX domain socket it means that only clients on the
44 // local machine can connect. In addition there are two other aspects to 48 // local machine can connect. In addition there are two other aspects to
52 class LinuxAttachOperation; 56 class LinuxAttachOperation;
53 57
54 class LinuxAttachListener: AllStatic { 58 class LinuxAttachListener: AllStatic {
55 private: 59 private:
56 // the path to which we bind the UNIX domain socket 60 // the path to which we bind the UNIX domain socket
57 static char _path[PATH_MAX+1]; 61 static char _path[UNIX_PATH_MAX];
58 static bool _has_path; 62 static bool _has_path;
59 63
60 // the file descriptor for the listening socket 64 // the file descriptor for the listening socket
61 static int _listener; 65 static int _listener;
62 66
63 static void set_path(char* path) { 67 static void set_path(char* path) {
64 if (path == NULL) { 68 if (path == NULL) {
65 _has_path = false; 69 _has_path = false;
66 } else { 70 } else {
67 strncpy(_path, path, PATH_MAX); 71 strncpy(_path, path, UNIX_PATH_MAX);
68 _path[PATH_MAX] = '\0'; 72 _path[UNIX_PATH_MAX-1] = '\0';
69 _has_path = true; 73 _has_path = true;
70 } 74 }
71 } 75 }
72 76
73 static void set_listener(int s) { _listener = s; } 77 static void set_listener(int s) { _listener = s; }
111 set_socket(-1); 115 set_socket(-1);
112 } 116 }
113 }; 117 };
114 118
115 // statics 119 // statics
116 char LinuxAttachListener::_path[PATH_MAX+1]; 120 char LinuxAttachListener::_path[UNIX_PATH_MAX];
117 bool LinuxAttachListener::_has_path; 121 bool LinuxAttachListener::_has_path;
118 int LinuxAttachListener::_listener = -1; 122 int LinuxAttachListener::_listener = -1;
119 123
120 // Supporting class to help split a buffer into individual components 124 // Supporting class to help split a buffer into individual components
121 class ArgumentIterator : public StackObj { 125 class ArgumentIterator : public StackObj {
161 } 165 }
162 166
163 // Initialization - create a listener socket and bind it to a file 167 // Initialization - create a listener socket and bind it to a file
164 168
165 int LinuxAttachListener::init() { 169 int LinuxAttachListener::init() {
166 char path[PATH_MAX+1]; // socket file 170 char path[UNIX_PATH_MAX]; // socket file
167 int listener; // listener socket (file descriptor) 171 char initial_path[UNIX_PATH_MAX]; // socket file during setup
172 int listener; // listener socket (file descriptor)
168 173
169 // register function to cleanup 174 // register function to cleanup
170 ::atexit(listener_cleanup); 175 ::atexit(listener_cleanup);
176
177 int n = snprintf(path, UNIX_PATH_MAX, "%s/.java_pid%d",
178 os::get_temp_directory(), os::current_process_id());
179 if (n <= (int)UNIX_PATH_MAX) {
180 n = snprintf(initial_path, UNIX_PATH_MAX, "%s.tmp", path);
181 }
182 if (n > (int)UNIX_PATH_MAX) {
183 return -1;
184 }
171 185
172 // create the listener socket 186 // create the listener socket
173 listener = ::socket(PF_UNIX, SOCK_STREAM, 0); 187 listener = ::socket(PF_UNIX, SOCK_STREAM, 0);
174 if (listener == -1) { 188 if (listener == -1) {
175 return -1; 189 return -1;
176 } 190 }
177 191
178 int res = -1; 192 // bind socket
179 struct sockaddr_un addr; 193 struct sockaddr_un addr;
180 addr.sun_family = AF_UNIX; 194 addr.sun_family = AF_UNIX;
181 195 strcpy(addr.sun_path, initial_path);
182 // FIXME: Prior to b39 the tool-side API expected to find the well 196 ::unlink(initial_path);
183 // known file in the working directory. To allow this libjvm.so work with 197 int res = ::bind(listener, (struct sockaddr*)&addr, sizeof(addr));
184 // a pre-b39 SDK we create it in the working directory if
185 // +StartAttachListener is used is used. All unit tests for this feature
186 // currently used this flag. Once b39 SDK has been promoted we can remove
187 // this code.
188 if (StartAttachListener) {
189 sprintf(path, ".java_pid%d", os::current_process_id());
190 strcpy(addr.sun_path, path);
191 ::unlink(path);
192 res = ::bind(listener, (struct sockaddr*)&addr, sizeof(addr));
193 }
194 if (res == -1) {
195 snprintf(path, PATH_MAX+1, "%s/.java_pid%d",
196 os::get_temp_directory(), os::current_process_id());
197 strcpy(addr.sun_path, path);
198 ::unlink(path);
199 res = ::bind(listener, (struct sockaddr*)&addr, sizeof(addr));
200 }
201 if (res == -1) { 198 if (res == -1) {
202 RESTARTABLE(::close(listener), res); 199 RESTARTABLE(::close(listener), res);
203 return -1; 200 return -1;
204 } 201 }
202
203 // put in listen mode, set permissions, and rename into place
204 res = ::listen(listener, 5);
205 if (res == 0) {
206 RESTARTABLE(::chmod(initial_path, S_IREAD|S_IWRITE), res);
207 if (res == 0) {
208 res = ::rename(initial_path, path);
209 }
210 }
211 if (res == -1) {
212 RESTARTABLE(::close(listener), res);
213 ::unlink(initial_path);
214 return -1;
215 }
205 set_path(path); 216 set_path(path);
206
207 // put in listen mode and set permission
208 if ((::listen(listener, 5) == -1) || (::chmod(path, S_IREAD|S_IWRITE) == -1)) {
209 RESTARTABLE(::close(listener), res);
210 ::unlink(path);
211 set_path(NULL);
212 return -1;
213 }
214 set_listener(listener); 217 set_listener(listener);
215 218
216 return 0; 219 return 0;
217 } 220 }
218 221