Path: blob/master/src/hotspot/share/logging/logAsyncWriter.cpp
64440 views
/*1* Copyright Amazon.com Inc. or its affiliates. All Rights Reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation.7*8* This code is distributed in the hope that it will be useful, but WITHOUT9* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or10* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License11* version 2 for more details (a copy is included in the LICENSE file that12* accompanied this code).13*14* You should have received a copy of the GNU General Public License version15* 2 along with this work; if not, write to the Free Software Foundation,16* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.17*18* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA19* or visit www.oracle.com if you need additional information or have any20* questions.21*22*/23#include "precompiled.hpp"24#include "logging/logAsyncWriter.hpp"25#include "logging/logConfiguration.hpp"26#include "logging/logFileOutput.hpp"27#include "logging/logHandle.hpp"28#include "runtime/atomic.hpp"29#include "runtime/os.inline.hpp"3031class AsyncLogWriter::AsyncLogLocker : public StackObj {32public:33AsyncLogLocker() {34assert(_instance != nullptr, "AsyncLogWriter::_lock is unavailable");35_instance->_lock.lock();36}3738~AsyncLogLocker() {39_instance->_lock.unlock();40}41};4243void AsyncLogWriter::enqueue_locked(const AsyncLogMessage& msg) {44if (_buffer.size() >= _buffer_max_size) {45bool p_created;46uint32_t* counter = _stats.add_if_absent(msg.output(), 0, &p_created);47*counter = *counter + 1;48// drop the enqueueing message.49os::free(msg.message());50return;51}5253_buffer.push_back(msg);54_data_available = true;55_lock.notify();56}5758void AsyncLogWriter::enqueue(LogFileOutput& output, const LogDecorations& decorations, const char* msg) {59AsyncLogMessage m(&output, decorations, os::strdup(msg));6061{ // critical area62AsyncLogLocker locker;63enqueue_locked(m);64}65}6667// LogMessageBuffer consists of a multiple-part/multiple-line messsage.68// The lock here guarantees its integrity.69void AsyncLogWriter::enqueue(LogFileOutput& output, LogMessageBuffer::Iterator msg_iterator) {70AsyncLogLocker locker;7172for (; !msg_iterator.is_at_end(); msg_iterator++) {73AsyncLogMessage m(&output, msg_iterator.decorations(), os::strdup(msg_iterator.message()));74enqueue_locked(m);75}76}7778AsyncLogWriter::AsyncLogWriter()79: _flush_sem(0), _lock(), _data_available(false),80_initialized(false),81_stats(17 /*table_size*/) {82if (os::create_thread(this, os::asynclog_thread)) {83_initialized = true;84} else {85log_warning(logging, thread)("AsyncLogging failed to create thread. Falling back to synchronous logging.");86}8788log_info(logging)("The maximum entries of AsyncLogBuffer: " SIZE_FORMAT ", estimated memory use: " SIZE_FORMAT " bytes",89_buffer_max_size, AsyncLogBufferSize);90}9192class AsyncLogMapIterator {93AsyncLogBuffer& _logs;9495public:96AsyncLogMapIterator(AsyncLogBuffer& logs) :_logs(logs) {}97bool do_entry(LogFileOutput* output, uint32_t* counter) {98using none = LogTagSetMapping<LogTag::__NO_TAG>;99100if (*counter > 0) {101LogDecorations decorations(LogLevel::Warning, none::tagset(), LogDecorators::All);102stringStream ss;103ss.print(UINT32_FORMAT_W(6) " messages dropped due to async logging", *counter);104AsyncLogMessage msg(output, decorations, ss.as_string(true /*c_heap*/));105_logs.push_back(msg);106*counter = 0;107}108109return true;110}111};112113void AsyncLogWriter::write() {114// Use kind of copy-and-swap idiom here.115// Empty 'logs' swaps the content with _buffer.116// Along with logs destruction, all processed messages are deleted.117//118// The operation 'pop_all()' is done in O(1). All I/O jobs are then performed without119// lock protection. This guarantees I/O jobs don't block logsites.120AsyncLogBuffer logs;121122{ // critical region123AsyncLogLocker locker;124125_buffer.pop_all(&logs);126// append meta-messages of dropped counters127AsyncLogMapIterator dropped_counters_iter(logs);128_stats.iterate(&dropped_counters_iter);129_data_available = false;130}131132LinkedListIterator<AsyncLogMessage> it(logs.head());133134int req = 0;135while (!it.is_empty()) {136AsyncLogMessage* e = it.next();137char* msg = e->message();138139if (msg != nullptr) {140e->output()->write_blocking(e->decorations(), msg);141os::free(msg);142} else if (e->output() == nullptr) {143// This is a flush token. Record that we found it and then144// signal the flushing thread after the loop.145req++;146}147}148149if (req > 0) {150assert(req == 1, "AsyncLogWriter::flush() is NOT MT-safe!");151_flush_sem.signal(req);152}153}154155void AsyncLogWriter::run() {156while (true) {157{158AsyncLogLocker locker;159160while (!_data_available) {161_lock.wait(0/* no timeout */);162}163}164165write();166}167}168169AsyncLogWriter* AsyncLogWriter::_instance = nullptr;170171void AsyncLogWriter::initialize() {172if (!LogConfiguration::is_async_mode()) return;173174assert(_instance == nullptr, "initialize() should only be invoked once.");175176AsyncLogWriter* self = new AsyncLogWriter();177if (self->_initialized) {178Atomic::release_store_fence(&AsyncLogWriter::_instance, self);179// All readers of _instance after the fence see non-NULL.180// We use LogOutputList's RCU counters to ensure all synchronous logsites have completed.181// After that, we start AsyncLog Thread and it exclusively takes over all logging I/O.182for (LogTagSet* ts = LogTagSet::first(); ts != NULL; ts = ts->next()) {183ts->wait_until_no_readers();184}185os::start_thread(self);186log_debug(logging, thread)("Async logging thread started.");187}188}189190AsyncLogWriter* AsyncLogWriter::instance() {191return _instance;192}193194// Inserts a flush token into the async output buffer and waits until the AsyncLog thread195// signals that it has seen it and completed all dequeued message processing.196// This method is not MT-safe in itself, but is guarded by another lock in the usual197// usecase - see the comments in the header file for more details.198void AsyncLogWriter::flush() {199if (_instance != nullptr) {200{201using none = LogTagSetMapping<LogTag::__NO_TAG>;202AsyncLogLocker locker;203LogDecorations d(LogLevel::Off, none::tagset(), LogDecorators::None);204AsyncLogMessage token(nullptr, d, nullptr);205206// Push directly in-case we are at logical max capacity, as this must not get dropped.207_instance->_buffer.push_back(token);208_instance->_data_available = true;209_instance->_lock.notify();210}211212_instance->_flush_sem.wait();213}214}215216217