< prev index next >

src/hotspot/os/solaris/attachListener_solaris.cpp

Print this page


   1 /*
   2  * Copyright (c) 2005, 2018, 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  *


  58 // the result is returned via a UNIX domain socket. A pair of connected
  59 // sockets (socketpair) is created in the enqueue function and the file
  60 // descriptor for one of the sockets is returned to the client as the
  61 // return from the door call. The other end is retained in this process.
  62 // When the operation completes the result is sent to the client and
  63 // the socket is closed.
  64 
  65 // forward reference
  66 class SolarisAttachOperation;
  67 
  68 class SolarisAttachListener: AllStatic {
  69  private:
  70 
  71   // the path to which we attach the door file descriptor
  72   static char _door_path[PATH_MAX+1];
  73   static volatile bool _has_door_path;
  74 
  75   // door descriptor returned by door_create
  76   static int _door_descriptor;
  77 
  78   static void set_door_path(char* path) {
  79     if (path == NULL) {
  80       _has_door_path = false;
  81     } else {
  82       strncpy(_door_path, path, PATH_MAX);
  83       _door_path[PATH_MAX] = '\0';      // ensure it's nul terminated
  84       _has_door_path = true;
  85     }
  86   }
  87 
  88   static void set_door_descriptor(int dd)               { _door_descriptor = dd; }
  89 
  90   // mutex to protect operation list
  91   static mutex_t _mutex;
  92 
  93   // semaphore to wakeup listener thread
  94   static sema_t _wakeup;
  95 
  96   static mutex_t* mutex()                               { return &_mutex; }
  97   static sema_t* wakeup()                               { return &_wakeup; }
  98 
  99   // enqueued operation list
 100   static SolarisAttachOperation* _head;
 101   static SolarisAttachOperation* _tail;
 102 
 103   static SolarisAttachOperation* head()                 { return _head; }
 104   static void set_head(SolarisAttachOperation* head)    { _head = head; }
 105 
 106   static SolarisAttachOperation* tail()                 { return _tail; }
 107   static void set_tail(SolarisAttachOperation* tail)    { _tail = tail; }
 108 
 109   // create the door
 110   static int create_door();
 111 
 112  public:
 113   enum {
 114     ATTACH_PROTOCOL_VER = 1                             // protocol version
 115   };
 116   enum {
 117     ATTACH_ERROR_BADREQUEST     = 100,                  // error code returned by
 118     ATTACH_ERROR_BADVERSION     = 101,                  // the door call
 119     ATTACH_ERROR_RESOURCE       = 102,
 120     ATTACH_ERROR_INTERNAL       = 103,
 121     ATTACH_ERROR_DENIED         = 104
 122   };
 123 













 124   // initialize the listener
 125   static int init();
 126 
 127   static bool has_door_path()                           { return _has_door_path; }
 128   static char* door_path()                              { return _door_path; }
 129   static int door_descriptor()                          { return _door_descriptor; }
 130 
 131   // enqueue an operation
 132   static void enqueue(SolarisAttachOperation* op);
 133 
 134   // dequeue an operation
 135   static SolarisAttachOperation* dequeue();
 136 };
 137 
 138 
 139 // SolarisAttachOperation is an AttachOperation that additionally encapsulates
 140 // a socket connection to the requesting client/tool. SolarisAttachOperation
 141 // can additionally be held in a linked list.
 142 
 143 class SolarisAttachOperation: public AttachOperation {


 152 
 153   SolarisAttachOperation* next()                         { return _next; }
 154   void set_next(SolarisAttachOperation* next)            { _next = next; }
 155 
 156  public:
 157   void complete(jint res, bufferedStream* st);
 158 
 159   int socket() const                                     { return _socket; }
 160   void set_socket(int s)                                 { _socket = s; }
 161 
 162   SolarisAttachOperation(char* name) : AttachOperation(name) {
 163     set_socket(-1);
 164     set_next(NULL);
 165   }
 166 };
 167 
 168 // statics
 169 char SolarisAttachListener::_door_path[PATH_MAX+1];
 170 volatile bool SolarisAttachListener::_has_door_path;
 171 int SolarisAttachListener::_door_descriptor = -1;

 172 mutex_t SolarisAttachListener::_mutex;
 173 sema_t SolarisAttachListener::_wakeup;
 174 SolarisAttachOperation* SolarisAttachListener::_head = NULL;
 175 SolarisAttachOperation* SolarisAttachListener::_tail = NULL;
 176 
 177 // Supporting class to help split a buffer into individual components
 178 class ArgumentIterator : public StackObj {
 179  private:
 180   char* _pos;
 181   char* _end;
 182  public:
 183   ArgumentIterator(char* arg_buffer, size_t arg_size) {
 184     _pos = arg_buffer;
 185     _end = _pos + arg_size - 1;
 186   }
 187   char* next() {
 188     if (*_pos == '\0') {
 189       // advance the iterator if possible (null arguments)
 190       if (_pos < _end) {
 191         _pos += 1;


 347       }
 348     }
 349 
 350     // Return 0 (success) + file descriptor, or non-0 (error)
 351     if (res == 0) {
 352       door_desc_t desc;
 353       // DOOR_RELEASE flag makes sure fd is closed after passing it to
 354       // the client.  See door_return(3DOOR) man page.
 355       desc.d_attributes = DOOR_DESCRIPTOR | DOOR_RELEASE;
 356       desc.d_data.d_desc.d_descriptor = return_fd;
 357       door_return((char*)&res, sizeof(res), &desc, 1);
 358     } else {
 359       door_return((char*)&res, sizeof(res), NULL, 0);
 360     }
 361   }
 362 }
 363 
 364 // atexit hook to detach the door and remove the file
 365 extern "C" {
 366   static void listener_cleanup() {
 367     static int cleanup_done;
 368     if (!cleanup_done) {
 369       cleanup_done = 1;
 370       int dd = SolarisAttachListener::door_descriptor();
 371       if (dd >= 0) {

 372         ::close(dd);
 373       }
 374       if (SolarisAttachListener::has_door_path()) {
 375         char* path = SolarisAttachListener::door_path();
 376         ::fdetach(path);
 377         ::unlink(path);
 378       }
 379     }
 380   }
 381 }
 382 
 383 // Create the door
 384 int SolarisAttachListener::create_door() {
 385   char door_path[PATH_MAX+1];
 386   char initial_path[PATH_MAX+1];
 387   int fd, res;
 388 
 389   // register exit function


 390   ::atexit(listener_cleanup);

 391 
 392   // create the door descriptor
 393   int dd = ::door_create(enqueue_proc, NULL, 0);
 394   if (dd < 0) {
 395     return -1;
 396   }
 397 
 398   // create initial file to attach door descriptor
 399   snprintf(door_path, sizeof(door_path), "%s/.java_pid%d",
 400            os::get_temp_directory(), os::current_process_id());
 401   snprintf(initial_path, sizeof(initial_path), "%s.tmp", door_path);
 402   RESTARTABLE(::creat(initial_path, S_IRUSR | S_IWUSR), fd);
 403   if (fd == -1) {
 404     log_debug(attach)("attempt to create door file %s failed (%d)", initial_path, errno);
 405     ::door_revoke(dd);
 406     return -1;
 407   }
 408   assert(fd >= 0, "bad file descriptor");
 409   ::close(fd);
 410 


 624   thread->set_suspend_equivalent();
 625   // cleared by handle_special_suspend_equivalent_condition() or
 626   // java_suspend_self()
 627 
 628   int ret_code = SolarisAttachListener::init();
 629 
 630   // were we externally suspended while we were waiting?
 631   thread->check_and_wait_while_suspended();
 632 
 633   return ret_code;
 634 }
 635 
 636 // Attach Listener is started lazily except in the case when
 637 // +ReduseSignalUsage is used
 638 bool AttachListener::init_at_startup() {
 639   if (ReduceSignalUsage) {
 640     return true;
 641   } else {
 642     return false;
 643   }




















 644 }
 645 
 646 // If the file .attach_pid<pid> exists in the working directory
 647 // or /tmp then this is the trigger to start the attach mechanism
 648 bool AttachListener::is_init_trigger() {
 649   if (init_at_startup() || is_initialized()) {
 650     return false;               // initialized at startup or already initialized
 651   }
 652   char fn[PATH_MAX + 1];
 653   int ret;
 654   struct stat64 st;
 655   sprintf(fn, ".attach_pid%d", os::current_process_id());
 656   RESTARTABLE(::stat64(fn, &st), ret);
 657   if (ret == -1) {
 658     log_trace(attach)("Failed to find attach file: %s, trying alternate", fn);
 659     snprintf(fn, sizeof(fn), "%s/.attach_pid%d",
 660              os::get_temp_directory(), os::current_process_id());
 661     RESTARTABLE(::stat64(fn, &st), ret);
 662     if (ret == -1) {
 663       log_debug(attach)("Failed to find attach file: %s", fn);


   1 /*
   2  * Copyright (c) 2005, 2019, 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  *


  58 // the result is returned via a UNIX domain socket. A pair of connected
  59 // sockets (socketpair) is created in the enqueue function and the file
  60 // descriptor for one of the sockets is returned to the client as the
  61 // return from the door call. The other end is retained in this process.
  62 // When the operation completes the result is sent to the client and
  63 // the socket is closed.
  64 
  65 // forward reference
  66 class SolarisAttachOperation;
  67 
  68 class SolarisAttachListener: AllStatic {
  69  private:
  70 
  71   // the path to which we attach the door file descriptor
  72   static char _door_path[PATH_MAX+1];
  73   static volatile bool _has_door_path;
  74 
  75   // door descriptor returned by door_create
  76   static int _door_descriptor;
  77 
  78   static bool _atexit_registered;










  79 
  80   // mutex to protect operation list
  81   static mutex_t _mutex;
  82 
  83   // semaphore to wakeup listener thread
  84   static sema_t _wakeup;
  85 
  86   static mutex_t* mutex()                               { return &_mutex; }
  87   static sema_t* wakeup()                               { return &_wakeup; }
  88 
  89   // enqueued operation list
  90   static SolarisAttachOperation* _head;
  91   static SolarisAttachOperation* _tail;
  92 
  93   static SolarisAttachOperation* head()                 { return _head; }
  94   static void set_head(SolarisAttachOperation* head)    { _head = head; }
  95 
  96   static SolarisAttachOperation* tail()                 { return _tail; }
  97   static void set_tail(SolarisAttachOperation* tail)    { _tail = tail; }
  98 
  99   // create the door
 100   static int create_door();
 101 
 102  public:
 103   enum {
 104     ATTACH_PROTOCOL_VER = 1                             // protocol version
 105   };
 106   enum {
 107     ATTACH_ERROR_BADREQUEST     = 100,                  // error code returned by
 108     ATTACH_ERROR_BADVERSION     = 101,                  // the door call
 109     ATTACH_ERROR_RESOURCE       = 102,
 110     ATTACH_ERROR_INTERNAL       = 103,
 111     ATTACH_ERROR_DENIED         = 104
 112   };
 113 
 114   static void set_door_path(char* path) {
 115     if (path == NULL) {
 116       _door_path[0] = '\0';
 117       _has_door_path = false;
 118     } else {
 119       strncpy(_door_path, path, PATH_MAX);
 120       _door_path[PATH_MAX] = '\0';      // ensure it's nul terminated
 121       _has_door_path = true;
 122     }
 123   }
 124 
 125   static void set_door_descriptor(int dd)               { _door_descriptor = dd; }
 126 
 127   // initialize the listener
 128   static int init();
 129 
 130   static bool has_door_path()                           { return _has_door_path; }
 131   static char* door_path()                              { return _door_path; }
 132   static int door_descriptor()                          { return _door_descriptor; }
 133 
 134   // enqueue an operation
 135   static void enqueue(SolarisAttachOperation* op);
 136 
 137   // dequeue an operation
 138   static SolarisAttachOperation* dequeue();
 139 };
 140 
 141 
 142 // SolarisAttachOperation is an AttachOperation that additionally encapsulates
 143 // a socket connection to the requesting client/tool. SolarisAttachOperation
 144 // can additionally be held in a linked list.
 145 
 146 class SolarisAttachOperation: public AttachOperation {


 155 
 156   SolarisAttachOperation* next()                         { return _next; }
 157   void set_next(SolarisAttachOperation* next)            { _next = next; }
 158 
 159  public:
 160   void complete(jint res, bufferedStream* st);
 161 
 162   int socket() const                                     { return _socket; }
 163   void set_socket(int s)                                 { _socket = s; }
 164 
 165   SolarisAttachOperation(char* name) : AttachOperation(name) {
 166     set_socket(-1);
 167     set_next(NULL);
 168   }
 169 };
 170 
 171 // statics
 172 char SolarisAttachListener::_door_path[PATH_MAX+1];
 173 volatile bool SolarisAttachListener::_has_door_path;
 174 int SolarisAttachListener::_door_descriptor = -1;
 175 bool SolarisAttachListener::_atexit_registered = false;
 176 mutex_t SolarisAttachListener::_mutex;
 177 sema_t SolarisAttachListener::_wakeup;
 178 SolarisAttachOperation* SolarisAttachListener::_head = NULL;
 179 SolarisAttachOperation* SolarisAttachListener::_tail = NULL;
 180 
 181 // Supporting class to help split a buffer into individual components
 182 class ArgumentIterator : public StackObj {
 183  private:
 184   char* _pos;
 185   char* _end;
 186  public:
 187   ArgumentIterator(char* arg_buffer, size_t arg_size) {
 188     _pos = arg_buffer;
 189     _end = _pos + arg_size - 1;
 190   }
 191   char* next() {
 192     if (*_pos == '\0') {
 193       // advance the iterator if possible (null arguments)
 194       if (_pos < _end) {
 195         _pos += 1;


 351       }
 352     }
 353 
 354     // Return 0 (success) + file descriptor, or non-0 (error)
 355     if (res == 0) {
 356       door_desc_t desc;
 357       // DOOR_RELEASE flag makes sure fd is closed after passing it to
 358       // the client.  See door_return(3DOOR) man page.
 359       desc.d_attributes = DOOR_DESCRIPTOR | DOOR_RELEASE;
 360       desc.d_data.d_desc.d_descriptor = return_fd;
 361       door_return((char*)&res, sizeof(res), &desc, 1);
 362     } else {
 363       door_return((char*)&res, sizeof(res), NULL, 0);
 364     }
 365   }
 366 }
 367 
 368 // atexit hook to detach the door and remove the file
 369 extern "C" {
 370   static void listener_cleanup() {



 371     int dd = SolarisAttachListener::door_descriptor();
 372     if (dd >= 0) {
 373       SolarisAttachListener::set_door_descriptor(-1);
 374       ::close(dd);
 375     }
 376     if (SolarisAttachListener::has_door_path()) {
 377       char* path = SolarisAttachListener::door_path();
 378       ::fdetach(path);
 379       ::unlink(path);
 380       SolarisAttachListener::set_door_path(NULL);
 381     }
 382   }
 383 }
 384 
 385 // Create the door
 386 int SolarisAttachListener::create_door() {
 387   char door_path[PATH_MAX+1];
 388   char initial_path[PATH_MAX+1];
 389   int fd, res;
 390 
 391   // register exit function
 392   if (!_atexit_registered) {
 393     _atexit_registered = true;
 394     ::atexit(listener_cleanup);
 395   }
 396 
 397   // create the door descriptor
 398   int dd = ::door_create(enqueue_proc, NULL, 0);
 399   if (dd < 0) {
 400     return -1;
 401   }
 402 
 403   // create initial file to attach door descriptor
 404   snprintf(door_path, sizeof(door_path), "%s/.java_pid%d",
 405            os::get_temp_directory(), os::current_process_id());
 406   snprintf(initial_path, sizeof(initial_path), "%s.tmp", door_path);
 407   RESTARTABLE(::creat(initial_path, S_IRUSR | S_IWUSR), fd);
 408   if (fd == -1) {
 409     log_debug(attach)("attempt to create door file %s failed (%d)", initial_path, errno);
 410     ::door_revoke(dd);
 411     return -1;
 412   }
 413   assert(fd >= 0, "bad file descriptor");
 414   ::close(fd);
 415 


 629   thread->set_suspend_equivalent();
 630   // cleared by handle_special_suspend_equivalent_condition() or
 631   // java_suspend_self()
 632 
 633   int ret_code = SolarisAttachListener::init();
 634 
 635   // were we externally suspended while we were waiting?
 636   thread->check_and_wait_while_suspended();
 637 
 638   return ret_code;
 639 }
 640 
 641 // Attach Listener is started lazily except in the case when
 642 // +ReduseSignalUsage is used
 643 bool AttachListener::init_at_startup() {
 644   if (ReduceSignalUsage) {
 645     return true;
 646   } else {
 647     return false;
 648   }
 649 }
 650 
 651 bool AttachListener::check_socket_file() {
 652   int ret;
 653   struct stat64 st;
 654   ret = stat64(SolarisAttachListener::door_path(), &st);
 655   if (ret == -1) { // need to restart attach listener.
 656     log_debug(attach)("Door file %s does not exist - Restart Attach Listener",
 657                       SolarisAttachListener::door_path());
 658 
 659     listener_cleanup();
 660 
 661     // wait to terminate current attach listener instance...
 662     while (AttachListener::transit_state(AL_INITIALIZING,
 663                                          AL_NOT_INITIALIZED) != AL_NOT_INITIALIZED) {
 664       os::naked_yield();
 665     }
 666     return is_init_trigger();
 667   }
 668   return false;
 669 }
 670 
 671 // If the file .attach_pid<pid> exists in the working directory
 672 // or /tmp then this is the trigger to start the attach mechanism
 673 bool AttachListener::is_init_trigger() {
 674   if (init_at_startup() || is_initialized()) {
 675     return false;               // initialized at startup or already initialized
 676   }
 677   char fn[PATH_MAX + 1];
 678   int ret;
 679   struct stat64 st;
 680   sprintf(fn, ".attach_pid%d", os::current_process_id());
 681   RESTARTABLE(::stat64(fn, &st), ret);
 682   if (ret == -1) {
 683     log_trace(attach)("Failed to find attach file: %s, trying alternate", fn);
 684     snprintf(fn, sizeof(fn), "%s/.attach_pid%d",
 685              os::get_temp_directory(), os::current_process_id());
 686     RESTARTABLE(::stat64(fn, &st), ret);
 687     if (ret == -1) {
 688       log_debug(attach)("Failed to find attach file: %s", fn);


< prev index next >