attachListener_solaris.cpp revision 1472:c18cbe5936b8
1139826Simp/* 253541Sshin * Copyright (c) 2005, 2006, Oracle and/or its affiliates. All rights reserved. 353541Sshin * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 453541Sshin * 553541Sshin * This code is free software; you can redistribute it and/or modify it 653541Sshin * under the terms of the GNU General Public License version 2 only, as 753541Sshin * published by the Free Software Foundation. 853541Sshin * 953541Sshin * This code is distributed in the hope that it will be useful, but WITHOUT 1053541Sshin * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 1153541Sshin * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 1253541Sshin * version 2 for more details (a copy is included in the LICENSE file that 1353541Sshin * accompanied this code). 1453541Sshin * 1553541Sshin * You should have received a copy of the GNU General Public License version 1653541Sshin * 2 along with this work; if not, write to the Free Software Foundation, 1753541Sshin * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 1853541Sshin * 1953541Sshin * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 2053541Sshin * or visit www.oracle.com if you need additional information or have any 2153541Sshin * questions. 2253541Sshin * 2353541Sshin */ 2453541Sshin 2553541Sshin# include "incls/_precompiled.incl" 2653541Sshin# include "incls/_attachListener_solaris.cpp.incl" 2753541Sshin 28174510Sobrien#include <door.h> 29174510Sobrien#include <string.h> 3053541Sshin#include <signal.h> 3153541Sshin#include <sys/types.h> 32174510Sobrien#include <sys/socket.h> 33174510Sobrien#include <sys/stat.h> 34174510Sobrien 3562587Sitojun// stropts.h uses STR in stream ioctl defines 3662587Sitojun#undef STR 37142215Sglebius#include <stropts.h> 38142215Sglebius#undef STR 39178167Sqingli#define STR(a) #a 4055009Sshin 4153541Sshin// The attach mechanism on Solaris is implemented using the Doors IPC 4253541Sshin// mechanism. The first tool to attempt to attach causes the attach 4353541Sshin// listener thread to startup. This thread creats a door that is 4453541Sshin// associated with a function that enqueues an operation to the attach 4553541Sshin// listener. The door is attached to a file in the file system so that 4653541Sshin// client (tools) can locate it. To enqueue an operation to the VM the 4753541Sshin// client calls through the door which invokes the enqueue function in 4853541Sshin// this process. The credentials of the client are checked and if the 4953541Sshin// effective uid matches this process then the operation is enqueued. 5053541Sshin// When an operation completes the attach listener is required to send the 5153541Sshin// operation result and any result data to the client. In this implementation 5278064Sume// the result is returned via a UNIX domain socket. A pair of connected 53181803Sbz// sockets (socketpair) is created in the enqueue function and the file 5453541Sshin// descriptor for one of the sockets is returned to the client as the 5553541Sshin// return from the door call. The other end is retained in this process. 5653541Sshin// When the operation completes the result is sent to the client and 5753541Sshin// the socket is closed. 58147306Sbrooks 5953541Sshin// forward reference 60178167Sqingliclass SolarisAttachOperation; 61178167Sqingli 62178167Sqingliclass SolarisAttachListener: AllStatic { 6353541Sshin private: 6453541Sshin 6553541Sshin // the path to which we attach the door file descriptor 6653541Sshin static char _door_path[PATH_MAX+1]; 67151477Ssuz static volatile bool _has_door_path; 6862587Sitojun 6953541Sshin // door descriptor returned by door_create 70148385Sume static int _door_descriptor; 7153541Sshin 7262587Sitojun static void set_door_path(char* path) { 7353541Sshin if (path == NULL) { 74142215Sglebius _has_door_path = false; 75142215Sglebius } else { 76142215Sglebius strncpy(_door_path, path, PATH_MAX); 77142215Sglebius _door_path[PATH_MAX] = '\0'; // ensure it's nul terminated 7862587Sitojun _has_door_path = true; 7953541Sshin } 8062587Sitojun } 81175162Sobrien 82175162Sobrien static void set_door_descriptor(int dd) { _door_descriptor = dd; } 83175162Sobrien 84175162Sobrien // mutex to protect operation list 85175162Sobrien static mutex_t _mutex; 86175162Sobrien 87175162Sobrien // semaphore to wakeup listener thread 8853541Sshin static sema_t _wakeup; 8962587Sitojun 9062587Sitojun static mutex_t* mutex() { return &_mutex; } 9153541Sshin static sema_t* wakeup() { return &_wakeup; } 9253541Sshin 93108470Sschweikh // enqueued operation list 9453541Sshin static SolarisAttachOperation* _head; 9553541Sshin static SolarisAttachOperation* _tail; 96148987Sume 9753541Sshin static SolarisAttachOperation* head() { return _head; } 9853541Sshin static void set_head(SolarisAttachOperation* head) { _head = head; } 99171259Sdelphij 10053541Sshin static SolarisAttachOperation* tail() { return _tail; } 10153541Sshin static void set_tail(SolarisAttachOperation* tail) { _tail = tail; } 10253541Sshin 10362587Sitojun // create the door 10453541Sshin static int create_door(); 10553541Sshin 10662587Sitojun public: 10753541Sshin enum { 10853541Sshin ATTACH_PROTOCOL_VER = 1 // protocol version 109142215Sglebius }; 11053541Sshin enum { 11153541Sshin ATTACH_ERROR_BADREQUEST = 100, // error code returned by 11253541Sshin ATTACH_ERROR_BADVERSION = 101, // the door call 11353541Sshin ATTACH_ERROR_RESOURCE = 102, 11462587Sitojun ATTACH_ERROR_INTERNAL = 103, 115165118Sbz ATTACH_ERROR_DENIED = 104 11653541Sshin }; 11778064Sume 11878064Sume // initialize the listener 11978064Sume static int init(); 12078064Sume 12178064Sume static bool has_door_path() { return _has_door_path; } 12278064Sume static char* door_path() { return _door_path; } 123181803Sbz static int door_descriptor() { return _door_descriptor; } 12478064Sume 12578064Sume // enqueue an operation 12678064Sume static void enqueue(SolarisAttachOperation* op); 12778064Sume 12878064Sume // dequeue an operation 129148385Sume static SolarisAttachOperation* dequeue(); 130148385Sume}; 13178064Sume 13253541Sshin 13378064Sume// SolarisAttachOperation is an AttachOperation that additionally encapsulates 13478064Sume// a socket connection to the requesting client/tool. SolarisAttachOperation 135165118Sbz// can additionally be held in a linked list. 136165118Sbz 13778064Sumeclass SolarisAttachOperation: public AttachOperation { 13853541Sshin private: 13953541Sshin friend class SolarisAttachListener; 14053541Sshin 141148987Sume // connection to client 142120941Sume int _socket; 14395023Ssuz 144120941Sume // linked list support 145120941Sume SolarisAttachOperation* _next; 146120941Sume 14795023Ssuz SolarisAttachOperation* next() { return _next; } 14853541Sshin void set_next(SolarisAttachOperation* next) { _next = next; } 14978064Sume 150120941Sume public: 15153541Sshin void complete(jint res, bufferedStream* st); 15253541Sshin 15353541Sshin int socket() const { return _socket; } 15453541Sshin void set_socket(int s) { _socket = s; } 15553541Sshin 15678064Sume SolarisAttachOperation(char* name) : AttachOperation(name) { 15753541Sshin set_socket(-1); 15853541Sshin set_next(NULL); 15953541Sshin } 16053541Sshin}; 16153541Sshin 16253541Sshin// statics 16378064Sumechar SolarisAttachListener::_door_path[PATH_MAX+1]; 16478064Sumevolatile bool SolarisAttachListener::_has_door_path; 16578064Sumeint SolarisAttachListener::_door_descriptor = -1; 16678064Sumemutex_t SolarisAttachListener::_mutex; 16753541Sshinsema_t SolarisAttachListener::_wakeup; 16853541SshinSolarisAttachOperation* SolarisAttachListener::_head = NULL; 16953541SshinSolarisAttachOperation* SolarisAttachListener::_tail = NULL; 17095023Ssuz 17153541Sshin// Supporting class to help split a buffer into individual components 17253541Sshinclass ArgumentIterator : public StackObj { 173120941Sume private: 17453541Sshin char* _pos; 17578064Sume char* _end; 17678064Sume public: 17753541Sshin ArgumentIterator(char* arg_buffer, size_t arg_size) { 17853541Sshin _pos = arg_buffer; 17953541Sshin _end = _pos + arg_size - 1; 18053541Sshin } 18153541Sshin char* next() { 18253541Sshin if (*_pos == '\0') { 18353541Sshin return NULL; 18453541Sshin } 18553541Sshin char* res = _pos; 18653541Sshin char* next_pos = strchr(_pos, '\0'); 18753541Sshin if (next_pos < _end) { 18853541Sshin next_pos++; 18953541Sshin } 19053541Sshin _pos = next_pos; 19153541Sshin return res; 19253541Sshin } 19353541Sshin}; 19453541Sshin 19553541Sshin// Calls from the door function to check that the client credentials 19653541Sshin// match this process. Returns 0 if credentials okay, otherwise -1. 19753541Sshinstatic int check_credentials() { 19853541Sshin door_cred_t cred_info; 19953541Sshin 20053541Sshin // get client credentials 20153541Sshin if (door_cred(&cred_info) == -1) { 202142215Sglebius return -1; // unable to get them 203142215Sglebius } 204142215Sglebius 205151465Ssuz // get our euid/eguid (probably could cache these) 206142215Sglebius uid_t euid = geteuid(); 207142215Sglebius gid_t egid = getegid(); 20853541Sshin 209142215Sglebius // check that the effective uid/gid matches - discuss this with Jeff. 21053541Sshin if (cred_info.dc_euid == euid && cred_info.dc_egid == egid) { 21153541Sshin return 0; // okay 212151465Ssuz } else { 21353541Sshin return -1; // denied 21453541Sshin } 215121765Ssam} 216178167Sqingli 217178167Sqingli 218178167Sqingli// Parses the argument buffer to create an AttachOperation that we should 21953541Sshin// enqueue to the attach listener. 220171260Sdelphij// The buffer is expected to be formatted as follows: 22153541Sshin// <ver>0<cmd>0<arg>0<arg>0<arg>0 22253541Sshin// where <ver> is the version number (must be "1"), <cmd> is the command 22353541Sshin// name ("load, "datadump", ...) and <arg> is an argument. 22453541Sshin// 225178167Sqinglistatic SolarisAttachOperation* create_operation(char* argp, size_t arg_size, int* err) { 226178167Sqingli // assume bad request until parsed 227178167Sqingli *err = SolarisAttachListener::ATTACH_ERROR_BADREQUEST; 228178167Sqingli 229178167Sqingli if (arg_size < 2 || argp[arg_size-1] != '\0') { 230178167Sqingli return NULL; // no ver or not null terminated 23153541Sshin } 232178167Sqingli 233121765Ssam // Use supporting class to iterate over the buffer 234121765Ssam ArgumentIterator args(argp, arg_size); 235121765Ssam 236121765Ssam // First check the protocol version 237121765Ssam char* ver = args.next(); 23853541Sshin if (ver == NULL) { 23962587Sitojun return NULL; 24053541Sshin } 24162587Sitojun if (atoi(ver) != SolarisAttachListener::ATTACH_PROTOCOL_VER) { 24262587Sitojun *err = SolarisAttachListener::ATTACH_ERROR_BADVERSION; 24362587Sitojun return NULL; 24453541Sshin } 24562587Sitojun 24662587Sitojun // Get command name and create the operation 24753541Sshin char* name = args.next(); 24853541Sshin if (name == NULL || strlen(name) > AttachOperation::name_length_max) { 249151479Ssuz return NULL; 25053541Sshin } 25178064Sume SolarisAttachOperation* op = new SolarisAttachOperation(name); 25253541Sshin 25353541Sshin // Iterate over the arguments 25453541Sshin for (int i=0; i<AttachOperation::arg_count_max; i++) { 25562587Sitojun char* arg = args.next(); 25653541Sshin if (arg == NULL) { 25753541Sshin op->set_arg(i, NULL); 25853541Sshin } else { 25953541Sshin if (strlen(arg) > AttachOperation::arg_length_max) { 26053541Sshin delete op; 26162587Sitojun return NULL; 26253541Sshin } 26353541Sshin op->set_arg(i, arg); 264120941Sume } 26553541Sshin } 266165118Sbz 267120941Sume // return operation 26878064Sume *err = 0; 26953541Sshin return op; 27053541Sshin} 27153541Sshin 272120941Sume// create special operation to indicate all clients have detached 273165118Sbzstatic SolarisAttachOperation* create_detachall_operation() { 27462587Sitojun return new SolarisAttachOperation(AttachOperation::detachall_operation_name()); 27553541Sshin} 27653541Sshin 27753541Sshin// This is door function which the client executes via a door_call. 27853541Sshinextern "C" { 27953541Sshin static void enqueue_proc(void* cookie, char* argp, size_t arg_size, 28053541Sshin door_desc_t* dt, uint_t n_desc) 28153541Sshin { 28253541Sshin int return_fd = -1; 28353541Sshin SolarisAttachOperation* op = NULL; 28453541Sshin 28553541Sshin // no listener 28653541Sshin jint res = 0; 28753541Sshin if (!AttachListener::is_initialized()) { 28853541Sshin // how did we get here? 28953541Sshin debug_only(warning("door_call when not enabled")); 29053541Sshin res = (jint)SolarisAttachListener::ATTACH_ERROR_INTERNAL; 29153541Sshin } 292148987Sume 29353541Sshin // check client credentials 29453541Sshin if (res == 0) { 29553541Sshin if (check_credentials() != 0) { 29653541Sshin res = (jint)SolarisAttachListener::ATTACH_ERROR_DENIED; 29753541Sshin } 29853541Sshin } 29953541Sshin 30062587Sitojun // if we are stopped at ShowMessageBoxOnError then maybe we can 30153541Sshin // load a diagnostic library 30253541Sshin if (res == 0 && is_error_reported()) { 30353541Sshin if (ShowMessageBoxOnError) { 30453541Sshin // TBD - support loading of diagnostic library here 30553541Sshin } 30653541Sshin 30753541Sshin // can't enqueue operation after fatal error 30853541Sshin res = (jint)SolarisAttachListener::ATTACH_ERROR_RESOURCE; 30953541Sshin } 31053541Sshin 31153541Sshin // create the operation 312148385Sume if (res == 0) { 313148385Sume int err; 314148385Sume op = create_operation(argp, arg_size, &err); 315148385Sume res = (op == NULL) ? (jint)err : 0; 316148385Sume } 317148385Sume 318120941Sume // create a pair of connected sockets. Store the file descriptor 319181803Sbz // for one end in the operation and enqueue the operation. The 320120941Sume // file descriptor for the other end wil be returned to the client. 32162587Sitojun if (res == 0) { 32253541Sshin int s[2]; 32353541Sshin if (socketpair(PF_UNIX, SOCK_STREAM, 0, s) < 0) { 324120941Sume delete op; 325120941Sume res = (jint)SolarisAttachListener::ATTACH_ERROR_RESOURCE; 32653541Sshin } else { 32753541Sshin op->set_socket(s[0]); 328120941Sume return_fd = s[1]; 329181803Sbz SolarisAttachListener::enqueue(op); 330120941Sume } 33162587Sitojun } 33262587Sitojun 33353541Sshin // Return 0 (success) + file descriptor, or non-0 (error) 33453541Sshin if (res == 0) { 33553541Sshin door_desc_t desc; 336165118Sbz desc.d_attributes = DOOR_DESCRIPTOR; 337165118Sbz desc.d_data.d_desc.d_descriptor = return_fd; 338165118Sbz door_return((char*)&res, sizeof(res), &desc, 1); 339165118Sbz } else { 340165118Sbz door_return((char*)&res, sizeof(res), NULL, 0); 341165118Sbz } 342181803Sbz } 34362587Sitojun} 34453541Sshin 34553541Sshin// atexit hook to detach the door and remove the file 34653541Sshinextern "C" { 347108470Sschweikh static void listener_cleanup() { 34853541Sshin static int cleanup_done; 34953541Sshin if (!cleanup_done) { 35053541Sshin cleanup_done = 1; 35153541Sshin int dd = SolarisAttachListener::door_descriptor(); 35253541Sshin if (dd >= 0) { 353148987Sume ::close(dd); 354171259Sdelphij } 355171259Sdelphij if (SolarisAttachListener::has_door_path()) { 356171259Sdelphij char* path = SolarisAttachListener::door_path(); 35753541Sshin ::fdetach(path); 35853541Sshin ::unlink(path); 359171259Sdelphij } 360171259Sdelphij } 36153541Sshin } 36253541Sshin} 36353541Sshin 36453541Sshin// Create the door 365148385Sumeint SolarisAttachListener::create_door() { 36653541Sshin char door_path[PATH_MAX+1]; 36753541Sshin int fd, res; 36862587Sitojun 36953541Sshin // register exit function 370148385Sume ::atexit(listener_cleanup); 371120941Sume 372148385Sume // create the door descriptor 373148385Sume int dd = ::door_create(enqueue_proc, NULL, 0); 37453541Sshin if (dd < 0) { 37553541Sshin return -1; 37653541Sshin } 37762587Sitojun 37862587Sitojun snprintf(door_path, sizeof(door_path), "%s/.java_pid%d", 37962587Sitojun os::get_temp_directory(), os::current_process_id()); 38062587Sitojun RESTARTABLE(::creat(door_path, S_IRUSR | S_IWUSR), fd); 38162587Sitojun 38262587Sitojun if (fd == -1) { 38362587Sitojun debug_only(warning("attempt to create %s failed", door_path)); 38462587Sitojun return -1; 38553541Sshin } 38662587Sitojun assert(fd >= 0, "bad file descriptor"); 38753541Sshin set_door_path(door_path); 388111119Simp RESTARTABLE(::close(fd), res); 38962587Sitojun 390111119Simp // attach the door descriptor to the file 39162587Sitojun if ((res = ::fattach(dd, door_path)) == -1) { 39262587Sitojun // if busy then detach and try again 39362587Sitojun if (errno == EBUSY) { 39462587Sitojun ::fdetach(door_path); 39562587Sitojun res = ::fattach(dd, door_path); 39662587Sitojun } 39762587Sitojun if (res == -1) { 39878064Sume ::door_revoke(dd); 39962587Sitojun dd = -1; 40053541Sshin } 40153541Sshin } 40253541Sshin if (dd >= 0) { 40353541Sshin set_door_descriptor(dd); 40453541Sshin } else { 40553541Sshin // unable to create door or attach it to the file 40653541Sshin ::unlink(door_path); 40753541Sshin set_door_path(NULL); 40853541Sshin return -1; 40995023Ssuz } 41053541Sshin 41153541Sshin return 0; 41253541Sshin} 41353541Sshin 41462587Sitojun// Initialization - create the door, locks, and other initialization 41562587Sitojunint SolarisAttachListener::init() { 41653541Sshin if (create_door()) { 41753541Sshin return -1; 41853541Sshin } 41953541Sshin 42053541Sshin int status = os::Solaris::mutex_init(&_mutex); 42153541Sshin assert_status(status==0, status, "mutex_init"); 42253541Sshin 423148385Sume status = ::sema_init(&_wakeup, 0, NULL, NULL); 42453541Sshin assert_status(status==0, status, "sema_init"); 42553541Sshin 42653541Sshin set_head(NULL); 42753541Sshin set_tail(NULL); 428148385Sume 429148385Sume return 0; 43053541Sshin} 43153541Sshin 43253541Sshin// Dequeue an operation 43353541SshinSolarisAttachOperation* SolarisAttachListener::dequeue() { 43453541Sshin for (;;) { 43553541Sshin int res; 43653541Sshin 43753541Sshin // wait for somebody to enqueue something 43853541Sshin while ((res = ::sema_wait(wakeup())) == EINTR) 43953541Sshin ; 44053541Sshin if (res) { 44153541Sshin warning("sema_wait failed: %s", strerror(res)); 44253541Sshin return NULL; 44353541Sshin } 44453541Sshin 445148385Sume // lock the list 44653541Sshin res = os::Solaris::mutex_lock(mutex()); 44795023Ssuz assert(res == 0, "mutex_lock failed"); 448148385Sume 44953541Sshin // remove the head of the list 45053541Sshin SolarisAttachOperation* op = head(); 451148987Sume if (op != NULL) { 452148987Sume set_head(op->next()); 453148987Sume if (head() == NULL) { 454148987Sume set_tail(NULL); 45553541Sshin } 45653541Sshin } 45753541Sshin 458148385Sume // unlock 45953541Sshin os::Solaris::mutex_unlock(mutex()); 460148385Sume 461148385Sume // if we got an operation when return it. 462148385Sume if (op != NULL) { 463148385Sume return op; 46453541Sshin } 465148385Sume } 466148385Sume} 467148385Sume 468148385Sume// Enqueue an operation 469148385Sumevoid SolarisAttachListener::enqueue(SolarisAttachOperation* op) { 470148385Sume // lock list 471148385Sume int res = os::Solaris::mutex_lock(mutex()); 472148385Sume assert(res == 0, "mutex_lock failed"); 473148385Sume 474148385Sume // enqueue at tail 475148385Sume op->set_next(NULL); 476165118Sbz if (head() == NULL) { 477148385Sume set_head(op); 478148385Sume } else { 479148385Sume tail()->set_next(op); 480165118Sbz } 481165118Sbz set_tail(op); 482148385Sume 48353541Sshin // wakeup the attach listener 48453541Sshin RESTARTABLE(::sema_post(wakeup()), res); 48553541Sshin assert(res == 0, "sema_post failed"); 48653541Sshin 48753541Sshin // unlock 48853541Sshin os::Solaris::mutex_unlock(mutex()); 489148385Sume} 490148385Sume 491148385Sume 49253541Sshin// support function - writes the (entire) buffer to a socket 493148385Sumestatic int write_fully(int s, char* buf, int len) { 494148385Sume do { 49553541Sshin int n = ::write(s, buf, len); 496148385Sume if (n == -1) { 49753541Sshin if (errno != EINTR) return -1; 49853541Sshin } else { 49953541Sshin buf += n; 50053541Sshin len -= n; 50153541Sshin } 502121315Sume } 50353541Sshin while (len > 0); 50453541Sshin return 0; 50553541Sshin} 50653541Sshin 50753541Sshin// Complete an operation by sending the operation result and any result 50853541Sshin// output to the client. At this time the socket is in blocking mode so 50953541Sshin// potentially we can block if there is a lot of data and the client is 51053541Sshin// non-responsive. For most operations this is a non-issue because the 51153541Sshin// default send buffer is sufficient to buffer everything. In the future 51253541Sshin// if there are operations that involves a very big reply then it the 51353541Sshin// socket could be made non-blocking and a timeout could be used. 51453541Sshin 51553541Sshinvoid SolarisAttachOperation::complete(jint res, bufferedStream* st) { 51653541Sshin if (this->socket() >= 0) { 51753541Sshin JavaThread* thread = JavaThread::current(); 51853541Sshin ThreadBlockInVM tbivm(thread); 51953541Sshin 52053541Sshin thread->set_suspend_equivalent(); 521120941Sume // cleared by handle_special_suspend_equivalent_condition() or 52253541Sshin // java_suspend_self() via check_and_wait_while_suspended() 52353541Sshin 52453541Sshin // write operation result 52553541Sshin char msg[32]; 52653541Sshin sprintf(msg, "%d\n", res); 52753541Sshin int rc = write_fully(this->socket(), msg, strlen(msg)); 52853541Sshin 52953541Sshin // write any result data 53053541Sshin if (rc == 0) { 53153541Sshin write_fully(this->socket(), (char*) st->base(), st->size()); 53253541Sshin ::shutdown(this->socket(), 2); 533120941Sume } 534120941Sume 53553541Sshin // close socket and we're done 536151536Ssuz RESTARTABLE(::close(this->socket()), rc); 537148385Sume 538148385Sume // were we externally suspended while we were waiting? 539181803Sbz thread->check_and_wait_while_suspended(); 540148385Sume } 541148385Sume delete this; 542148385Sume} 54353541Sshin 544148385Sume 545148385Sume// AttachListener functions 546148385Sume 547148385SumeAttachOperation* AttachListener::dequeue() { 548148385Sume JavaThread* thread = JavaThread::current(); 549148385Sume ThreadBlockInVM tbivm(thread); 550148385Sume 551148385Sume thread->set_suspend_equivalent(); 55253541Sshin // cleared by handle_special_suspend_equivalent_condition() or 55353541Sshin // java_suspend_self() via check_and_wait_while_suspended() 55453541Sshin 55553541Sshin AttachOperation* op = SolarisAttachListener::dequeue(); 55653541Sshin 55753541Sshin // were we externally suspended while we were waiting? 558148987Sume thread->check_and_wait_while_suspended(); 55962587Sitojun 56062587Sitojun return op; 56162587Sitojun} 56262587Sitojun 56353541Sshinint AttachListener::pd_init() { 56453541Sshin JavaThread* thread = JavaThread::current(); 565171259Sdelphij ThreadBlockInVM tbivm(thread); 56653541Sshin 56753541Sshin thread->set_suspend_equivalent(); 56853541Sshin // cleared by handle_special_suspend_equivalent_condition() or 56962587Sitojun // java_suspend_self() 57053541Sshin 57162587Sitojun int ret_code = SolarisAttachListener::init(); 57262587Sitojun 57362587Sitojun // were we externally suspended while we were waiting? 57462587Sitojun thread->check_and_wait_while_suspended(); 57562587Sitojun 57653541Sshin return ret_code; 57753541Sshin} 57853541Sshin 57953541Sshin// Attach Listener is started lazily except in the case when 58053541Sshin// +ReduseSignalUsage is used 58153541Sshinbool AttachListener::init_at_startup() { 58253541Sshin if (ReduceSignalUsage) { 583165118Sbz return true; 58453541Sshin } else { 58553541Sshin return false; 58678064Sume } 58778064Sume} 588165118Sbz 589165118Sbz// If the file .attach_pid<pid> exists in the working directory 59078064Sume// or /tmp then this is the trigger to start the attach mechanism 59162587Sitojunbool AttachListener::is_init_trigger() { 59262587Sitojun if (init_at_startup() || is_initialized()) { 59362587Sitojun return false; // initialized at startup or already initialized 59462587Sitojun } 59562587Sitojun char fn[PATH_MAX+1]; 59662587Sitojun sprintf(fn, ".attach_pid%d", os::current_process_id()); 59762587Sitojun int ret; 59862587Sitojun struct stat64 st; 599181803Sbz RESTARTABLE(::stat64(fn, &st), ret); 60053541Sshin if (ret == -1) { 60153541Sshin snprintf(fn, sizeof(fn), "%s/.attach_pid%d", 60262587Sitojun os::get_temp_directory(), os::current_process_id()); 603148385Sume RESTARTABLE(::stat64(fn, &st), ret); 60462587Sitojun } 60562587Sitojun if (ret == 0) { 60662587Sitojun // simple check to avoid starting the attach mechanism when 60762587Sitojun // a bogus user creates the file 60853541Sshin if (st.st_uid == geteuid()) { 609148385Sume init(); 610148385Sume return true; 611150202Ssuz } 61253541Sshin } 61353541Sshin return false; 61478064Sume} 61553541Sshin 616165118Sbz// if VM aborts then detach/cleanup 61778064Sumevoid AttachListener::abort() { 61853541Sshin listener_cleanup(); 61953541Sshin} 62053541Sshin 62178064Sumevoid AttachListener::pd_data_dump() { 62278064Sume os::signal_notify(SIGQUIT); 62378064Sume} 62453541Sshin 62553541Sshinstatic jint enable_dprobes(AttachOperation* op, outputStream* out) { 62653541Sshin const char* probe = op->arg(0); 62753541Sshin if (probe == NULL || probe[0] == '\0') { 62853541Sshin out->print_cr("No probe specified"); 62978064Sume return JNI_ERR; 63078064Sume } else { 63178064Sume int probe_typess = atoi(probe); 63262587Sitojun if (errno) { 63353541Sshin out->print_cr("invalid probe type"); 63453541Sshin return JNI_ERR; 63553541Sshin } else { 63653541Sshin DTrace::enable_dprobes(probe_typess); 63753541Sshin return JNI_OK; 63853541Sshin } 63953541Sshin } 64053541Sshin} 64153541Sshin 64253541Sshin// platform specific operations table 64353541Sshinstatic AttachOperationFunctionInfo funcs[] = { 64453541Sshin { "enabledprobes", enable_dprobes }, 64553541Sshin { NULL, NULL } 64653541Sshin}; 64753541Sshin 64853541SshinAttachOperationFunctionInfo* AttachListener::pd_find_operation(const char* name) { 64953541Sshin int i; 65053541Sshin for (i = 0; funcs[i].name != NULL; i++) { 65153541Sshin if (strcmp(funcs[i].name, name) == 0) { 65253541Sshin return &funcs[i]; 65353541Sshin } 65462587Sitojun } 65553541Sshin return NULL; 65653541Sshin} 65795023Ssuz 65853541Sshin// Solaris specific global flag set. Currently, we support only 65953541Sshin// changing ExtendedDTraceProbes flag. 66053541Sshinjint AttachListener::pd_set_flag(AttachOperation* op, outputStream* out) { 661165118Sbz const char* name = op->arg(0); 66262587Sitojun assert(name != NULL, "flag name should not be null"); 66353541Sshin bool flag = true; 66453541Sshin const char* arg1; 66553541Sshin if ((arg1 = op->arg(1)) != NULL) { 666120941Sume flag = (atoi(arg1) != 0); 667165118Sbz if (errno) { 668120941Sume out->print_cr("flag value has to be an integer"); 66978064Sume return JNI_ERR; 67053541Sshin } 67153541Sshin } 67253541Sshin 673120941Sume if (strcmp(name, "ExtendedDTraceProbes") == 0) { 674120941Sume DTrace::set_extended_dprobes(flag); 67553541Sshin return JNI_OK; 67653541Sshin } 67753541Sshin 67853541Sshin if (strcmp(name, "DTraceMonitorProbes") == 0) { 67953541Sshin DTrace::set_monitor_dprobes(flag); 68062587Sitojun return JNI_OK; 68153541Sshin } 68253541Sshin 68353541Sshin out->print_cr("flag '%s' cannot be changed", name); 68453541Sshin return JNI_ERR; 68553541Sshin} 68653541Sshin 687151465Ssuzvoid AttachListener::pd_detachall() { 68862587Sitojun DTrace::detach_all_clients(); 68953541Sshin} 69053541Sshin