src/os/solaris/vm/attachListener_solaris.cpp

Wed, 27 Mar 2013 19:21:18 +0100

author
tschatzl
date
Wed, 27 Mar 2013 19:21:18 +0100
changeset 4854
754c24457b20
parent 4153
b9a9ed0f8eeb
child 5264
e95fc50106cf
permissions
-rw-r--r--

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

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

mercurial