Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/jdk17u
Path: blob/master/src/hotspot/share/logging/logAsyncWriter.cpp
64440 views
1
/*
2
* Copyright Amazon.com Inc. or its affiliates. All Rights Reserved.
3
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4
*
5
* This code is free software; you can redistribute it and/or modify it
6
* under the terms of the GNU General Public License version 2 only, as
7
* published by the Free Software Foundation.
8
*
9
* This code is distributed in the hope that it will be useful, but WITHOUT
10
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12
* version 2 for more details (a copy is included in the LICENSE file that
13
* accompanied this code).
14
*
15
* You should have received a copy of the GNU General Public License version
16
* 2 along with this work; if not, write to the Free Software Foundation,
17
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18
*
19
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20
* or visit www.oracle.com if you need additional information or have any
21
* questions.
22
*
23
*/
24
#include "precompiled.hpp"
25
#include "logging/logAsyncWriter.hpp"
26
#include "logging/logConfiguration.hpp"
27
#include "logging/logFileOutput.hpp"
28
#include "logging/logHandle.hpp"
29
#include "runtime/atomic.hpp"
30
#include "runtime/os.inline.hpp"
31
32
class AsyncLogWriter::AsyncLogLocker : public StackObj {
33
public:
34
AsyncLogLocker() {
35
assert(_instance != nullptr, "AsyncLogWriter::_lock is unavailable");
36
_instance->_lock.lock();
37
}
38
39
~AsyncLogLocker() {
40
_instance->_lock.unlock();
41
}
42
};
43
44
void AsyncLogWriter::enqueue_locked(const AsyncLogMessage& msg) {
45
if (_buffer.size() >= _buffer_max_size) {
46
bool p_created;
47
uint32_t* counter = _stats.add_if_absent(msg.output(), 0, &p_created);
48
*counter = *counter + 1;
49
// drop the enqueueing message.
50
os::free(msg.message());
51
return;
52
}
53
54
_buffer.push_back(msg);
55
_data_available = true;
56
_lock.notify();
57
}
58
59
void AsyncLogWriter::enqueue(LogFileOutput& output, const LogDecorations& decorations, const char* msg) {
60
AsyncLogMessage m(&output, decorations, os::strdup(msg));
61
62
{ // critical area
63
AsyncLogLocker locker;
64
enqueue_locked(m);
65
}
66
}
67
68
// LogMessageBuffer consists of a multiple-part/multiple-line messsage.
69
// The lock here guarantees its integrity.
70
void AsyncLogWriter::enqueue(LogFileOutput& output, LogMessageBuffer::Iterator msg_iterator) {
71
AsyncLogLocker locker;
72
73
for (; !msg_iterator.is_at_end(); msg_iterator++) {
74
AsyncLogMessage m(&output, msg_iterator.decorations(), os::strdup(msg_iterator.message()));
75
enqueue_locked(m);
76
}
77
}
78
79
AsyncLogWriter::AsyncLogWriter()
80
: _flush_sem(0), _lock(), _data_available(false),
81
_initialized(false),
82
_stats(17 /*table_size*/) {
83
if (os::create_thread(this, os::asynclog_thread)) {
84
_initialized = true;
85
} else {
86
log_warning(logging, thread)("AsyncLogging failed to create thread. Falling back to synchronous logging.");
87
}
88
89
log_info(logging)("The maximum entries of AsyncLogBuffer: " SIZE_FORMAT ", estimated memory use: " SIZE_FORMAT " bytes",
90
_buffer_max_size, AsyncLogBufferSize);
91
}
92
93
class AsyncLogMapIterator {
94
AsyncLogBuffer& _logs;
95
96
public:
97
AsyncLogMapIterator(AsyncLogBuffer& logs) :_logs(logs) {}
98
bool do_entry(LogFileOutput* output, uint32_t* counter) {
99
using none = LogTagSetMapping<LogTag::__NO_TAG>;
100
101
if (*counter > 0) {
102
LogDecorations decorations(LogLevel::Warning, none::tagset(), LogDecorators::All);
103
stringStream ss;
104
ss.print(UINT32_FORMAT_W(6) " messages dropped due to async logging", *counter);
105
AsyncLogMessage msg(output, decorations, ss.as_string(true /*c_heap*/));
106
_logs.push_back(msg);
107
*counter = 0;
108
}
109
110
return true;
111
}
112
};
113
114
void AsyncLogWriter::write() {
115
// Use kind of copy-and-swap idiom here.
116
// Empty 'logs' swaps the content with _buffer.
117
// Along with logs destruction, all processed messages are deleted.
118
//
119
// The operation 'pop_all()' is done in O(1). All I/O jobs are then performed without
120
// lock protection. This guarantees I/O jobs don't block logsites.
121
AsyncLogBuffer logs;
122
123
{ // critical region
124
AsyncLogLocker locker;
125
126
_buffer.pop_all(&logs);
127
// append meta-messages of dropped counters
128
AsyncLogMapIterator dropped_counters_iter(logs);
129
_stats.iterate(&dropped_counters_iter);
130
_data_available = false;
131
}
132
133
LinkedListIterator<AsyncLogMessage> it(logs.head());
134
135
int req = 0;
136
while (!it.is_empty()) {
137
AsyncLogMessage* e = it.next();
138
char* msg = e->message();
139
140
if (msg != nullptr) {
141
e->output()->write_blocking(e->decorations(), msg);
142
os::free(msg);
143
} else if (e->output() == nullptr) {
144
// This is a flush token. Record that we found it and then
145
// signal the flushing thread after the loop.
146
req++;
147
}
148
}
149
150
if (req > 0) {
151
assert(req == 1, "AsyncLogWriter::flush() is NOT MT-safe!");
152
_flush_sem.signal(req);
153
}
154
}
155
156
void AsyncLogWriter::run() {
157
while (true) {
158
{
159
AsyncLogLocker locker;
160
161
while (!_data_available) {
162
_lock.wait(0/* no timeout */);
163
}
164
}
165
166
write();
167
}
168
}
169
170
AsyncLogWriter* AsyncLogWriter::_instance = nullptr;
171
172
void AsyncLogWriter::initialize() {
173
if (!LogConfiguration::is_async_mode()) return;
174
175
assert(_instance == nullptr, "initialize() should only be invoked once.");
176
177
AsyncLogWriter* self = new AsyncLogWriter();
178
if (self->_initialized) {
179
Atomic::release_store_fence(&AsyncLogWriter::_instance, self);
180
// All readers of _instance after the fence see non-NULL.
181
// We use LogOutputList's RCU counters to ensure all synchronous logsites have completed.
182
// After that, we start AsyncLog Thread and it exclusively takes over all logging I/O.
183
for (LogTagSet* ts = LogTagSet::first(); ts != NULL; ts = ts->next()) {
184
ts->wait_until_no_readers();
185
}
186
os::start_thread(self);
187
log_debug(logging, thread)("Async logging thread started.");
188
}
189
}
190
191
AsyncLogWriter* AsyncLogWriter::instance() {
192
return _instance;
193
}
194
195
// Inserts a flush token into the async output buffer and waits until the AsyncLog thread
196
// signals that it has seen it and completed all dequeued message processing.
197
// This method is not MT-safe in itself, but is guarded by another lock in the usual
198
// usecase - see the comments in the header file for more details.
199
void AsyncLogWriter::flush() {
200
if (_instance != nullptr) {
201
{
202
using none = LogTagSetMapping<LogTag::__NO_TAG>;
203
AsyncLogLocker locker;
204
LogDecorations d(LogLevel::Off, none::tagset(), LogDecorators::None);
205
AsyncLogMessage token(nullptr, d, nullptr);
206
207
// Push directly in-case we are at logical max capacity, as this must not get dropped.
208
_instance->_buffer.push_back(token);
209
_instance->_data_available = true;
210
_instance->_lock.notify();
211
}
212
213
_instance->_flush_sem.wait();
214
}
215
}
216
217