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

     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 }

mercurial