fix console_buffer: avoid potential deadlock when using dmesg over MAVLink shell

dmesg was locking the console buffer, then writing to stdout (a pipe in
the case of the MAVLink shell).
This might block, waiting for mavlink to read from the pipe. If however
mavlink tries to write to the console at that time, the lock is already
taken.
This patch avoids nested locking by using a separate buffer.
This commit is contained in:
Beat Küng 2021-11-30 11:52:46 +01:00 committed by Daniel Agar
parent 01db98fccf
commit cbd6e735ad
1 changed files with 24 additions and 27 deletions

View File

@ -67,50 +67,47 @@ private:
int _head{0};
int _tail{0};
px4_sem_t _lock = SEM_INITIALIZER(1);
bool _is_printing{false};
pthread_t _printing_task;
};
void ConsoleBuffer::print(bool follow)
{
lock();
_printing_task = pthread_self();
int i = _head;
// print to stdout, but with a buffer in between to avoid nested locking and potential dead-locks
// (which could happen in combination with the MAVLink shell: dmesg writing to the pipe waiting
// mavlink to read, while mavlink calls printf, waiting for the console lock)
const int buffer_length = 512;
char buffer[buffer_length];
int offset = -1;
while (true) {
_is_printing = true;
do {
if (i < _tail) {
::write(1, _buffer + i, _tail - i);
// print the full buffer or what's newly added
int total_size_read = 0;
} else if (_tail < i) {
::write(1, _buffer + i, BOARD_CONSOLE_BUFFER_SIZE - i);
::write(1, _buffer, _tail);
}
do {
int read_size = read(buffer, buffer_length, &offset);
i = _tail;
if (read_size <= 0) {
break;
}
::write(1, buffer, read_size);
if (read_size < buffer_length) {
break;
}
total_size_read += read_size;
} while (total_size_read < BOARD_CONSOLE_BUFFER_SIZE);
_is_printing = false;
if (follow) {
unlock();
usleep(10000);
lock();
} else {
break;
}
}
unlock();
} while (follow);
}
void ConsoleBuffer::write(const char *buffer, size_t len)
{
if (_is_printing && pthread_self() == _printing_task) { // avoid adding to the buffer while we are printing it
return;
}
lock(); // same rule as for printf: this cannot be used from IRQ handlers
for (size_t i = 0; i < len; ++i) {