Mercurial > hg > truffle
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 |