Projects
openEuler:24.03:SP1:Everything
openjdk-1.8.0
_service:tar_scm:8229517-Support-for-optional-a...
Sign Up
Log In
Username
Password
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
File _service:tar_scm:8229517-Support-for-optional-asynchronous-buffered-l.patch of Package openjdk-1.8.0
From 577f318d824d91e5deb8b6b82dd211583cb93cac Mon Sep 17 00:00:00 2001 From: eapen <zhangyipeng7@huawei.com> Date: Thu, 15 Dec 2022 10:37:31 +0800 Subject: [PATCH 18/33] I68TO2: 8229517: Support for optional asynchronous/buffered logging --- hotspot/src/os/windows/vm/os_windows.cpp | 1 + hotspot/src/share/vm/runtime/arguments.cpp | 10 ++ hotspot/src/share/vm/runtime/globals.hpp | 9 ++ hotspot/src/share/vm/runtime/init.cpp | 2 + hotspot/src/share/vm/runtime/logAsyncWriter.cpp | 164 ++++++++++++++++++++++++ hotspot/src/share/vm/runtime/logAsyncWriter.hpp | 159 +++++++++++++++++++++++ hotspot/src/share/vm/runtime/os.hpp | 1 + hotspot/src/share/vm/runtime/thread.cpp | 26 +++- hotspot/src/share/vm/runtime/vmStructs.cpp | 2 + hotspot/src/share/vm/utilities/linkedlist.hpp | 47 +++++-- hotspot/src/share/vm/utilities/ostream.cpp | 26 ++++ hotspot/src/share/vm/utilities/ostream.hpp | 3 + 12 files changed, 440 insertions(+), 10 deletions(-) create mode 100644 hotspot/src/share/vm/runtime/logAsyncWriter.cpp create mode 100644 hotspot/src/share/vm/runtime/logAsyncWriter.hpp diff --git a/hotspot/src/os/windows/vm/os_windows.cpp b/hotspot/src/os/windows/vm/os_windows.cpp index 25122de..cc31126 100644 --- a/hotspot/src/os/windows/vm/os_windows.cpp +++ b/hotspot/src/os/windows/vm/os_windows.cpp @@ -562,6 +562,7 @@ bool os::create_thread(Thread* thread, ThreadType thr_type, size_t stack_size) { case os::pgc_thread: case os::cgc_thread: case os::watcher_thread: + case os::asynclog_thread: if (VMThreadStackSize > 0) stack_size = (size_t)(VMThreadStackSize * K); break; } diff --git a/hotspot/src/share/vm/runtime/arguments.cpp b/hotspot/src/share/vm/runtime/arguments.cpp index 91e2ce0..fba3d4b 100644 --- a/hotspot/src/share/vm/runtime/arguments.cpp +++ b/hotspot/src/share/vm/runtime/arguments.cpp @@ -2269,6 +2269,16 @@ bool Arguments::verify_percentage(uintx value, const char* name) { // no gc log rotation when log file not supplied or // NumberOfGCLogFiles is 0 void check_gclog_consistency() { + if (UseAsyncGCLog) { + if (Arguments::gc_log_filename() == NULL) { + jio_fprintf(defaultStream::output_stream(), + "To enable Async GC log, use -Xloggc:<filename> -XX:UseAsyncGCLog\n" + "Async GC log is turned off\n"); + UseAsyncGCLog = false; + + } + } + if (UseGCLogFileRotation) { if ((Arguments::gc_log_filename() == NULL) || (NumberOfGCLogFiles == 0)) { jio_fprintf(defaultStream::output_stream(), diff --git a/hotspot/src/share/vm/runtime/globals.hpp b/hotspot/src/share/vm/runtime/globals.hpp index 41b1392..10e4e7f 100644 --- a/hotspot/src/share/vm/runtime/globals.hpp +++ b/hotspot/src/share/vm/runtime/globals.hpp @@ -4104,6 +4104,15 @@ class CommandLineFlags { \ JFR_ONLY(product(bool, LogJFR, false, \ "Enable JFR logging (consider +Verbose)")) \ + \ + product(bool, UseAsyncGCLog, false, \ + "Enable asynchronous GC logging") \ + \ + product(uintx, AsyncLogBufferSize, 2*M, \ + "Memory budget (in bytes) for the buffer of Asynchronous") \ + \ + diagnostic(bool, PrintAsyncGCLog, false, \ + "Print some information of Async GC Log") \ /* * Macros for factoring of globals diff --git a/hotspot/src/share/vm/runtime/init.cpp b/hotspot/src/share/vm/runtime/init.cpp index d2e0f22..b185409 100644 --- a/hotspot/src/share/vm/runtime/init.cpp +++ b/hotspot/src/share/vm/runtime/init.cpp @@ -32,6 +32,7 @@ #include "runtime/handles.inline.hpp" #include "runtime/icache.hpp" #include "runtime/init.hpp" +#include "runtime/logAsyncWriter.hpp" #include "runtime/safepoint.hpp" #include "runtime/sharedRuntime.hpp" #include "services/memTracker.hpp" @@ -106,6 +107,7 @@ jint init_globals() { if (status != JNI_OK) return status; + AsyncLogWriter::initialize(); interpreter_init(); // before any methods loaded invocationCounter_init(); // before any methods loaded marksweep_init(); diff --git a/hotspot/src/share/vm/runtime/logAsyncWriter.cpp b/hotspot/src/share/vm/runtime/logAsyncWriter.cpp new file mode 100644 index 0000000..750a23f --- /dev/null +++ b/hotspot/src/share/vm/runtime/logAsyncWriter.cpp @@ -0,0 +1,164 @@ +/* + * Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. + * Copyright (c) 2022, Huawei Technologies Co., Ltd. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ +#include "precompiled.hpp" +#include "runtime/atomic.hpp" +#include "runtime/logAsyncWriter.hpp" +#include "utilities/ostream.hpp" + +class AsyncLogWriter::AsyncLogLocker : public StackObj { + public: + AsyncLogLocker() { + assert(_instance != NULL, "AsyncLogWriter::_lock is unavailable"); + _instance->_lock.wait(); + } + + ~AsyncLogLocker() { + _instance->_lock.signal(); + } +}; + +void AsyncLogWriter::enqueue_locked(const AsyncLogMessage& msg) { + if (_buffer.size() >= _buffer_max_size) { + // drop the enqueueing message. + os::free(msg.message()); + return; + } + + assert(_buffer.size() < _buffer_max_size, "_buffer is over-sized."); + _buffer.push_back(msg); + _sem.signal(); +} + +void AsyncLogWriter::enqueue(const char* msg) { + AsyncLogMessage m(os::strdup(msg)); + + { // critical area + AsyncLogLocker locker; + enqueue_locked(m); + } +} + +AsyncLogWriter::AsyncLogWriter() + : NamedThread(), + _lock(1), _sem(0), _io_sem(1), + _initialized(false), + _buffer_max_size(AsyncLogBufferSize / sizeof(AsyncLogMessage)) { + if (os::create_thread(this, os::asynclog_thread)) { + _initialized = true; + set_name("AsyncLog Thread"); + } else { + if (PrintAsyncGCLog) { + tty->print_cr("AsyncLogging failed to create thread. Falling back to synchronous logging."); + } + } + + if (PrintAsyncGCLog) { + tty->print_cr("The maximum entries of AsyncLogBuffer: " SIZE_FORMAT ", estimated memory use: " SIZE_FORMAT " bytes", + _buffer_max_size, AsyncLogBufferSize); + } +} + +void AsyncLogWriter::write() { + // Use kind of copy-and-swap idiom here. + // Empty 'logs' swaps the content with _buffer. + // Along with logs destruction, all processed messages are deleted. + // + // The operation 'pop_all()' is done in O(1). All I/O jobs are then performed without + // lock protection. This guarantees I/O jobs don't block logsites. + AsyncLogBuffer logs; + bool own_io = false; + + { // critical region + AsyncLogLocker locker; + + _buffer.pop_all(&logs); + own_io = _io_sem.trywait(); + } + + LinkedListIterator<AsyncLogMessage> it(logs.head()); + if (!own_io) { + _io_sem.wait(); + } + + bool flush = false; + while (!it.is_empty()) { + AsyncLogMessage* e = it.next(); + char* msg = e->message(); + + if (msg != NULL) { + flush = true; + ((gcLogFileStream*)gclog_or_tty)->write_blocking(msg, strlen(msg)); + os::free(msg); + } + } + if (flush) { + ((gcLogFileStream*)gclog_or_tty)->fileStream::flush(); + } + _io_sem.signal(); +} + +void AsyncLogWriter::run() { + while (true) { + // The value of a semphore cannot be negative. Therefore, the current thread falls asleep + // when its value is zero. It will be waken up when new messages are enqueued. + _sem.wait(); + write(); + } +} + +AsyncLogWriter* AsyncLogWriter::_instance = NULL; + +void AsyncLogWriter::initialize() { + if (!UseAsyncGCLog) return; + + assert(_instance == NULL, "initialize() should only be invoked once."); + + AsyncLogWriter* self = new AsyncLogWriter(); + if (self->_initialized) { + OrderAccess::release_store_ptr(&AsyncLogWriter::_instance, self); + os::start_thread(self); + if (PrintAsyncGCLog) { + tty->print_cr("Async logging thread started."); + } + } +} + +AsyncLogWriter* AsyncLogWriter::instance() { + return _instance; +} + +// write() acquires and releases _io_sem even _buffer is empty. +// This guarantees all logging I/O of dequeued messages are done when it returns. +void AsyncLogWriter::flush() { + if (_instance != NULL) { + _instance->write(); + } +} + +void AsyncLogWriter::print_on(outputStream* st) const{ + st->print("\"%s\" ", name()); + Thread::print_on(st); + st->cr(); +} diff --git a/hotspot/src/share/vm/runtime/logAsyncWriter.hpp b/hotspot/src/share/vm/runtime/logAsyncWriter.hpp new file mode 100644 index 0000000..5242426 --- /dev/null +++ b/hotspot/src/share/vm/runtime/logAsyncWriter.hpp @@ -0,0 +1,159 @@ +/* + * Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. + * Copyright (c) 2022, Huawei Technologies Co., Ltd. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ +#ifndef SHARE_VM_RUNTIME_LOGASYNCWRITER_HPP +#define SHARE_VM_RUNTIME_LOGASYNCWRITER_HPP +#include "memory/resourceArea.hpp" +#include "runtime/semaphore.hpp" +#include "utilities/linkedlist.hpp" + +template <typename E, MEMFLAGS F> +class LinkedListDeque : private LinkedListImpl<E, ResourceObj::C_HEAP, F> { + private: + LinkedListNode<E>* _tail; + size_t _size; + + public: + LinkedListDeque() : _tail(NULL), _size(0) {} + void push_back(const E& e) { + if (!_tail) { + _tail = this->add(e); + } else { + _tail = this->insert_after(e, _tail); + } + + ++_size; + } + + // pop all elements to logs. + void pop_all(LinkedList<E>* logs) { + logs->move(static_cast<LinkedList<E>* >(this)); + _tail = NULL; + _size = 0; + } + + void pop_all(LinkedListDeque<E, F>* logs) { + logs->_size = _size; + logs->_tail = _tail; + pop_all(static_cast<LinkedList<E>* >(logs)); + } + + void pop_front() { + LinkedListNode<E>* h = this->unlink_head(); + if (h == _tail) { + _tail = NULL; + } + + if (h != NULL) { + --_size; + this->delete_node(h); + } + } + + size_t size() const { return _size; } + + const E* front() const { + return this->_head == NULL ? NULL : this->_head->peek(); + } + + const E* back() const { + return _tail == NULL ? NULL : _tail->peek(); + } + + LinkedListNode<E>* head() const { + return this->_head; + } +}; + +class AsyncLogMessage { + char* _message; + +public: + AsyncLogMessage(char* msg) + : _message(msg) {} + + // placeholder for LinkedListImpl. + bool equals(const AsyncLogMessage& o) const { return false; } + + char* message() const { return _message; } +}; + +typedef LinkedListDeque<AsyncLogMessage, mtInternal> AsyncLogBuffer; + +// +// ASYNC LOGGING SUPPORT +// +// Summary: +// Async Logging is working on the basis of singleton AsyncLogWriter, which manages an intermediate buffer and a flushing thread. +// +// Interface: +// +// initialize() is called once when JVM is initialized. It creates and initializes the singleton instance of AsyncLogWriter. +// Once async logging is established, there's no way to turn it off. +// +// instance() is MT-safe and returns the pointer of the singleton instance if and only if async logging is enabled and has well +// initialized. Clients can use its return value to determine async logging is established or not. +// +// The basic operation of AsyncLogWriter is enqueue(). 2 overloading versions of it are provided to match LogOutput::write(). +// They are both MT-safe and non-blocking. Derived classes of LogOutput can invoke the corresponding enqueue() in write() and +// return 0. AsyncLogWriter is responsible of copying neccessary data. +// +// The static member function flush() is designated to flush out all pending messages when JVM is terminating. +// In normal JVM termination, flush() is invoked in LogConfiguration::finalize(). flush() is MT-safe and can be invoked arbitrary +// times. It is no-op if async logging is not established. +// +class AsyncLogWriter : public NamedThread { + class AsyncLogLocker; + + static AsyncLogWriter* _instance; + // _lock(1) denotes a critional region. + Semaphore _lock; + // _sem is a semaphore whose value denotes how many messages have been enqueued. + // It decreases in AsyncLogWriter::run() + Semaphore _sem; + // A lock of IO + Semaphore _io_sem; + + volatile bool _initialized; + AsyncLogBuffer _buffer; + + const size_t _buffer_max_size; + + AsyncLogWriter(); + void enqueue_locked(const AsyncLogMessage& msg); + void write(); + void run(); + + public: + void enqueue(const char* msg); + + static AsyncLogWriter* instance(); + static void initialize(); + static void flush(); + // Printing + void print_on(outputStream* st) const; + +}; + +#endif // SHARE_LOGGING_LOGASYNCWRITER_HPP diff --git a/hotspot/src/share/vm/runtime/os.hpp b/hotspot/src/share/vm/runtime/os.hpp index acc57f4..5f41e96 100644 --- a/hotspot/src/share/vm/runtime/os.hpp +++ b/hotspot/src/share/vm/runtime/os.hpp @@ -463,6 +463,7 @@ class os: AllStatic { java_thread, compiler_thread, watcher_thread, + asynclog_thread, // dedicated to flushing logs os_thread }; diff --git a/hotspot/src/share/vm/runtime/thread.cpp b/hotspot/src/share/vm/runtime/thread.cpp index cacab59..61627e4 100644 --- a/hotspot/src/share/vm/runtime/thread.cpp +++ b/hotspot/src/share/vm/runtime/thread.cpp @@ -57,6 +57,7 @@ #include "runtime/java.hpp" #include "runtime/javaCalls.hpp" #include "runtime/jniPeriodicChecker.hpp" +#include "runtime/logAsyncWriter.hpp" #include "runtime/memprofiler.hpp" #include "runtime/mutexLocker.hpp" #include "runtime/objectMonitor.hpp" @@ -881,7 +882,9 @@ void Thread::print_on_error(outputStream* st, char* buf, int buflen) const { else if (is_GC_task_thread()) st->print("GCTaskThread"); else if (is_Watcher_thread()) st->print("WatcherThread"); else if (is_ConcurrentGC_thread()) st->print("ConcurrentGCThread"); - else st->print("Thread"); + else if (this == AsyncLogWriter::instance()) { + st->print("%s", this->name()); + } else st->print("Thread"); st->print(" [stack: " PTR_FORMAT "," PTR_FORMAT "]", _stack_base - _stack_size, _stack_base); @@ -4387,6 +4390,12 @@ void Threads::print_on(outputStream* st, bool print_stacks, bool internal_format st->cr(); } CompileBroker::print_compiler_threads_on(st); + if (UseAsyncGCLog) { + AsyncLogWriter* aio_writer = AsyncLogWriter::instance(); + if (aio_writer != NULL) { + aio_writer->print_on(st); + } + } st->flush(); } @@ -4432,6 +4441,21 @@ void Threads::print_on_error(outputStream* st, Thread* current, char* buf, int b wt->print_on_error(st, buf, buflen); st->cr(); } + + if (UseAsyncGCLog) { + AsyncLogWriter* aio_writer = AsyncLogWriter::instance(); + if (aio_writer != NULL) { + bool is_current = (current == aio_writer); + found_current = found_current || is_current; + st->print("%s", is_current ? "=>" : " "); + + st->print(PTR_FORMAT, aio_writer); + st->print(" "); + aio_writer->print_on_error(st, buf, buflen); + st->cr(); + } + } + if (!found_current) { st->cr(); st->print("=>" PTR_FORMAT " (exited) ", current); diff --git a/hotspot/src/share/vm/runtime/vmStructs.cpp b/hotspot/src/share/vm/runtime/vmStructs.cpp index ab20f5c..5d1cf2b 100644 --- a/hotspot/src/share/vm/runtime/vmStructs.cpp +++ b/hotspot/src/share/vm/runtime/vmStructs.cpp @@ -97,6 +97,7 @@ #include "runtime/sharedRuntime.hpp" #include "runtime/stubRoutines.hpp" #include "runtime/thread.inline.hpp" +#include "runtime/logAsyncWriter.hpp" #include "runtime/virtualspace.hpp" #include "runtime/vmStructs.hpp" #include "utilities/array.hpp" @@ -1599,6 +1600,7 @@ typedef TwoOopHashtable<Symbol*, mtClass> SymbolTwoOopHashtable; declare_type(Thread, ThreadShadow) \ declare_type(NamedThread, Thread) \ declare_type(WatcherThread, Thread) \ + declare_type(AsyncLogWriter, Thread) \ declare_type(JavaThread, Thread) \ declare_type(JvmtiAgentThread, JavaThread) \ declare_type(ServiceThread, JavaThread) \ diff --git a/hotspot/src/share/vm/utilities/linkedlist.hpp b/hotspot/src/share/vm/utilities/linkedlist.hpp index a76c15c..f4f2a9b 100644 --- a/hotspot/src/share/vm/utilities/linkedlist.hpp +++ b/hotspot/src/share/vm/utilities/linkedlist.hpp @@ -40,6 +40,25 @@ template <class E> class LinkedListNode : public ResourceObj { E _data; // embedded content LinkedListNode<E>* _next; // next entry + // Select member function 'bool U::equals(const U&) const' if 'U' is of class + // type. This works because of the "Substitution Failure Is Not An Error" + // (SFINAE) rule. Notice that this version of 'equal' will also be chosen for + // class types which don't define a corresponding 'equals()' method (and will + // result in a compilation error for them). It is not easily possible to + // specialize this 'equal()' function exclusively for class types which define + // the correct 'equals()' function because that function can be in a base + // class, a dependent base class or have a compatible but slightly different + // signature. + template <class U> + static bool equal(const U& a, const U& b, bool (U::*t)(const U&) const) { + return a.equals(b); + } + + template <class U> + static bool equal(const U& a, const U& b, ...) { + return a == b; + } + protected: LinkedListNode() : _next(NULL) { } @@ -51,6 +70,10 @@ template <class E> class LinkedListNode : public ResourceObj { E* data() { return &_data; } const E* peek() const { return &_data; } + + bool equals(const E& t) const { + return equal<E>(_data, t, NULL); + } }; // A linked list interface. It does not specify @@ -62,6 +85,7 @@ template <class E> class LinkedList : public ResourceObj { public: LinkedList() : _head(NULL) { } + virtual ~LinkedList() {} inline void set_head(LinkedListNode<E>* h) { _head = h; } inline LinkedListNode<E>* head() const { return _head; } @@ -182,7 +206,7 @@ template <class E, ResourceObj::allocation_type T = ResourceObj::C_HEAP, virtual LinkedListNode<E>* find_node(const E& e) { LinkedListNode<E>* p = this->head(); - while (p != NULL && !p->peek()->equals(e)) { + while (p != NULL && !p->equals(e)) { p = p->next(); } return p; @@ -229,7 +253,7 @@ template <class E, ResourceObj::allocation_type T = ResourceObj::C_HEAP, LinkedListNode<E>* prev = NULL; while (tmp != NULL) { - if (tmp->peek()->equals(e)) { + if (tmp->equals(e)) { return remove_after(prev); } prev = tmp; @@ -396,16 +420,21 @@ template <class E, int (*FUNC)(const E&, const E&), // Iterates all entries in the list template <class E> class LinkedListIterator : public StackObj { private: - LinkedListNode<E>* _p; - bool _is_empty; + mutable LinkedListNode<E>* _p; + public: - LinkedListIterator(LinkedListNode<E>* head) : _p(head) { - _is_empty = (head == NULL); - } + LinkedListIterator(LinkedListNode<E>* head) : _p(head) { } + + bool is_empty() const { return _p == NULL; } - bool is_empty() const { return _is_empty; } + E* next() { + if (_p == NULL) return NULL; + E* e = _p->data(); + _p = _p->next(); + return e; + } - const E* next() { + const E* next() const { if (_p == NULL) return NULL; const E* e = _p->peek(); _p = _p->next(); diff --git a/hotspot/src/share/vm/utilities/ostream.cpp b/hotspot/src/share/vm/utilities/ostream.cpp index 14d82ad..5d40559 100644 --- a/hotspot/src/share/vm/utilities/ostream.cpp +++ b/hotspot/src/share/vm/utilities/ostream.cpp @@ -30,6 +30,7 @@ #include "runtime/mutexLocker.hpp" #include "runtime/os.hpp" #include "runtime/vmThread.hpp" +#include "runtime/logAsyncWriter.hpp" #include "utilities/defaultStream.hpp" #include "utilities/ostream.hpp" #include "utilities/top.hpp" @@ -876,6 +877,17 @@ gcLogFileStream::gcLogFileStream(const char* file_name) : _file_lock(NULL) { } void gcLogFileStream::write(const char* s, size_t len) { + if (UseAsyncGCLog) { + AsyncLogWriter* aio_writer = AsyncLogWriter::instance(); + if (aio_writer != NULL) { + aio_writer->enqueue(s); + return; + } + } + write_blocking(s, len); +} + +void gcLogFileStream::write_blocking(const char* s, size_t len) { if (_file != NULL) { // we can't use Thread::current() here because thread may be NULL // in early stage(ostream_init_log) @@ -1047,6 +1059,17 @@ void gcLogFileStream::rotate_log_impl(bool force, outputStream* out) { } } +void gcLogFileStream::flush() { + if (UseAsyncGCLog) { + AsyncLogWriter* aio_writer = AsyncLogWriter::instance(); + if (aio_writer != NULL) { + // do nothing + return; + } + } + fileStream::flush(); +} + defaultStream* defaultStream::instance = NULL; int defaultStream::_output_fd = 1; int defaultStream::_error_fd = 2; @@ -1456,6 +1479,9 @@ void ostream_exit() { // ostream_abort() is called by os::abort() when VM is about to die. void ostream_abort() { + if (UseAsyncGCLog) { + AsyncLogWriter::flush(); + } // Here we can't delete gclog_or_tty and tty, just flush their output if (gclog_or_tty) gclog_or_tty->flush(); if (tty) tty->flush(); diff --git a/hotspot/src/share/vm/utilities/ostream.hpp b/hotspot/src/share/vm/utilities/ostream.hpp index d0f9aac..85ff599 100644 --- a/hotspot/src/share/vm/utilities/ostream.hpp +++ b/hotspot/src/share/vm/utilities/ostream.hpp @@ -254,6 +254,7 @@ class gcLogFileStream : public fileStream { gcLogFileStream(const char* file_name); ~gcLogFileStream(); virtual void write(const char* c, size_t len); + void write_blocking(const char* c, size_t len); virtual void rotate_log(bool force, outputStream* out = NULL); void dump_loggc_header(); @@ -263,6 +264,8 @@ class gcLogFileStream : public fileStream { ((GCLogFileSize != 0) && ((uintx)_bytes_written >= GCLogFileSize)); } + virtual void flush(); + }; #ifndef PRODUCT -- 1.8.3.1
Locations
Projects
Search
Status Monitor
Help
Open Build Service
OBS Manuals
API Documentation
OBS Portal
Reporting a Bug
Contact
Mailing List
Forums
Chat (IRC)
Twitter
Open Build Service (OBS)
is an
openSUSE project
.
浙ICP备2022010568号-2