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; 68 } 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 | 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 char JfrEmergencyDump::_dump_path[JVM_MAXPATHLEN] = {0}; 50 51 static fio_fd open_exclusivly(const char* path) { 52 return os::open(path, O_CREAT | O_RDWR, S_IREAD | S_IWRITE); 53 } 54 55 static int file_sort(const char** const file1, const char** file2) { 56 assert(NULL != *file1 && NULL != *file2, "invariant"); 57 int cmp = strncmp(*file1, *file2, iso8601_len); 58 if (0 == cmp) { 59 const char* const dot1 = strchr(*file1, '.'); 60 assert(NULL != dot1, "invariant"); 61 const char* const dot2 = strchr(*file2, '.'); 62 assert(NULL != dot2, "invariant"); 63 ptrdiff_t file1_len = dot1 - *file1; 64 ptrdiff_t file2_len = dot2 - *file2; 65 if (file1_len < file2_len) { 66 return -1; 67 } 68 if (file1_len > file2_len) { 69 return 1; 70 } 232 int64_t bytes_read = 0; 233 int64_t bytes_written = 0; 234 while (bytes_read < current_filesize) { 235 const ssize_t read_result = os::read_at(current_fd, file_copy_block, size_of_file_copy_block, bytes_read); 236 if (-1 == read_result) { 237 log_info(jfr)( // For user, should not be "jfr, system" 238 "Unable to recover JFR data"); 239 break; 240 } 241 bytes_read += (int64_t)read_result; 242 assert(bytes_read - bytes_written <= (int64_t)size_of_file_copy_block, "invariant"); 243 bytes_written += (int64_t)os::write(emergency_fd, file_copy_block, bytes_read - bytes_written); 244 assert(bytes_read == bytes_written, "invariant"); 245 } 246 os::close(current_fd); 247 } 248 } 249 } 250 } 251 252 const char* JfrEmergencyDump::create_emergency_dump_path() { 253 if (*_dump_path != '\0') { 254 return _dump_path; 255 } 256 257 const char* const cwd = os::get_current_directory(_dump_path, JVM_MAXPATHLEN); 258 if (NULL == cwd) { 259 return NULL; 260 } 261 size_t pos = strlen(cwd); 262 const int fsep_len = jio_snprintf(&_dump_path[pos], JVM_MAXPATHLEN - pos, "%s", os::file_separator()); 263 const char* filename_fmt = NULL; 264 // fetch specific error cause 265 switch (JfrJavaSupport::cause()) { 266 case JfrJavaSupport::OUT_OF_MEMORY: 267 filename_fmt = vm_oom_filename_fmt; 268 break; 269 case JfrJavaSupport::STACK_OVERFLOW: 270 filename_fmt = vm_soe_filename_fmt; 271 break; 272 default: 273 filename_fmt = vm_error_filename_fmt; 274 } 275 pos += fsep_len; 276 Arguments::copy_expand_pid(filename_fmt, strlen(filename_fmt), &_dump_path[pos], JVM_MAXPATHLEN - pos); 277 if (*_dump_path != '\0') { 278 log_info(jfr)( // For user, should not be "jfr, system" 279 "Attempting to recover JFR data, emergency jfr file: %s", _dump_path); 280 } 281 return _dump_path; 282 } 283 284 // Caller needs ResourceMark 285 const char* JfrEmergencyDump::create_emergency_chunk_path(const char* repository_path) { 286 assert(repository_path != NULL, "invariant"); 287 288 if (*_dump_path != '\0') { 289 return _dump_path; 290 } 291 292 const size_t repository_path_len = strlen(repository_path); 293 // date time 294 char date_time_buffer[32] = { 0 }; 295 date_time(date_time_buffer, sizeof(date_time_buffer)); 296 size_t date_time_len = strlen(date_time_buffer); 297 size_t chunkname_max_len = repository_path_len // repository_base_path 298 + 1 // "/" 299 + date_time_len // date_time 300 + strlen(chunk_file_jfr_ext) // .jfr 301 + 1; 302 // append the individual substrings 303 jio_snprintf(_dump_path, chunkname_max_len, "%s%s%s%s", repository_path, os::file_separator(), date_time_buffer, chunk_file_jfr_ext); 304 return _dump_path; 305 } 306 307 fio_fd JfrEmergencyDump::emergency_dump_file_descriptor() { 308 ResourceMark rm; 309 const char* const emergency_dump_path = create_emergency_dump_path(); 310 return emergency_dump_path != NULL ? open_exclusivly(emergency_dump_path) : invalid_fd; 311 } 312 313 const char* JfrEmergencyDump::build_dump_path(const char* repository_path) { 314 return repository_path == NULL ? create_emergency_dump_path() : create_emergency_chunk_path(repository_path); 315 } 316 317 void JfrEmergencyDump::on_vm_error(const char* repository_path) { 318 assert(repository_path != NULL, "invariant"); 319 ResourceMark rm; 320 const fio_fd emergency_fd = emergency_dump_file_descriptor(); 321 if (emergency_fd != invalid_fd) { 322 RepositoryIterator iterator(repository_path, strlen(repository_path)); 323 write_emergency_file(emergency_fd, iterator); 324 os::close(emergency_fd); 325 } 326 } 327 |