2626#include " logging/logConfiguration.hpp"
2727#include " logging/logFileOutput.hpp"
2828#include " logging/logFileStreamOutput.hpp"
29- #include " logging/logHandle .hpp"
29+ #include " memory/allocation .hpp"
3030#include " memory/resourceArea.hpp"
3131#include " runtime/atomic.hpp"
32- #include " runtime/os.inline.hpp"
33- #include " runtime/globals.hpp"
3432
33+ class AsyncLogWriter ::Locker : public StackObj {
34+ Thread*& _holder;
35+ PlatformMonitor& _lock;
3536
36- class AsyncLogWriter ::AsyncLogLocker : public StackObj {
37- static Thread* _holder;
3837public:
39- static Thread* current_holder () { return _holder; }
40- AsyncLogLocker () {
41- assert (_instance != nullptr , " AsyncLogWriter:: _lock is unavailable " );
42- _instance-> _lock .lock ();
38+ Locker ( Thread*& holder, PlatformMonitor& lock)
39+ : _holder(holder),
40+ _lock (lock) {
41+ _lock.lock ();
4342 _holder = Thread::current_or_null ();
4443 }
4544
46- ~AsyncLogLocker () {
45+ ~Locker () {
4746 assert (_holder == Thread::current_or_null (), " must be" );
4847 _holder = nullptr ;
49- _instance->_lock .unlock ();
48+ _lock.unlock ();
49+ }
50+
51+ void notify () {
52+ _lock.notify ();
5053 }
5154
5255 void wait () {
5356 Thread* saved_holder = _holder;
5457 _holder = nullptr ;
55- _instance-> _lock .wait (0 /* no timeout */ );
58+ _lock.wait (0 /* no timeout */ );
5659 _holder = saved_holder;
5760 }
5861};
5962
60- Thread* AsyncLogWriter::AsyncLogLocker::_holder = nullptr ;
63+ class AsyncLogWriter ::ProducerLocker : public Locker {
64+ static Thread* _holder;
65+ public:
66+ static Thread* current_holder () { return _holder; }
67+ ProducerLocker () : Locker(_holder, _instance->_producer_lock) {}
68+ };
69+
70+ class AsyncLogWriter ::ConsumerLocker : public Locker {
71+ static Thread* _holder;
72+ public:
73+ static Thread* current_holder () { return _holder; }
74+ ConsumerLocker () : Locker(_holder, _instance->_consumer_lock) {}
75+ };
76+
77+ Thread* AsyncLogWriter::ProducerLocker::_holder = nullptr ;
78+ Thread* AsyncLogWriter::ConsumerLocker::_holder = nullptr ;
6179
6280// LogDecorator::None applies to 'constant initialization' because of its constexpr constructor.
6381const LogDecorations& AsyncLogWriter::None = LogDecorations(LogLevel::Warning, LogTagSetMapping<LogTag::__NO_TAG>::tagset(),
6482 LogDecorators::None);
6583
66- bool AsyncLogWriter::Buffer::push_back (LogFileStreamOutput* output, const LogDecorations& decorations, const char * msg) {
67- const size_t len = strlen (msg) ;
84+ bool AsyncLogWriter::Buffer::push_back (LogFileStreamOutput* output, const LogDecorations& decorations, const char * msg, const size_t msg_len ) {
85+ const size_t len = msg_len ;
6886 const size_t sz = Message::calc_size (len);
6987 const bool is_token = output == nullptr ;
7088 // Always leave headroom for the flush token. Pushing a token must succeed.
@@ -80,7 +98,7 @@ bool AsyncLogWriter::Buffer::push_back(LogFileStreamOutput* output, const LogDec
8098}
8199
82100void AsyncLogWriter::Buffer::push_flush_token () {
83- bool result = push_back (nullptr , AsyncLogWriter::None, " " );
101+ bool result = push_back (nullptr , AsyncLogWriter::None, " " , 0 );
84102 assert (result, " fail to enqueue the flush token." );
85103}
86104
@@ -89,22 +107,45 @@ void AsyncLogWriter::enqueue_locked(LogFileStreamOutput* output, const LogDecora
89107 // client should use "" instead.
90108 assert (msg != nullptr , " enqueuing a null message!" );
91109
92- if (!_buffer->push_back (output, decorations, msg)) {
93- bool p_created;
94- uint32_t * counter = _stats.put_if_absent (output, 0 , &p_created);
95- *counter = *counter + 1 ;
96- return ;
97- }
110+ size_t msg_len = strlen (msg);
111+ void * stalled_message = nullptr ;
112+ {
113+ ConsumerLocker clocker;
114+ if (_buffer->push_back (output, decorations, msg, msg_len)) {
115+ _data_available = true ;
116+ clocker.notify ();
117+ return ;
118+ }
98119
99- _data_available = true ;
100- _lock.notify ();
120+ if (LogConfiguration::async_mode () == LogConfiguration::AsyncMode::Stall) {
121+ size_t size = Message::calc_size (msg_len);
122+ stalled_message = os::malloc (size, mtLogging);
123+ if (stalled_message == nullptr ) {
124+ // Out of memory. We bail without any notice.
125+ // Some other part of the system will probably fail later.
126+ return ;
127+ }
128+ _stalled_message = new (stalled_message) Message (output, decorations, msg, msg_len);
129+ _data_available = true ;
130+ clocker.notify ();
131+ // Note: we still hold the producer lock so cannot race against other threads trying to log a message
132+ while (_stalled_message != nullptr ) {
133+ clocker.wait ();
134+ }
135+ } else {
136+ bool p_created;
137+ uint32_t * counter = _stats.put_if_absent (output, 0 , &p_created);
138+ *counter = *counter + 1 ;
139+ }
140+ } // ConsumerLocker out of scope
141+ os::free (stalled_message);
101142}
102143
103144// This function checks for cases where continuing with asynchronous logging may lead to stability issues, such as a deadlock.
104145// If this returns false then we give up on logging asynchronously and do so synchronously instead.
105146bool AsyncLogWriter::is_enqueue_allowed () {
106147 AsyncLogWriter* alw = AsyncLogWriter::instance ();
107- Thread* holding_thread = AsyncLogWriter::AsyncLogLocker ::current_holder ();
148+ Thread* holding_thread = AsyncLogWriter::ProducerLocker ::current_holder ();
108149 Thread* this_thread = Thread::current_or_null ();
109150 if (this_thread == nullptr ) {
110151 // The current thread is unattached.
@@ -142,7 +183,7 @@ bool AsyncLogWriter::enqueue(LogFileStreamOutput& output, const LogDecorations&
142183 return false ;
143184 }
144185
145- AsyncLogLocker locker ;
186+ ProducerLocker plocker ;
146187
147188#ifdef ASSERT
148189 if (TestingAsyncLoggingDeathTest || TestingAsyncLoggingDeathTestNoCrash) {
@@ -162,17 +203,21 @@ bool AsyncLogWriter::enqueue(LogFileStreamOutput& output, LogMessageBuffer::Iter
162203 }
163204
164205 // If we get here we know the AsyncLogWriter is initialized.
165- AsyncLogLocker locker ;
206+ ProducerLocker plocker ;
166207 for (; !msg_iterator.is_at_end (); msg_iterator++) {
167208 AsyncLogWriter::instance ()->enqueue_locked (&output, msg_iterator.decorations (), msg_iterator.message ());
168209 }
169210 return true ;
170211}
171212
172213AsyncLogWriter::AsyncLogWriter ()
173- : _flush_sem(0 ), _lock(), _data_available(false ),
174- _initialized(false ),
175- _stats() {
214+ : _flush_sem(0 ),
215+ _producer_lock(),
216+ _consumer_lock(),
217+ _data_available(false ),
218+ _initialized(false ),
219+ _stats(),
220+ _stalled_message(nullptr ) {
176221
177222 size_t size = AsyncLogBufferSize / 2 ;
178223 _buffer = new Buffer (size);
@@ -185,7 +230,7 @@ AsyncLogWriter::AsyncLogWriter()
185230 }
186231}
187232
188- void AsyncLogWriter::write (AsyncLogMap<AnyObj::RESOURCE_AREA>& snapshot) {
233+ bool AsyncLogWriter::write (AsyncLogMap<AnyObj::RESOURCE_AREA>& snapshot) {
189234 int req = 0 ;
190235 auto it = _buffer_staging->iterator ();
191236 while (it.hasNext ()) {
@@ -213,20 +258,21 @@ void AsyncLogWriter::write(AsyncLogMap<AnyObj::RESOURCE_AREA>& snapshot) {
213258
214259 if (req > 0 ) {
215260 assert (req == 1 , " Only one token is allowed in queue. AsyncLogWriter::flush() is NOT MT-safe!" );
216- _flush_sem. signal (req) ;
261+ return true ;
217262 }
263+ return false ;
218264}
219265
220266void AsyncLogWriter::run () {
221267 while (true ) {
222268 ResourceMark rm;
223269 AsyncLogMap<AnyObj::RESOURCE_AREA> snapshot;
224270 {
225- AsyncLogLocker locker;
226-
271+ ConsumerLocker clocker;
227272 while (!_data_available) {
228- locker .wait ();
273+ clocker .wait ();
229274 }
275+
230276 // Only doing a swap and statistics under the lock to
231277 // guarantee that I/O jobs don't block logsites.
232278 _buffer_staging->reset ();
@@ -243,7 +289,23 @@ void AsyncLogWriter::run() {
243289 });
244290 _data_available = false ;
245291 }
246- write (snapshot);
292+
293+ bool saw_flush_token = write (snapshot);
294+
295+ // Any stalled message must be written *after* the buffer has been written.
296+ // This is because we try hard to output messages in program-order.
297+ if (_stalled_message != nullptr ) {
298+ assert (LogConfiguration::async_mode () == LogConfiguration::AsyncMode::Stall, " must be" );
299+ ConsumerLocker clocker;
300+ Message* m = (Message*)_stalled_message;
301+ m->output ()->write_blocking (m->decorations (), m->message ());
302+ _stalled_message = nullptr ;
303+ clocker.notify ();
304+ }
305+
306+ if (saw_flush_token) {
307+ _flush_sem.signal (1 );
308+ }
247309 }
248310}
249311
@@ -281,19 +343,20 @@ AsyncLogWriter* AsyncLogWriter::instance() {
281343void AsyncLogWriter::flush () {
282344 if (_instance != nullptr ) {
283345 {
284- AsyncLogLocker locker;
346+ ProducerLocker plocker;
347+ ConsumerLocker clocker;
285348 // Push directly in-case we are at logical max capacity, as this must not get dropped.
286349 _instance->_buffer ->push_flush_token ();
287350 _instance->_data_available = true ;
288- _instance-> _lock .notify ();
351+ clocker .notify ();
289352 }
290353
291354 _instance->_flush_sem .wait ();
292355 }
293356}
294357
295358AsyncLogWriter::BufferUpdater::BufferUpdater (size_t newsize) {
296- AsyncLogLocker locker ;
359+ ConsumerLocker clocker ;
297360 auto p = AsyncLogWriter::_instance;
298361
299362 _buf1 = p->_buffer ;
@@ -307,7 +370,7 @@ AsyncLogWriter::BufferUpdater::~BufferUpdater() {
307370 auto p = AsyncLogWriter::_instance;
308371
309372 {
310- AsyncLogLocker locker ;
373+ ConsumerLocker clocker ;
311374
312375 delete p->_buffer ;
313376 delete p->_buffer_staging ;
0 commit comments