Path: blob/master/src/hotspot/share/logging/logAsyncWriter.cpp
40930 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"2930Semaphore AsyncLogWriter::_sem(0);31Semaphore AsyncLogWriter::_io_sem(1);3233class AsyncLogLocker : public StackObj {34private:35static Semaphore _lock;36public:37AsyncLogLocker() {38_lock.wait();39}4041~AsyncLogLocker() {42_lock.signal();43}44};4546Semaphore AsyncLogLocker::_lock(1);4748void AsyncLogWriter::enqueue_locked(const AsyncLogMessage& msg) {49if (_buffer.size() >= _buffer_max_size) {50bool p_created;51uint32_t* counter = _stats.add_if_absent(msg.output(), 0, &p_created);52*counter = *counter + 1;53// drop the enqueueing message.54return;55}5657assert(_buffer.size() < _buffer_max_size, "_buffer is over-sized.");58_buffer.push_back(msg);59_sem.signal();60}6162void AsyncLogWriter::enqueue(LogFileOutput& output, const LogDecorations& decorations, const char* msg) {63AsyncLogMessage m(output, decorations, os::strdup(msg));6465{ // critical area66AsyncLogLocker lock;67enqueue_locked(m);68}69}7071// LogMessageBuffer consists of a multiple-part/multiple-line messsage.72// The lock here guarantees its integrity.73void AsyncLogWriter::enqueue(LogFileOutput& output, LogMessageBuffer::Iterator msg_iterator) {74AsyncLogLocker lock;7576for (; !msg_iterator.is_at_end(); msg_iterator++) {77AsyncLogMessage m(output, msg_iterator.decorations(), os::strdup(msg_iterator.message()));78enqueue_locked(m);79}80}8182AsyncLogWriter::AsyncLogWriter()83: _initialized(false),84_stats(17 /*table_size*/) {85if (os::create_thread(this, os::asynclog_thread)) {86_initialized = true;87} else {88log_warning(logging, thread)("AsyncLogging failed to create thread. Falling back to synchronous logging.");89}9091log_info(logging)("The maximum entries of AsyncLogBuffer: " SIZE_FORMAT ", estimated memory use: " SIZE_FORMAT " bytes",92_buffer_max_size, AsyncLogBufferSize);93}9495class AsyncLogMapIterator {96AsyncLogBuffer& _logs;9798public:99AsyncLogMapIterator(AsyncLogBuffer& logs) :_logs(logs) {}100bool do_entry(LogFileOutput* output, uint32_t* counter) {101using none = LogTagSetMapping<LogTag::__NO_TAG>;102103if (*counter > 0) {104LogDecorations decorations(LogLevel::Warning, none::tagset(), output->decorators());105stringStream ss;106ss.print(UINT32_FORMAT_W(6) " messages dropped due to async logging", *counter);107AsyncLogMessage msg(*output, decorations, ss.as_string(true /*c_heap*/));108_logs.push_back(msg);109*counter = 0;110}111112return true;113}114};115116void AsyncLogWriter::write() {117// Use kind of copy-and-swap idiom here.118// Empty 'logs' swaps the content with _buffer.119// Along with logs destruction, all processed messages are deleted.120//121// The operation 'pop_all()' is done in O(1). All I/O jobs are then performed without122// lock protection. This guarantees I/O jobs don't block logsites.123AsyncLogBuffer logs;124bool own_io = false;125126{ // critical region127AsyncLogLocker lock;128129_buffer.pop_all(&logs);130// append meta-messages of dropped counters131AsyncLogMapIterator dropped_counters_iter(logs);132_stats.iterate(&dropped_counters_iter);133own_io = _io_sem.trywait();134}135136LinkedListIterator<AsyncLogMessage> it(logs.head());137if (!own_io) {138_io_sem.wait();139}140141while (!it.is_empty()) {142AsyncLogMessage* e = it.next();143char* msg = e->message();144145if (msg != nullptr) {146e->output()->write_blocking(e->decorations(), msg);147os::free(msg);148}149}150_io_sem.signal();151}152153void AsyncLogWriter::run() {154while (true) {155// The value of a semphore cannot be negative. Therefore, the current thread falls asleep156// when its value is zero. It will be waken up when new messages are enqueued.157_sem.wait();158write();159}160}161162AsyncLogWriter* AsyncLogWriter::_instance = nullptr;163164void AsyncLogWriter::initialize() {165if (!LogConfiguration::is_async_mode()) return;166167assert(_instance == nullptr, "initialize() should only be invoked once.");168169AsyncLogWriter* self = new AsyncLogWriter();170if (self->_initialized) {171Atomic::release_store_fence(&AsyncLogWriter::_instance, self);172// All readers of _instance after the fence see non-NULL.173// We use LogOutputList's RCU counters to ensure all synchronous logsites have completed.174// After that, we start AsyncLog Thread and it exclusively takes over all logging I/O.175for (LogTagSet* ts = LogTagSet::first(); ts != NULL; ts = ts->next()) {176ts->wait_until_no_readers();177}178os::start_thread(self);179log_debug(logging, thread)("Async logging thread started.");180}181}182183AsyncLogWriter* AsyncLogWriter::instance() {184return _instance;185}186187// write() acquires and releases _io_sem even _buffer is empty.188// This guarantees all logging I/O of dequeued messages are done when it returns.189void AsyncLogWriter::flush() {190if (_instance != nullptr) {191_instance->write();192}193}194195196