< prev index next >

src/hotspot/share/jfr/recorder/repository/jfrEmergencyDump.cpp

Print this page




  28 #include "jfr/leakprofiler/leakProfiler.hpp"
  29 #include "jfr/recorder/repository/jfrEmergencyDump.hpp"
  30 #include "jfr/recorder/service/jfrPostBox.hpp"
  31 #include "jfr/recorder/service/jfrRecorderService.hpp"
  32 #include "jfr/utilities/jfrTypes.hpp"
  33 #include "logging/log.hpp"
  34 #include "memory/resourceArea.hpp"
  35 #include "runtime/atomic.hpp"
  36 #include "runtime/handles.inline.hpp"
  37 #include "runtime/globals.hpp"
  38 #include "runtime/mutexLocker.hpp"
  39 #include "runtime/os.hpp"
  40 #include "runtime/thread.inline.hpp"
  41 #include "utilities/growableArray.hpp"
  42 
  43 static const char vm_error_filename_fmt[] = "hs_err_pid%p.jfr";
  44 static const char vm_oom_filename_fmt[] = "hs_oom_pid%p.jfr";
  45 static const char vm_soe_filename_fmt[] = "hs_soe_pid%p.jfr";
  46 static const char chunk_file_jfr_ext[] = ".jfr";
  47 static const size_t iso8601_len = 19; // "YYYY-MM-DDTHH:MM:SS"

  48 
  49 static fio_fd open_exclusivly(const char* path) {
  50   return os::open(path, O_CREAT | O_RDWR, S_IREAD | S_IWRITE);
  51 }
  52 
  53 static int file_sort(const char** const file1, const char** file2) {
  54   assert(NULL != *file1 && NULL != *file2, "invariant");
  55   int cmp = strncmp(*file1, *file2, iso8601_len);
  56   if (0 == cmp) {
  57     const char* const dot1 = strchr(*file1, '.');
  58     assert(NULL != dot1, "invariant");
  59     const char* const dot2 = strchr(*file2, '.');
  60     assert(NULL != dot2, "invariant");
  61     ptrdiff_t file1_len = dot1 - *file1;
  62     ptrdiff_t file2_len = dot2 - *file2;
  63     if (file1_len < file2_len) {
  64       return -1;
  65     }
  66     if (file1_len > file2_len) {
  67       return 1;


 195       const char* const entry_path = filter(dentry->d_name);
 196       if (NULL != entry_path) {
 197         _files->append(entry_path);
 198       }
 199     }
 200     os::closedir(dirp);
 201     if (_files->length() > 1) {
 202       _files->sort(file_sort);
 203     }
 204   }
 205 }
 206 
 207 bool RepositoryIterator::has_next() const {
 208   return (_files != NULL && _iterator < _files->length());
 209 }
 210 
 211 const char* const RepositoryIterator::next() const {
 212   return _iterator >= _files->length() ? NULL : fully_qualified(_files->at(_iterator++));
 213 }
 214 
 215 static void write_emergency_file(fio_fd emergency_fd, const RepositoryIterator& iterator) {
 216   assert(emergency_fd != invalid_fd, "invariant");
 217   const size_t size_of_file_copy_block = 1 * M; // 1 mb
 218   jbyte* const file_copy_block = NEW_RESOURCE_ARRAY_RETURN_NULL(jbyte, size_of_file_copy_block);
 219   if (file_copy_block == NULL) {
 220     return;
 221   }
 222   while (iterator.has_next()) {
 223     fio_fd current_fd = invalid_fd;
 224     const char* const fqn = iterator.next();
 225     if (fqn != NULL) {
 226       current_fd = open_exclusivly(fqn);
 227       if (current_fd != invalid_fd) {
 228         const int64_t current_filesize = file_size(current_fd);
 229         assert(current_filesize > 0, "invariant");
 230         int64_t bytes_read = 0;
 231         int64_t bytes_written = 0;
 232         while (bytes_read < current_filesize) {
 233           const ssize_t read_result = os::read_at(current_fd, file_copy_block, size_of_file_copy_block, bytes_read);
 234           if (-1 == read_result) {
 235             log_info(jfr)( // For user, should not be "jfr, system"
 236               "Unable to recover JFR data");
 237             break;
 238           }
 239           bytes_read += (int64_t)read_result;
 240           assert(bytes_read - bytes_written <= (int64_t)size_of_file_copy_block, "invariant");
 241           bytes_written += (int64_t)os::write(emergency_fd, file_copy_block, bytes_read - bytes_written);
 242           assert(bytes_read == bytes_written, "invariant");
 243         }
 244         os::close(current_fd);
 245       }
 246     }
 247   }
 248 }
 249 
 250 static const char* create_emergency_dump_path() {
 251   char* buffer = NEW_RESOURCE_ARRAY_RETURN_NULL(char, JVM_MAXPATHLEN);
 252   if (NULL == buffer) {
 253     return NULL;
 254   }
 255   const char* const cwd = os::get_current_directory(buffer, JVM_MAXPATHLEN);
 256   if (NULL == cwd) {
 257     return NULL;
 258   }
 259   size_t pos = strlen(cwd);
 260   const int fsep_len = jio_snprintf(&buffer[pos], JVM_MAXPATHLEN - pos, "%s", os::file_separator());
 261   const char* filename_fmt = NULL;
 262   // fetch specific error cause
 263   switch (JfrJavaSupport::cause()) {
 264     case JfrJavaSupport::OUT_OF_MEMORY:
 265       filename_fmt = vm_oom_filename_fmt;
 266       break;
 267     case JfrJavaSupport::STACK_OVERFLOW:
 268       filename_fmt = vm_soe_filename_fmt;
 269       break;
 270     default:
 271       filename_fmt = vm_error_filename_fmt;
 272   }
 273   char* emergency_dump_path = NULL;
 274   pos += fsep_len;
 275   if (Arguments::copy_expand_pid(filename_fmt, strlen(filename_fmt), &buffer[pos], JVM_MAXPATHLEN - pos)) {
 276     const size_t emergency_filename_length = strlen(buffer);
 277     emergency_dump_path = NEW_RESOURCE_ARRAY_RETURN_NULL(char, emergency_filename_length + 1);
 278     if (NULL == emergency_dump_path) {
 279       return NULL;
 280     }
 281     strncpy(emergency_dump_path, buffer, emergency_filename_length + 1);
 282   }
 283   if (emergency_dump_path != NULL) {
 284     log_info(jfr)( // For user, should not be "jfr, system"
 285       "Attempting to recover JFR data, emergency jfr file: %s", emergency_dump_path);
 286   }
 287   return emergency_dump_path;
 288 }
 289 
 290 // Caller needs ResourceMark
 291 static const char* create_emergency_chunk_path(const char* repository_path) {
 292   assert(repository_path != NULL, "invariant");
 293   const size_t repository_path_len = strlen(repository_path);
 294   // date time
 295   char date_time_buffer[32] = { 0 };
 296   date_time(date_time_buffer, sizeof(date_time_buffer));
 297   size_t date_time_len = strlen(date_time_buffer);
 298   size_t chunkname_max_len = repository_path_len          // repository_base_path
 299                              + 1                          // "/"
 300                              + date_time_len              // date_time
 301                              + strlen(chunk_file_jfr_ext) // .jfr
 302                              + 1;
 303   char* chunk_path = NEW_RESOURCE_ARRAY_RETURN_NULL(char, chunkname_max_len);
 304   if (chunk_path == NULL) {
 305     return NULL;
 306   }
 307   // append the individual substrings
 308   jio_snprintf(chunk_path, chunkname_max_len, "%s%s%s%s", repository_path, os::file_separator(), date_time_buffer, chunk_file_jfr_ext);
 309   return chunk_path;
 310 }
 311 
 312 static fio_fd emergency_dump_file_descriptor() {
 313   ResourceMark rm;
 314   const char* const emergency_dump_path = create_emergency_dump_path();
 315   return emergency_dump_path != NULL ? open_exclusivly(emergency_dump_path) : invalid_fd;

 316 }
 317 

 318 const char* JfrEmergencyDump::build_dump_path(const char* repository_path) {
 319   return repository_path == NULL ? create_emergency_dump_path() : create_emergency_chunk_path(repository_path);









 320 }
 321 
 322 void JfrEmergencyDump::on_vm_error(const char* repository_path) {
 323   assert(repository_path != NULL, "invariant");
 324   ResourceMark rm;
 325   const fio_fd emergency_fd = emergency_dump_file_descriptor();
 326   if (emergency_fd != invalid_fd) {
 327     RepositoryIterator iterator(repository_path, strlen(repository_path));
 328     write_emergency_file(emergency_fd, iterator);
 329     os::close(emergency_fd);

 330   }
 331 }
 332 
 333 /*
 334 * We are just about to exit the VM, so we will be very aggressive
 335 * at this point in order to increase overall success of dumping jfr data.
 336 *
 337 * If we end up deadlocking in the attempt of dumping out jfr data,
 338 * we rely on the WatcherThread task "is_error_reported()",
 339 * to exit the VM after a hard-coded timeout (disallow WatcherThread to emergency dump).
 340 * This "safety net" somewhat explains the aggressiveness in this attempt.
 341 *
 342 */
 343 static bool prepare_for_emergency_dump(Thread* thread) {
 344   assert(thread != NULL, "invariant");
 345 
 346   if (thread->is_Watcher_thread()) {
 347     // need WatcherThread as a safeguard against potential deadlocks
 348     return false;
 349   }




  28 #include "jfr/leakprofiler/leakProfiler.hpp"
  29 #include "jfr/recorder/repository/jfrEmergencyDump.hpp"
  30 #include "jfr/recorder/service/jfrPostBox.hpp"
  31 #include "jfr/recorder/service/jfrRecorderService.hpp"
  32 #include "jfr/utilities/jfrTypes.hpp"
  33 #include "logging/log.hpp"
  34 #include "memory/resourceArea.hpp"
  35 #include "runtime/atomic.hpp"
  36 #include "runtime/handles.inline.hpp"
  37 #include "runtime/globals.hpp"
  38 #include "runtime/mutexLocker.hpp"
  39 #include "runtime/os.hpp"
  40 #include "runtime/thread.inline.hpp"
  41 #include "utilities/growableArray.hpp"
  42 
  43 static const char vm_error_filename_fmt[] = "hs_err_pid%p.jfr";
  44 static const char vm_oom_filename_fmt[] = "hs_oom_pid%p.jfr";
  45 static const char vm_soe_filename_fmt[] = "hs_soe_pid%p.jfr";
  46 static const char chunk_file_jfr_ext[] = ".jfr";
  47 static const size_t iso8601_len = 19; // "YYYY-MM-DDTHH:MM:SS"
  48 static fio_fd emergency_fd = invalid_fd;
  49 
  50 static fio_fd open_exclusivly(const char* path) {
  51   return os::open(path, O_CREAT | O_RDWR, S_IREAD | S_IWRITE);
  52 }
  53 
  54 static int file_sort(const char** const file1, const char** file2) {
  55   assert(NULL != *file1 && NULL != *file2, "invariant");
  56   int cmp = strncmp(*file1, *file2, iso8601_len);
  57   if (0 == cmp) {
  58     const char* const dot1 = strchr(*file1, '.');
  59     assert(NULL != dot1, "invariant");
  60     const char* const dot2 = strchr(*file2, '.');
  61     assert(NULL != dot2, "invariant");
  62     ptrdiff_t file1_len = dot1 - *file1;
  63     ptrdiff_t file2_len = dot2 - *file2;
  64     if (file1_len < file2_len) {
  65       return -1;
  66     }
  67     if (file1_len > file2_len) {
  68       return 1;


 196       const char* const entry_path = filter(dentry->d_name);
 197       if (NULL != entry_path) {
 198         _files->append(entry_path);
 199       }
 200     }
 201     os::closedir(dirp);
 202     if (_files->length() > 1) {
 203       _files->sort(file_sort);
 204     }
 205   }
 206 }
 207 
 208 bool RepositoryIterator::has_next() const {
 209   return (_files != NULL && _iterator < _files->length());
 210 }
 211 
 212 const char* const RepositoryIterator::next() const {
 213   return _iterator >= _files->length() ? NULL : fully_qualified(_files->at(_iterator++));
 214 }
 215 
 216 static void write_emergency_file(const RepositoryIterator& iterator) {
 217   assert(emergency_fd != invalid_fd, "invariant");
 218   const size_t size_of_file_copy_block = 1 * M; // 1 mb
 219   jbyte* const file_copy_block = NEW_RESOURCE_ARRAY_RETURN_NULL(jbyte, size_of_file_copy_block);
 220   if (file_copy_block == NULL) {
 221     return;
 222   }
 223   while (iterator.has_next()) {
 224     fio_fd current_fd = invalid_fd;
 225     const char* const fqn = iterator.next();
 226     if (fqn != NULL) {
 227       current_fd = open_exclusivly(fqn);
 228       if (current_fd != invalid_fd) {
 229         const int64_t current_filesize = file_size(current_fd);
 230         assert(current_filesize > 0, "invariant");
 231         int64_t bytes_read = 0;
 232         int64_t bytes_written = 0;
 233         while (bytes_read < current_filesize) {
 234           const ssize_t read_result = os::read_at(current_fd, file_copy_block, size_of_file_copy_block, bytes_read);
 235           if (-1 == read_result) {
 236             log_info(jfr)( // For user, should not be "jfr, system"
 237               "Unable to recover JFR data");
 238             break;
 239           }
 240           bytes_read += (int64_t)read_result;
 241           assert(bytes_read - bytes_written <= (int64_t)size_of_file_copy_block, "invariant");
 242           bytes_written += (int64_t)os::write(emergency_fd, file_copy_block, bytes_read - bytes_written);
 243           assert(bytes_read == bytes_written, "invariant");
 244         }
 245         os::close(current_fd);
 246       }
 247     }
 248   }
 249 }
 250 
 251 // "emergency_dump_path" have to be allocated JVM_MAXPATHLEN or larger.
 252 static void create_emergency_dump_path(char* emergency_dump_path) {
 253   char buffer[JVM_MAXPATHLEN];
 254   emergency_dump_path[0] = '\0';

 255   const char* const cwd = os::get_current_directory(buffer, JVM_MAXPATHLEN);
 256   if (NULL == cwd) {
 257     return;
 258   }
 259   size_t pos = strlen(cwd);
 260   const int fsep_len = jio_snprintf(&buffer[pos], JVM_MAXPATHLEN - pos, "%s", os::file_separator());
 261   const char* filename_fmt = NULL;
 262   // fetch specific error cause
 263   switch (JfrJavaSupport::cause()) {
 264     case JfrJavaSupport::OUT_OF_MEMORY:
 265       filename_fmt = vm_oom_filename_fmt;
 266       break;
 267     case JfrJavaSupport::STACK_OVERFLOW:
 268       filename_fmt = vm_soe_filename_fmt;
 269       break;
 270     default:
 271       filename_fmt = vm_error_filename_fmt;
 272   }

 273   pos += fsep_len;
 274   if (Arguments::copy_expand_pid(filename_fmt, strlen(filename_fmt), &buffer[pos], JVM_MAXPATHLEN - pos)) {
 275     strncpy(emergency_dump_path, buffer, JVM_MAXPATHLEN);





 276   }
 277   if (emergency_dump_path[0] != '\0') {
 278     log_info(jfr)( // For user, should not be "jfr, system"
 279       "Attempting to recover JFR data, emergency jfr file: %s", emergency_dump_path);
 280   }

 281 }
 282 
 283 // Caller needs ResourceMark
 284 static const char* create_emergency_chunk_path(const char* repository_path) {
 285   assert(repository_path != NULL, "invariant");
 286   const size_t repository_path_len = strlen(repository_path);
 287   // date time
 288   char date_time_buffer[32] = { 0 };
 289   date_time(date_time_buffer, sizeof(date_time_buffer));
 290   size_t date_time_len = strlen(date_time_buffer);
 291   size_t chunkname_max_len = repository_path_len          // repository_base_path
 292                              + 1                          // "/"
 293                              + date_time_len              // date_time
 294                              + strlen(chunk_file_jfr_ext) // .jfr
 295                              + 1;
 296   char* chunk_path = NEW_RESOURCE_ARRAY_RETURN_NULL(char, chunkname_max_len);
 297   if (chunk_path == NULL) {
 298     return NULL;
 299   }
 300   // append the individual substrings
 301   jio_snprintf(chunk_path, chunkname_max_len, "%s%s%s%s", repository_path, os::file_separator(), date_time_buffer, chunk_file_jfr_ext);
 302   return chunk_path;
 303 }
 304 
 305 void JfrEmergencyDump::setup_emergency_dump_file_descriptor() {
 306   assert(emergency_fd == invalid_fd, "invariant");
 307   char emergency_dump_path[JVM_MAXPATHLEN];
 308   create_emergency_dump_path(emergency_dump_path);
 309   emergency_fd = (emergency_dump_path[0] != '\0') ? open_exclusivly(emergency_dump_path) : invalid_fd;
 310 }
 311 
 312 // Caller needs ResourceMark
 313 const char* JfrEmergencyDump::build_dump_path(const char* repository_path) {
 314   if (repository_path == NULL) {
 315     char* dump_path = NEW_RESOURCE_ARRAY_RETURN_NULL(char, JVM_MAXPATHLEN);
 316     if (dump_path == NULL) {
 317       return NULL;
 318     }
 319     create_emergency_dump_path(dump_path);
 320     return dump_path;
 321   } else {
 322     return create_emergency_chunk_path(repository_path);
 323   }
 324 }
 325 
 326 void JfrEmergencyDump::on_vm_error(const char* repository_path) {
 327   assert(repository_path != NULL, "invariant");
 328   ResourceMark rm;

 329   if (emergency_fd != invalid_fd) {
 330     RepositoryIterator iterator(repository_path, strlen(repository_path));
 331     write_emergency_file(iterator);
 332     os::close(emergency_fd);
 333     emergency_fd = invalid_fd;
 334   }
 335 }
 336 
 337 /*
 338 * We are just about to exit the VM, so we will be very aggressive
 339 * at this point in order to increase overall success of dumping jfr data.
 340 *
 341 * If we end up deadlocking in the attempt of dumping out jfr data,
 342 * we rely on the WatcherThread task "is_error_reported()",
 343 * to exit the VM after a hard-coded timeout (disallow WatcherThread to emergency dump).
 344 * This "safety net" somewhat explains the aggressiveness in this attempt.
 345 *
 346 */
 347 static bool prepare_for_emergency_dump(Thread* thread) {
 348   assert(thread != NULL, "invariant");
 349 
 350   if (thread->is_Watcher_thread()) {
 351     // need WatcherThread as a safeguard against potential deadlocks
 352     return false;
 353   }


< prev index next >