325 assert(rm == NULL || Thread::current()->current_resource_mark() == rm,
326 "stringStream is re-allocated with a different ResourceMark");
327 buffer = NEW_RESOURCE_ARRAY(char, end);
328 strncpy(buffer, oldbuf, buffer_pos);
329 buffer_length = end;
330 }
331 }
332 // invariant: buffer is always null-terminated
333 guarantee(buffer_pos + write_len + 1 <= buffer_length, "stringStream oob");
334 buffer[buffer_pos + write_len] = 0;
335 strncpy(buffer + buffer_pos, s, write_len);
336 buffer_pos += write_len;
337
338 // Note that the following does not depend on write_len.
339 // This means that position and count get updated
340 // even when overflow occurs.
341 update_position(s, len);
342 }
343
344 char* stringStream::as_string() {
345 char* copy = NEW_RESOURCE_ARRAY(char, buffer_pos+1);
346 strncpy(copy, buffer, buffer_pos);
347 copy[buffer_pos] = 0; // terminating null
348 return copy;
349 }
350
351 stringStream::~stringStream() {}
352
353 xmlStream* xtty;
354 outputStream* tty;
355 outputStream* gclog_or_tty;
356 extern Mutex* tty_lock;
357
358 fileStream::fileStream(const char* file_name) {
359 _file = fopen(file_name, "w");
360 _need_close = true;
361 }
362
363 fileStream::fileStream(const char* file_name, const char* opentype) {
364 _file = fopen(file_name, opentype);
365 _need_close = true;
366 }
367
368 void fileStream::write(const char* s, size_t len) {
369 if (_file != NULL) {
370 // Make an unused local variable to avoid warning from gcc 4.x compiler.
371 size_t count = fwrite(s, 1, len, _file);
372 }
373 update_position(s, len);
374 }
375
376 long fileStream::fileSize() {
377 long size = -1;
378 if (_file != NULL) {
379 long pos = ::ftell(_file);
380 if (::fseek(_file, 0, SEEK_END) == 0) {
381 size = ::ftell(_file);
382 }
383 ::fseek(_file, pos, SEEK_SET);
384 }
385 return size;
410
411 fdStream::~fdStream() {
412 if (_fd != -1) {
413 if (_need_close) close(_fd);
414 _fd = -1;
415 }
416 }
417
418 void fdStream::write(const char* s, size_t len) {
419 if (_fd != -1) {
420 // Make an unused local variable to avoid warning from gcc 4.x compiler.
421 size_t count = ::write(_fd, s, (int)len);
422 }
423 update_position(s, len);
424 }
425
426 rotatingFileStream::~rotatingFileStream() {
427 if (_file != NULL) {
428 if (_need_close) fclose(_file);
429 _file = NULL;
430 FREE_C_HEAP_ARRAY(char, _file_name, mtInternal);
431 _file_name = NULL;
432 }
433 }
434
435 rotatingFileStream::rotatingFileStream(const char* file_name) {
436 _cur_file_num = 0;
437 _bytes_written = 0L;
438 _file_name = NEW_C_HEAP_ARRAY(char, strlen(file_name)+10, mtInternal);
439 jio_snprintf(_file_name, strlen(file_name)+10, "%s.%d", file_name, _cur_file_num);
440 _file = fopen(_file_name, "w");
441 _need_close = true;
442 }
443
444 rotatingFileStream::rotatingFileStream(const char* file_name, const char* opentype) {
445 _cur_file_num = 0;
446 _bytes_written = 0L;
447 _file_name = NEW_C_HEAP_ARRAY(char, strlen(file_name)+10, mtInternal);
448 jio_snprintf(_file_name, strlen(file_name)+10, "%s.%d", file_name, _cur_file_num);
449 _file = fopen(_file_name, opentype);
450 _need_close = true;
451 }
452
453 void rotatingFileStream::write(const char* s, size_t len) {
454 if (_file != NULL) {
455 size_t count = fwrite(s, 1, len, _file);
456 _bytes_written += count;
457 }
458 update_position(s, len);
459 }
460
461 // rotate_log must be called from VMThread at safepoint. In case need change parameters
462 // for gc log rotation from thread other than VMThread, a sub type of VM_Operation
463 // should be created and be submitted to VMThread's operation queue. DO NOT call this
464 // function directly. Currently, it is safe to rotate log at safepoint through VMThread.
465 // That is, no mutator threads and concurrent GC threads run parallel with VMThread to
466 // write to gc log file at safepoint. If in future, changes made for mutator threads or
467 // concurrent GC threads to run parallel with VMThread at safepoint, write and rotate_log
468 // must be synchronized.
469 void rotatingFileStream::rotate_log() {
470 if (_bytes_written < (jlong)GCLogFileSize) {
471 return;
472 }
473
474 #ifdef ASSERT
475 Thread *thread = Thread::current();
476 assert(thread == NULL ||
477 (thread->is_VM_thread() && SafepointSynchronize::is_at_safepoint()),
478 "Must be VMThread at safepoint");
479 #endif
480 if (NumberOfGCLogFiles == 1) {
481 // rotate in same file
482 rewind();
483 _bytes_written = 0L;
484 return;
485 }
486
487 // rotate file in names file.0, file.1, file.2, ..., file.<MaxGCLogFileNumbers-1>
488 // close current file, rotate to next file
489 if (_file != NULL) {
490 _cur_file_num ++;
491 if (_cur_file_num >= NumberOfGCLogFiles) _cur_file_num = 0;
492 jio_snprintf(_file_name, strlen(Arguments::gc_log_filename()) + 10, "%s.%d",
493 Arguments::gc_log_filename(), _cur_file_num);
494 fclose(_file);
495 _file = NULL;
496 }
497 _file = fopen(_file_name, "w");
498 if (_file != NULL) {
499 _bytes_written = 0L;
500 _need_close = true;
501 } else {
502 tty->print_cr("failed to open rotation log file %s due to %s\n",
503 _file_name, strerror(errno));
504 _need_close = false;
505 }
506 }
507
508 defaultStream* defaultStream::instance = NULL;
509 int defaultStream::_output_fd = 1;
510 int defaultStream::_error_fd = 2;
511 FILE* defaultStream::_output_stream = stdout;
512 FILE* defaultStream::_error_stream = stderr;
513
514 #define LOG_MAJOR_VERSION 160
515 #define LOG_MINOR_VERSION 1
516
517 void defaultStream::init() {
518 _inited = true;
519 if (LogVMOutput || LogCompilation) {
520 init_log();
521 }
522 }
523
524 bool defaultStream::has_log_file() {
|
325 assert(rm == NULL || Thread::current()->current_resource_mark() == rm,
326 "stringStream is re-allocated with a different ResourceMark");
327 buffer = NEW_RESOURCE_ARRAY(char, end);
328 strncpy(buffer, oldbuf, buffer_pos);
329 buffer_length = end;
330 }
331 }
332 // invariant: buffer is always null-terminated
333 guarantee(buffer_pos + write_len + 1 <= buffer_length, "stringStream oob");
334 buffer[buffer_pos + write_len] = 0;
335 strncpy(buffer + buffer_pos, s, write_len);
336 buffer_pos += write_len;
337
338 // Note that the following does not depend on write_len.
339 // This means that position and count get updated
340 // even when overflow occurs.
341 update_position(s, len);
342 }
343
344 char* stringStream::as_string() {
345 char* copy = NEW_RESOURCE_ARRAY(char, buffer_pos + 1);
346 strncpy(copy, buffer, buffer_pos);
347 copy[buffer_pos] = 0; // terminating null
348 return copy;
349 }
350
351 stringStream::~stringStream() {}
352
353 xmlStream* xtty;
354 outputStream* tty;
355 outputStream* gclog_or_tty;
356 extern Mutex* tty_lock;
357
358 #define EXTRACHARLEN 32
359 #define CURRENTAPPX ".current"
360 #define FILENAMEBUFLEN 1024
361 // convert YYYY-MM-DD HH:MM:SS to YYYY-MM-DD_HH-MM-SS
362 char* get_datetime_string(char *buf, size_t len) {
363 os::local_time_string(buf, len);
364 int i = strlen(buf);
365 while (i-- >= 0) {
366 if (buf[i] == ' ') buf[i] = '_';
367 else if (buf[i] == ':') buf[i] = '-';
368 }
369 return buf;
370 }
371
372 char* extend_file_name(const char* file_name) {
373 char* extended_name = NULL;
374 char timestr[EXTRACHARLEN];
375 char pidtext[EXTRACHARLEN];
376 const char* spp = strstr(file_name, "%p");
377 const char* spt = strstr(file_name, "%t");
378 int pp = (spp != NULL) ? spp - file_name : -1;
379 int pt = (spt != NULL) ? spt - file_name : -1;
380
381 if (pp < 0 && pt < 0) {
382 extended_name = NEW_C_HEAP_ARRAY(char, strlen(file_name) + 1, mtInternal);
383 strcpy(extended_name, file_name);
384 return extended_name;
385 }
386
387 if (pp > 0) {
388 jio_snprintf(pidtext, sizeof(pidtext), "pid%d", os::current_process_id());
389 } else {
390 pidtext[0] = '\0';
391 }
392
393 if (pt > 0) {
394 get_datetime_string(timestr, sizeof(timestr));
395 } else {
396 timestr[0] = '\0';
397 }
398
399 size_t len = strlen(file_name) + strlen(pidtext) + strlen(timestr) + 2 * EXTRACHARLEN;
400 extended_name = NEW_C_HEAP_ARRAY(char, len, mtInternal);
401 if (pp > 0 && pt > 0 ) {
402 // *%p*%t*
403 if (pp < pt) {
404 memcpy(extended_name, file_name, (size_t)pp);
405 extended_name[pp] = '\0';
406 strcat(extended_name, pidtext);
407 size_t t_len = strlen(extended_name);
408 if (pt - pp > 2) {
409 memcpy(extended_name + t_len, file_name + pp + 2, pt - pp - 2);
410 extended_name[t_len + pt - pp - 2] = '\0';
411 }
412 strcat(extended_name, timestr);
413 strcat(extended_name, file_name + pt + 2);
414 // *%t*%p*
415 } else {
416 memcpy(extended_name, file_name, (size_t)(pt));
417 extended_name[pt] = '\0';
418 strcat(extended_name, timestr);
419 size_t t_len = strlen(extended_name);
420 if (pp - pt > 2) {
421 memcpy(extended_name + t_len, file_name + pt + 2, pp - pt - 2);
422 extended_name[t_len + pp - pt - 2] = '\0';
423 }
424 strcat(extended_name, pidtext);
425 strcat(extended_name, file_name + pp + 2);
426 }
427 return extended_name;
428 }
429
430 if (pp > 0) {
431 // only requested pid
432 memcpy(extended_name, file_name, (size_t)pp);
433 extended_name[pp] = '\0';
434 strcat(extended_name, pidtext);
435 strcat(extended_name, file_name + pp + 2);
436 }
437
438 if (pt > 0) {
439 // only requested timestamp
440 memcpy(extended_name, file_name, (size_t)pt);
441 extended_name[pt] = '\0';
442 strcat(extended_name, timestr);
443 strcat(extended_name, file_name + pt + 2);
444 }
445 return extended_name;
446 }
447
448 // log vm version, os verison, platform info, build id,
449 // memory usage and command line flags into head of fileStream
450 void fileStream::dump_loggc_header() {
451 if(is_open()) {
452 this->print_cr(Abstract_VM_Version::internal_vm_info_string());
453 os::print_memory_info(this);
454 this->print("CommandLine flags: ");
455 CommandLineFlags::printSetFlags(this);
456 }
457 }
458
459 fileStream::fileStream(const char* file_name) {
460 char* f_name = extend_file_name(file_name);
461 _file = fopen(f_name, "w");
462 _need_close = true;
463 FREE_C_HEAP_ARRAY(char, f_name, mtInternal);
464 dump_loggc_header();
465 }
466
467 fileStream::fileStream(const char* file_name, const char* opentype) {
468 char* f_name = extend_file_name(file_name);
469 _file = fopen(f_name, opentype);
470 _need_close = true;
471 FREE_C_HEAP_ARRAY(char, f_name, mtInternal);
472 dump_loggc_header();
473 }
474
475 void fileStream::write(const char* s, size_t len) {
476 if (_file != NULL) {
477 // Make an unused local variable to avoid warning from gcc 4.x compiler.
478 size_t count = fwrite(s, 1, len, _file);
479 }
480 update_position(s, len);
481 }
482
483 long fileStream::fileSize() {
484 long size = -1;
485 if (_file != NULL) {
486 long pos = ::ftell(_file);
487 if (::fseek(_file, 0, SEEK_END) == 0) {
488 size = ::ftell(_file);
489 }
490 ::fseek(_file, pos, SEEK_SET);
491 }
492 return size;
517
518 fdStream::~fdStream() {
519 if (_fd != -1) {
520 if (_need_close) close(_fd);
521 _fd = -1;
522 }
523 }
524
525 void fdStream::write(const char* s, size_t len) {
526 if (_fd != -1) {
527 // Make an unused local variable to avoid warning from gcc 4.x compiler.
528 size_t count = ::write(_fd, s, (int)len);
529 }
530 update_position(s, len);
531 }
532
533 rotatingFileStream::~rotatingFileStream() {
534 if (_file != NULL) {
535 if (_need_close) fclose(_file);
536 _file = NULL;
537 }
538 if (_file_name != NULL) {
539 FREE_C_HEAP_ARRAY(char, _file_name, mtInternal);
540 _file_name = NULL;
541 }
542 }
543
544 rotatingFileStream::rotatingFileStream(const char* file_name) {
545 assert(UseGCLogFileRotation, "Should use UseGCLogFileRotation");
546 _cur_file_num = 0;
547 _bytes_written = 0L;
548 _file_name = extend_file_name(file_name);
549
550 if (NumberOfGCLogFiles > 1) {
551 char tempbuf[FILENAMEBUFLEN];
552 jio_snprintf(tempbuf, sizeof(tempbuf), "%s.%d" CURRENTAPPX, _file_name, _cur_file_num);
553 _file = fopen(tempbuf, "w");
554 } else {
555 _file = fopen(_file_name, "w");
556 }
557 _need_close = true;
558 dump_loggc_header();
559 }
560
561 void rotatingFileStream::write(const char* s, size_t len) {
562 if (_file != NULL) {
563 size_t count = fwrite(s, 1, len, _file);
564 _bytes_written += count;
565 }
566 update_position(s, len);
567 }
568
569 // rotate_log must be called from VMThread at safepoint. In case need change parameters
570 // for gc log rotation from thread other than VMThread, a sub type of VM_Operation
571 // should be created and be submitted to VMThread's operation queue. DO NOT call this
572 // function directly. Currently, it is safe to rotate log at safepoint through VMThread.
573 // That is, no mutator threads and concurrent GC threads run parallel with VMThread to
574 // write to gc log file at safepoint. If in future, changes made for mutator threads or
575 // concurrent GC threads to run parallel with VMThread at safepoint, write and rotate_log
576 // must be synchronized.
577 void rotatingFileStream::rotate_log() {
578 char time_msg[FILENAMEBUFLEN];
579 char time_str[EXTRACHARLEN];
580 char current_file_name[FILENAMEBUFLEN];
581 char renamed_file_name[FILENAMEBUFLEN];
582
583 if (_bytes_written < (jlong)GCLogFileSize) {
584 return;
585 }
586
587 #ifdef ASSERT
588 Thread *thread = Thread::current();
589 assert(thread == NULL ||
590 (thread->is_VM_thread() && SafepointSynchronize::is_at_safepoint()),
591 "Must be VMThread at safepoint");
592 #endif
593 if (NumberOfGCLogFiles == 1) {
594 // rotate in same file
595 rewind();
596 _bytes_written = 0L;
597 jio_snprintf(time_msg, sizeof(time_msg), "File %s rotated at %s\n",
598 _file_name, os::local_time_string((char *)time_str, sizeof(time_str)));
599 this->write(time_msg, strlen(time_msg));
600 dump_loggc_header();
601 return;
602 }
603
604 #if defined(_WINDOWS)
605 #ifndef F_OK
606 #define F_OK 0
607 #endif
608 #endif // _WINDOWS
609
610 // rotate file in names extended_filename.0, extended_filename.1, ...,
611 // extended_filename.<NumberOfGCLogFiles - 1>. Current rotation file name will
612 // have a form of extended_filename.<i>.current where i is the current rotation
613 // file number. After it reaches max file size, the file will be saved and renamed
614 // with .current removed from its tail.
615 size_t filename_len = strlen(_file_name);
616 if (_file != NULL) {
617 jio_snprintf(renamed_file_name, filename_len + EXTRACHARLEN, "%s.%d",
618 _file_name, _cur_file_num);
619 jio_snprintf(current_file_name, filename_len + EXTRACHARLEN, "%s.%d" CURRENTAPPX,
620 _file_name, _cur_file_num);
621 jio_snprintf(time_msg, sizeof(time_msg), "%s GC log file has reached the"
622 " maximum size. Saved as %s\n",
623 os::local_time_string((char *)time_str, sizeof(time_str)),
624 renamed_file_name);
625 this->write(time_msg, strlen(time_msg));
626
627 fclose(_file);
628 _file = NULL;
629
630 bool can_rename = true;
631 if (access(current_file_name, F_OK) != 0) {
632 // current file does not exist?
633 warning("No source file exists, cannot rename\n");
634 can_rename = false;
635 }
636 if (can_rename) {
637 if (access(renamed_file_name, F_OK) == 0) {
638 if (remove(renamed_file_name) != 0) {
639 warning("Could not delete existing file %s\n", renamed_file_name);
640 can_rename = false;
641 }
642 } else {
643 // file does not exist, ok to rename
644 }
645 }
646 if (can_rename && rename(current_file_name, renamed_file_name) != 0) {
647 warning("Could not rename %s to %s\n", _file_name, renamed_file_name);
648 }
649 }
650
651 _cur_file_num++;
652 if (_cur_file_num > NumberOfGCLogFiles - 1) _cur_file_num = 0;
653 jio_snprintf(current_file_name, filename_len + EXTRACHARLEN, "%s.%d" CURRENTAPPX,
654 _file_name, _cur_file_num);
655 _file = fopen(current_file_name, "w");
656
657 if (_file != NULL) {
658 _bytes_written = 0L;
659 _need_close = true;
660 // reuse current_file_name for time_msg
661 jio_snprintf(current_file_name, filename_len + EXTRACHARLEN,
662 "%s.%d", _file_name, _cur_file_num);
663 jio_snprintf(time_msg, sizeof(time_msg), "%s GC log file created %s\n",
664 os::local_time_string((char *)time_str, sizeof(time_str)),
665 current_file_name);
666 this->write(time_msg, strlen(time_msg));
667 dump_loggc_header();
668 // remove the existing file
669 if (access(current_file_name, F_OK) == 0) {
670 if (remove(current_file_name) != 0) {
671 warning("Could not delete existing file %s\n", current_file_name);
672 }
673 }
674 } else {
675 warning("failed to open rotation log file %s due to %s\n"
676 "Turned off GC log file rotation\n",
677 _file_name, strerror(errno));
678 _need_close = false;
679 FLAG_SET_DEFAULT(UseGCLogFileRotation, false);
680 }
681 }
682
683 defaultStream* defaultStream::instance = NULL;
684 int defaultStream::_output_fd = 1;
685 int defaultStream::_error_fd = 2;
686 FILE* defaultStream::_output_stream = stdout;
687 FILE* defaultStream::_error_stream = stderr;
688
689 #define LOG_MAJOR_VERSION 160
690 #define LOG_MINOR_VERSION 1
691
692 void defaultStream::init() {
693 _inited = true;
694 if (LogVMOutput || LogCompilation) {
695 init_log();
696 }
697 }
698
699 bool defaultStream::has_log_file() {
|