src/os/solaris/vm/attachListener_solaris.cpp

Thu, 12 Oct 2017 21:27:07 +0800

author
aoqi
date
Thu, 12 Oct 2017 21:27:07 +0800
changeset 7535
7ae4e26cb1e0
parent 6876
710a3c8b516e
permissions
-rw-r--r--

merge

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

mercurial