Wed, 27 Mar 2013 19:21:18 +0100
7112912: Message "Error occurred during initialization of VM" on boxes with lots of RAM
Summary: Ergonomics now also takes available virtual memory into account when deciding for a heap size. The helper method to determine the maximum allocatable memory block now uses the appropriate OS specific calls to retrieve available virtual memory for the java process. In 32 bit environments this method now also searches for the maximum actually reservable amount of memory. Merge previously separate implementations for Linux/BSD/Solaris into a single method.
Reviewed-by: jmasa, tamao
1 /*
2 * Copyright (c) 2005, 2012, 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 */
25 #include "precompiled.hpp"
26 #include "runtime/interfaceSupport.hpp"
27 #include "runtime/os.hpp"
28 #include "services/attachListener.hpp"
29 #include "services/dtraceAttacher.hpp"
31 #include <door.h>
32 #include <string.h>
33 #include <signal.h>
34 #include <sys/types.h>
35 #include <sys/socket.h>
36 #include <sys/stat.h>
38 // stropts.h uses STR in stream ioctl defines
39 #undef STR
40 #include <stropts.h>
41 #undef STR
42 #define STR(a) #a
44 // The attach mechanism on Solaris is implemented using the Doors IPC
45 // mechanism. The first tool to attempt to attach causes the attach
46 // listener thread to startup. This thread creats a door that is
47 // associated with a function that enqueues an operation to the attach
48 // listener. The door is attached to a file in the file system so that
49 // client (tools) can locate it. To enqueue an operation to the VM the
50 // client calls through the door which invokes the enqueue function in
51 // this process. The credentials of the client are checked and if the
52 // effective uid matches this process then the operation is enqueued.
53 // When an operation completes the attach listener is required to send the
54 // operation result and any result data to the client. In this implementation
55 // the result is returned via a UNIX domain socket. A pair of connected
56 // sockets (socketpair) is created in the enqueue function and the file
57 // descriptor for one of the sockets is returned to the client as the
58 // return from the door call. The other end is retained in this process.
59 // When the operation completes the result is sent to the client and
60 // the socket is closed.
62 // forward reference
63 class SolarisAttachOperation;
65 class SolarisAttachListener: AllStatic {
66 private:
68 // the path to which we attach the door file descriptor
69 static char _door_path[PATH_MAX+1];
70 static volatile bool _has_door_path;
72 // door descriptor returned by door_create
73 static int _door_descriptor;
75 static void set_door_path(char* path) {
76 if (path == NULL) {
77 _has_door_path = false;
78 } else {
79 strncpy(_door_path, path, PATH_MAX);
80 _door_path[PATH_MAX] = '\0'; // ensure it's nul terminated
81 _has_door_path = true;
82 }
83 }
85 static void set_door_descriptor(int dd) { _door_descriptor = dd; }
87 // mutex to protect operation list
88 static mutex_t _mutex;
90 // semaphore to wakeup listener thread
91 static sema_t _wakeup;
93 static mutex_t* mutex() { return &_mutex; }
94 static sema_t* wakeup() { return &_wakeup; }
96 // enqueued operation list
97 static SolarisAttachOperation* _head;
98 static SolarisAttachOperation* _tail;
100 static SolarisAttachOperation* head() { return _head; }
101 static void set_head(SolarisAttachOperation* head) { _head = head; }
103 static SolarisAttachOperation* tail() { return _tail; }
104 static void set_tail(SolarisAttachOperation* tail) { _tail = tail; }
106 // create the door
107 static int create_door();
109 public:
110 enum {
111 ATTACH_PROTOCOL_VER = 1 // protocol version
112 };
113 enum {
114 ATTACH_ERROR_BADREQUEST = 100, // error code returned by
115 ATTACH_ERROR_BADVERSION = 101, // the door call
116 ATTACH_ERROR_RESOURCE = 102,
117 ATTACH_ERROR_INTERNAL = 103,
118 ATTACH_ERROR_DENIED = 104
119 };
121 // initialize the listener
122 static int init();
124 static bool has_door_path() { return _has_door_path; }
125 static char* door_path() { return _door_path; }
126 static int door_descriptor() { return _door_descriptor; }
128 // enqueue an operation
129 static void enqueue(SolarisAttachOperation* op);
131 // dequeue an operation
132 static SolarisAttachOperation* dequeue();
133 };
136 // SolarisAttachOperation is an AttachOperation that additionally encapsulates
137 // a socket connection to the requesting client/tool. SolarisAttachOperation
138 // can additionally be held in a linked list.
140 class SolarisAttachOperation: public AttachOperation {
141 private:
142 friend class SolarisAttachListener;
144 // connection to client
145 int _socket;
147 // linked list support
148 SolarisAttachOperation* _next;
150 SolarisAttachOperation* next() { return _next; }
151 void set_next(SolarisAttachOperation* next) { _next = next; }
153 public:
154 void complete(jint res, bufferedStream* st);
156 int socket() const { return _socket; }
157 void set_socket(int s) { _socket = s; }
159 SolarisAttachOperation(char* name) : AttachOperation(name) {
160 set_socket(-1);
161 set_next(NULL);
162 }
163 };
165 // statics
166 char SolarisAttachListener::_door_path[PATH_MAX+1];
167 volatile bool SolarisAttachListener::_has_door_path;
168 int SolarisAttachListener::_door_descriptor = -1;
169 mutex_t SolarisAttachListener::_mutex;
170 sema_t SolarisAttachListener::_wakeup;
171 SolarisAttachOperation* SolarisAttachListener::_head = NULL;
172 SolarisAttachOperation* SolarisAttachListener::_tail = NULL;
174 // Supporting class to help split a buffer into individual components
175 class ArgumentIterator : public StackObj {
176 private:
177 char* _pos;
178 char* _end;
179 public:
180 ArgumentIterator(char* arg_buffer, size_t arg_size) {
181 _pos = arg_buffer;
182 _end = _pos + arg_size - 1;
183 }
184 char* next() {
185 if (*_pos == '\0') {
186 return NULL;
187 }
188 char* res = _pos;
189 char* next_pos = strchr(_pos, '\0');
190 if (next_pos < _end) {
191 next_pos++;
192 }
193 _pos = next_pos;
194 return res;
195 }
196 };
198 // Calls from the door function to check that the client credentials
199 // match this process. Returns 0 if credentials okay, otherwise -1.
200 static int check_credentials() {
201 door_cred_t cred_info;
203 // get client credentials
204 if (door_cred(&cred_info) == -1) {
205 return -1; // unable to get them
206 }
208 // get our euid/eguid (probably could cache these)
209 uid_t euid = geteuid();
210 gid_t egid = getegid();
212 // check that the effective uid/gid matches - discuss this with Jeff.
213 if (cred_info.dc_euid == euid && cred_info.dc_egid == egid) {
214 return 0; // okay
215 } else {
216 return -1; // denied
217 }
218 }
221 // Parses the argument buffer to create an AttachOperation that we should
222 // enqueue to the attach listener.
223 // The buffer is expected to be formatted as follows:
224 // <ver>0<cmd>0<arg>0<arg>0<arg>0
225 // where <ver> is the version number (must be "1"), <cmd> is the command
226 // name ("load, "datadump", ...) and <arg> is an argument.
227 //
228 static SolarisAttachOperation* create_operation(char* argp, size_t arg_size, int* err) {
229 // assume bad request until parsed
230 *err = SolarisAttachListener::ATTACH_ERROR_BADREQUEST;
232 if (arg_size < 2 || argp[arg_size-1] != '\0') {
233 return NULL; // no ver or not null terminated
234 }
236 // Use supporting class to iterate over the buffer
237 ArgumentIterator args(argp, arg_size);
239 // First check the protocol version
240 char* ver = args.next();
241 if (ver == NULL) {
242 return NULL;
243 }
244 if (atoi(ver) != SolarisAttachListener::ATTACH_PROTOCOL_VER) {
245 *err = SolarisAttachListener::ATTACH_ERROR_BADVERSION;
246 return NULL;
247 }
249 // Get command name and create the operation
250 char* name = args.next();
251 if (name == NULL || strlen(name) > AttachOperation::name_length_max) {
252 return NULL;
253 }
254 SolarisAttachOperation* op = new SolarisAttachOperation(name);
256 // Iterate over the arguments
257 for (int i=0; i<AttachOperation::arg_count_max; i++) {
258 char* arg = args.next();
259 if (arg == NULL) {
260 op->set_arg(i, NULL);
261 } else {
262 if (strlen(arg) > AttachOperation::arg_length_max) {
263 delete op;
264 return NULL;
265 }
266 op->set_arg(i, arg);
267 }
268 }
270 // return operation
271 *err = 0;
272 return op;
273 }
275 // create special operation to indicate all clients have detached
276 static SolarisAttachOperation* create_detachall_operation() {
277 return new SolarisAttachOperation(AttachOperation::detachall_operation_name());
278 }
280 // This is door function which the client executes via a door_call.
281 extern "C" {
282 static void enqueue_proc(void* cookie, char* argp, size_t arg_size,
283 door_desc_t* dt, uint_t n_desc)
284 {
285 int return_fd = -1;
286 SolarisAttachOperation* op = NULL;
288 // no listener
289 jint res = 0;
290 if (!AttachListener::is_initialized()) {
291 // how did we get here?
292 debug_only(warning("door_call when not enabled"));
293 res = (jint)SolarisAttachListener::ATTACH_ERROR_INTERNAL;
294 }
296 // check client credentials
297 if (res == 0) {
298 if (check_credentials() != 0) {
299 res = (jint)SolarisAttachListener::ATTACH_ERROR_DENIED;
300 }
301 }
303 // if we are stopped at ShowMessageBoxOnError then maybe we can
304 // load a diagnostic library
305 if (res == 0 && is_error_reported()) {
306 if (ShowMessageBoxOnError) {
307 // TBD - support loading of diagnostic library here
308 }
310 // can't enqueue operation after fatal error
311 res = (jint)SolarisAttachListener::ATTACH_ERROR_RESOURCE;
312 }
314 // create the operation
315 if (res == 0) {
316 int err;
317 op = create_operation(argp, arg_size, &err);
318 res = (op == NULL) ? (jint)err : 0;
319 }
321 // create a pair of connected sockets. Store the file descriptor
322 // for one end in the operation and enqueue the operation. The
323 // file descriptor for the other end wil be returned to the client.
324 if (res == 0) {
325 int s[2];
326 if (socketpair(PF_UNIX, SOCK_STREAM, 0, s) < 0) {
327 delete op;
328 res = (jint)SolarisAttachListener::ATTACH_ERROR_RESOURCE;
329 } else {
330 op->set_socket(s[0]);
331 return_fd = s[1];
332 SolarisAttachListener::enqueue(op);
333 }
334 }
336 // Return 0 (success) + file descriptor, or non-0 (error)
337 if (res == 0) {
338 door_desc_t desc;
339 // DOOR_RELEASE flag makes sure fd is closed after passing it to
340 // the client. See door_return(3DOOR) man page.
341 desc.d_attributes = DOOR_DESCRIPTOR | DOOR_RELEASE;
342 desc.d_data.d_desc.d_descriptor = return_fd;
343 door_return((char*)&res, sizeof(res), &desc, 1);
344 } else {
345 door_return((char*)&res, sizeof(res), NULL, 0);
346 }
347 }
348 }
350 // atexit hook to detach the door and remove the file
351 extern "C" {
352 static void listener_cleanup() {
353 static int cleanup_done;
354 if (!cleanup_done) {
355 cleanup_done = 1;
356 int dd = SolarisAttachListener::door_descriptor();
357 if (dd >= 0) {
358 ::close(dd);
359 }
360 if (SolarisAttachListener::has_door_path()) {
361 char* path = SolarisAttachListener::door_path();
362 ::fdetach(path);
363 ::unlink(path);
364 }
365 }
366 }
367 }
369 // Create the door
370 int SolarisAttachListener::create_door() {
371 char door_path[PATH_MAX+1];
372 char initial_path[PATH_MAX+1];
373 int fd, res;
375 // register exit function
376 ::atexit(listener_cleanup);
378 // create the door descriptor
379 int dd = ::door_create(enqueue_proc, NULL, 0);
380 if (dd < 0) {
381 return -1;
382 }
384 // create initial file to attach door descriptor
385 snprintf(door_path, sizeof(door_path), "%s/.java_pid%d",
386 os::get_temp_directory(), os::current_process_id());
387 snprintf(initial_path, sizeof(initial_path), "%s.tmp", door_path);
388 RESTARTABLE(::creat(initial_path, S_IRUSR | S_IWUSR), fd);
389 if (fd == -1) {
390 debug_only(warning("attempt to create %s failed", initial_path));
391 ::door_revoke(dd);
392 return -1;
393 }
394 assert(fd >= 0, "bad file descriptor");
395 RESTARTABLE(::close(fd), res);
397 // attach the door descriptor to the file
398 if ((res = ::fattach(dd, initial_path)) == -1) {
399 // if busy then detach and try again
400 if (errno == EBUSY) {
401 ::fdetach(initial_path);
402 res = ::fattach(dd, initial_path);
403 }
404 if (res == -1) {
405 ::door_revoke(dd);
406 dd = -1;
407 }
408 }
410 // rename file so that clients can attach
411 if (dd >= 0) {
412 if (::rename(initial_path, door_path) == -1) {
413 RESTARTABLE(::close(dd), res);
414 ::fdetach(initial_path);
415 dd = -1;
416 }
417 }
418 if (dd >= 0) {
419 set_door_descriptor(dd);
420 set_door_path(door_path);
421 } else {
422 // unable to create door, attach it to file, or rename file into place
423 ::unlink(initial_path);
424 return -1;
425 }
427 return 0;
428 }
430 // Initialization - create the door, locks, and other initialization
431 int SolarisAttachListener::init() {
432 if (create_door()) {
433 return -1;
434 }
436 int status = os::Solaris::mutex_init(&_mutex);
437 assert_status(status==0, status, "mutex_init");
439 status = ::sema_init(&_wakeup, 0, NULL, NULL);
440 assert_status(status==0, status, "sema_init");
442 set_head(NULL);
443 set_tail(NULL);
445 return 0;
446 }
448 // Dequeue an operation
449 SolarisAttachOperation* SolarisAttachListener::dequeue() {
450 for (;;) {
451 int res;
453 // wait for somebody to enqueue something
454 while ((res = ::sema_wait(wakeup())) == EINTR)
455 ;
456 if (res) {
457 warning("sema_wait failed: %s", strerror(res));
458 return NULL;
459 }
461 // lock the list
462 res = os::Solaris::mutex_lock(mutex());
463 assert(res == 0, "mutex_lock failed");
465 // remove the head of the list
466 SolarisAttachOperation* op = head();
467 if (op != NULL) {
468 set_head(op->next());
469 if (head() == NULL) {
470 set_tail(NULL);
471 }
472 }
474 // unlock
475 os::Solaris::mutex_unlock(mutex());
477 // if we got an operation when return it.
478 if (op != NULL) {
479 return op;
480 }
481 }
482 }
484 // Enqueue an operation
485 void SolarisAttachListener::enqueue(SolarisAttachOperation* op) {
486 // lock list
487 int res = os::Solaris::mutex_lock(mutex());
488 assert(res == 0, "mutex_lock failed");
490 // enqueue at tail
491 op->set_next(NULL);
492 if (head() == NULL) {
493 set_head(op);
494 } else {
495 tail()->set_next(op);
496 }
497 set_tail(op);
499 // wakeup the attach listener
500 RESTARTABLE(::sema_post(wakeup()), res);
501 assert(res == 0, "sema_post failed");
503 // unlock
504 os::Solaris::mutex_unlock(mutex());
505 }
508 // support function - writes the (entire) buffer to a socket
509 static int write_fully(int s, char* buf, int len) {
510 do {
511 int n = ::write(s, buf, len);
512 if (n == -1) {
513 if (errno != EINTR) return -1;
514 } else {
515 buf += n;
516 len -= n;
517 }
518 }
519 while (len > 0);
520 return 0;
521 }
523 // Complete an operation by sending the operation result and any result
524 // output to the client. At this time the socket is in blocking mode so
525 // potentially we can block if there is a lot of data and the client is
526 // non-responsive. For most operations this is a non-issue because the
527 // default send buffer is sufficient to buffer everything. In the future
528 // if there are operations that involves a very big reply then it the
529 // socket could be made non-blocking and a timeout could be used.
531 void SolarisAttachOperation::complete(jint res, bufferedStream* st) {
532 if (this->socket() >= 0) {
533 JavaThread* thread = JavaThread::current();
534 ThreadBlockInVM tbivm(thread);
536 thread->set_suspend_equivalent();
537 // cleared by handle_special_suspend_equivalent_condition() or
538 // java_suspend_self() via check_and_wait_while_suspended()
540 // write operation result
541 char msg[32];
542 sprintf(msg, "%d\n", res);
543 int rc = write_fully(this->socket(), msg, strlen(msg));
545 // write any result data
546 if (rc == 0) {
547 write_fully(this->socket(), (char*) st->base(), st->size());
548 ::shutdown(this->socket(), 2);
549 }
551 // close socket and we're done
552 RESTARTABLE(::close(this->socket()), rc);
554 // were we externally suspended while we were waiting?
555 thread->check_and_wait_while_suspended();
556 }
557 delete this;
558 }
561 // AttachListener functions
563 AttachOperation* AttachListener::dequeue() {
564 JavaThread* thread = JavaThread::current();
565 ThreadBlockInVM tbivm(thread);
567 thread->set_suspend_equivalent();
568 // cleared by handle_special_suspend_equivalent_condition() or
569 // java_suspend_self() via check_and_wait_while_suspended()
571 AttachOperation* op = SolarisAttachListener::dequeue();
573 // were we externally suspended while we were waiting?
574 thread->check_and_wait_while_suspended();
576 return op;
577 }
579 int AttachListener::pd_init() {
580 JavaThread* thread = JavaThread::current();
581 ThreadBlockInVM tbivm(thread);
583 thread->set_suspend_equivalent();
584 // cleared by handle_special_suspend_equivalent_condition() or
585 // java_suspend_self()
587 int ret_code = SolarisAttachListener::init();
589 // were we externally suspended while we were waiting?
590 thread->check_and_wait_while_suspended();
592 return ret_code;
593 }
595 // Attach Listener is started lazily except in the case when
596 // +ReduseSignalUsage is used
597 bool AttachListener::init_at_startup() {
598 if (ReduceSignalUsage) {
599 return true;
600 } else {
601 return false;
602 }
603 }
605 // If the file .attach_pid<pid> exists in the working directory
606 // or /tmp then this is the trigger to start the attach mechanism
607 bool AttachListener::is_init_trigger() {
608 if (init_at_startup() || is_initialized()) {
609 return false; // initialized at startup or already initialized
610 }
611 char fn[PATH_MAX+1];
612 sprintf(fn, ".attach_pid%d", os::current_process_id());
613 int ret;
614 struct stat64 st;
615 RESTARTABLE(::stat64(fn, &st), ret);
616 if (ret == -1) {
617 snprintf(fn, sizeof(fn), "%s/.attach_pid%d",
618 os::get_temp_directory(), os::current_process_id());
619 RESTARTABLE(::stat64(fn, &st), ret);
620 }
621 if (ret == 0) {
622 // simple check to avoid starting the attach mechanism when
623 // a bogus user creates the file
624 if (st.st_uid == geteuid()) {
625 init();
626 return true;
627 }
628 }
629 return false;
630 }
632 // if VM aborts then detach/cleanup
633 void AttachListener::abort() {
634 listener_cleanup();
635 }
637 void AttachListener::pd_data_dump() {
638 os::signal_notify(SIGQUIT);
639 }
641 static jint enable_dprobes(AttachOperation* op, outputStream* out) {
642 const char* probe = op->arg(0);
643 if (probe == NULL || probe[0] == '\0') {
644 out->print_cr("No probe specified");
645 return JNI_ERR;
646 } else {
647 int probe_typess = atoi(probe);
648 if (errno) {
649 out->print_cr("invalid probe type");
650 return JNI_ERR;
651 } else {
652 DTrace::enable_dprobes(probe_typess);
653 return JNI_OK;
654 }
655 }
656 }
658 // platform specific operations table
659 static AttachOperationFunctionInfo funcs[] = {
660 { "enabledprobes", enable_dprobes },
661 { NULL, NULL }
662 };
664 AttachOperationFunctionInfo* AttachListener::pd_find_operation(const char* name) {
665 int i;
666 for (i = 0; funcs[i].name != NULL; i++) {
667 if (strcmp(funcs[i].name, name) == 0) {
668 return &funcs[i];
669 }
670 }
671 return NULL;
672 }
674 // Solaris specific global flag set. Currently, we support only
675 // changing ExtendedDTraceProbes flag.
676 jint AttachListener::pd_set_flag(AttachOperation* op, outputStream* out) {
677 const char* name = op->arg(0);
678 assert(name != NULL, "flag name should not be null");
679 bool flag = true;
680 const char* arg1;
681 if ((arg1 = op->arg(1)) != NULL) {
682 flag = (atoi(arg1) != 0);
683 if (errno) {
684 out->print_cr("flag value has to be an integer");
685 return JNI_ERR;
686 }
687 }
689 if (strcmp(name, "ExtendedDTraceProbes") == 0) {
690 DTrace::set_extended_dprobes(flag);
691 return JNI_OK;
692 }
694 if (strcmp(name, "DTraceMonitorProbes") == 0) {
695 DTrace::set_monitor_dprobes(flag);
696 return JNI_OK;
697 }
699 out->print_cr("flag '%s' cannot be changed", name);
700 return JNI_ERR;
701 }
703 void AttachListener::pd_detachall() {
704 DTrace::detach_all_clients();
705 }