Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mobile
Path: blob/master/src/hotspot/share/logging/logAsyncWriter.cpp
40930 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
31
Semaphore AsyncLogWriter::_sem(0);
32
Semaphore AsyncLogWriter::_io_sem(1);
33
34
class AsyncLogLocker : public StackObj {
35
private:
36
static Semaphore _lock;
37
public:
38
AsyncLogLocker() {
39
_lock.wait();
40
}
41
42
~AsyncLogLocker() {
43
_lock.signal();
44
}
45
};
46
47
Semaphore AsyncLogLocker::_lock(1);
48
49
void AsyncLogWriter::enqueue_locked(const AsyncLogMessage& msg) {
50
if (_buffer.size() >= _buffer_max_size) {
51
bool p_created;
52
uint32_t* counter = _stats.add_if_absent(msg.output(), 0, &p_created);
53
*counter = *counter + 1;
54
// drop the enqueueing message.
55
return;
56
}
57
58
assert(_buffer.size() < _buffer_max_size, "_buffer is over-sized.");
59
_buffer.push_back(msg);
60
_sem.signal();
61
}
62
63
void AsyncLogWriter::enqueue(LogFileOutput& output, const LogDecorations& decorations, const char* msg) {
64
AsyncLogMessage m(output, decorations, os::strdup(msg));
65
66
{ // critical area
67
AsyncLogLocker lock;
68
enqueue_locked(m);
69
}
70
}
71
72
// LogMessageBuffer consists of a multiple-part/multiple-line messsage.
73
// The lock here guarantees its integrity.
74
void AsyncLogWriter::enqueue(LogFileOutput& output, LogMessageBuffer::Iterator msg_iterator) {
75
AsyncLogLocker lock;
76
77
for (; !msg_iterator.is_at_end(); msg_iterator++) {
78
AsyncLogMessage m(output, msg_iterator.decorations(), os::strdup(msg_iterator.message()));
79
enqueue_locked(m);
80
}
81
}
82
83
AsyncLogWriter::AsyncLogWriter()
84
: _initialized(false),
85
_stats(17 /*table_size*/) {
86
if (os::create_thread(this, os::asynclog_thread)) {
87
_initialized = true;
88
} else {
89
log_warning(logging, thread)("AsyncLogging failed to create thread. Falling back to synchronous logging.");
90
}
91
92
log_info(logging)("The maximum entries of AsyncLogBuffer: " SIZE_FORMAT ", estimated memory use: " SIZE_FORMAT " bytes",
93
_buffer_max_size, AsyncLogBufferSize);
94
}
95
96
class AsyncLogMapIterator {
97
AsyncLogBuffer& _logs;
98
99
public:
100
AsyncLogMapIterator(AsyncLogBuffer& logs) :_logs(logs) {}
101
bool do_entry(LogFileOutput* output, uint32_t* counter) {
102
using none = LogTagSetMapping<LogTag::__NO_TAG>;
103
104
if (*counter > 0) {
105
LogDecorations decorations(LogLevel::Warning, none::tagset(), output->decorators());
106
stringStream ss;
107
ss.print(UINT32_FORMAT_W(6) " messages dropped due to async logging", *counter);
108
AsyncLogMessage msg(*output, decorations, ss.as_string(true /*c_heap*/));
109
_logs.push_back(msg);
110
*counter = 0;
111
}
112
113
return true;
114
}
115
};
116
117
void AsyncLogWriter::write() {
118
// Use kind of copy-and-swap idiom here.
119
// Empty 'logs' swaps the content with _buffer.
120
// Along with logs destruction, all processed messages are deleted.
121
//
122
// The operation 'pop_all()' is done in O(1). All I/O jobs are then performed without
123
// lock protection. This guarantees I/O jobs don't block logsites.
124
AsyncLogBuffer logs;
125
bool own_io = false;
126
127
{ // critical region
128
AsyncLogLocker lock;
129
130
_buffer.pop_all(&logs);
131
// append meta-messages of dropped counters
132
AsyncLogMapIterator dropped_counters_iter(logs);
133
_stats.iterate(&dropped_counters_iter);
134
own_io = _io_sem.trywait();
135
}
136
137
LinkedListIterator<AsyncLogMessage> it(logs.head());
138
if (!own_io) {
139
_io_sem.wait();
140
}
141
142
while (!it.is_empty()) {
143
AsyncLogMessage* e = it.next();
144
char* msg = e->message();
145
146
if (msg != nullptr) {
147
e->output()->write_blocking(e->decorations(), msg);
148
os::free(msg);
149
}
150
}
151
_io_sem.signal();
152
}
153
154
void AsyncLogWriter::run() {
155
while (true) {
156
// The value of a semphore cannot be negative. Therefore, the current thread falls asleep
157
// when its value is zero. It will be waken up when new messages are enqueued.
158
_sem.wait();
159
write();
160
}
161
}
162
163
AsyncLogWriter* AsyncLogWriter::_instance = nullptr;
164
165
void AsyncLogWriter::initialize() {
166
if (!LogConfiguration::is_async_mode()) return;
167
168
assert(_instance == nullptr, "initialize() should only be invoked once.");
169
170
AsyncLogWriter* self = new AsyncLogWriter();
171
if (self->_initialized) {
172
Atomic::release_store_fence(&AsyncLogWriter::_instance, self);
173
// All readers of _instance after the fence see non-NULL.
174
// We use LogOutputList's RCU counters to ensure all synchronous logsites have completed.
175
// After that, we start AsyncLog Thread and it exclusively takes over all logging I/O.
176
for (LogTagSet* ts = LogTagSet::first(); ts != NULL; ts = ts->next()) {
177
ts->wait_until_no_readers();
178
}
179
os::start_thread(self);
180
log_debug(logging, thread)("Async logging thread started.");
181
}
182
}
183
184
AsyncLogWriter* AsyncLogWriter::instance() {
185
return _instance;
186
}
187
188
// write() acquires and releases _io_sem even _buffer is empty.
189
// This guarantees all logging I/O of dequeued messages are done when it returns.
190
void AsyncLogWriter::flush() {
191
if (_instance != nullptr) {
192
_instance->write();
193
}
194
}
195
196