1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-05-14 06:24:58 +00:00

LibC: Implement fflush(nullptr)

This caused all open file streams to be flushed.

This commit also changes `FILE::create` to handle buffer allocation
failure gracefully.
This commit is contained in:
Daniel Bertalan 2022-01-15 14:40:57 +01:00 committed by Brian Gianforcaro
parent b4e864d02d
commit 6a6dbf5b0b
3 changed files with 72 additions and 5 deletions

View file

@ -0,0 +1,35 @@
/*
* Copyright (c) 2021, Daniel Bertalan <dani@danielbertalan.dev>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#pragma once
#include <pthread.h>
// We don't want to bring LibThreading headers into LibC, so we use plain
// pthread mutexes and this RAII guard.
namespace LibC {
class [[nodiscard]] MutexLocker {
public:
explicit MutexLocker(pthread_mutex_t& mutex)
: m_mutex(mutex)
{
lock();
}
~MutexLocker()
{
unlock();
}
void lock() { pthread_mutex_lock(&m_mutex); }
void unlock() { pthread_mutex_unlock(&m_mutex); }
private:
pthread_mutex_t& m_mutex;
};
}

View file

@ -5,6 +5,7 @@
*/
#include <AK/Array.h>
#include <AK/IntrusiveList.h>
#include <AK/Types.h>
#include <LibC/bits/FILE.h>
#include <LibC/bits/pthread_integration.h>
@ -127,6 +128,10 @@ private:
pid_t m_popen_child { -1 };
Buffer m_buffer;
__pthread_mutex_t m_mutex;
IntrusiveListNode<FILE> m_list_node;
public:
using List = IntrusiveList<&FILE::m_list_node>;
};
class ScopedFileLock {

View file

@ -11,6 +11,7 @@
#include <AK/ScopedValueRollback.h>
#include <AK/StdLibExtras.h>
#include <AK/String.h>
#include <LibC/bits/mutex_locker.h>
#include <LibC/bits/stdio_file_implementation.h>
#include <assert.h>
#include <errno.h>
@ -26,6 +27,15 @@
#include <syscall.h>
#include <unistd.h>
static constinit pthread_mutex_t s_open_streams_lock = __PTHREAD_MUTEX_INITIALIZER;
// The list of open files is initialized in __stdio_init.
// We cannot rely on global constructors to initialize it, because it must
// be initialized before other global constructors run. Similarly, we cannot
// allow global destructors to destruct it.
alignas(FILE::List) static u8 s_open_streams_storage[sizeof(FILE::List)];
static FILE::List* const s_open_streams = reinterpret_cast<FILE::List*>(s_open_streams_storage);
FILE::~FILE()
{
bool already_closed = m_fd == -1;
@ -34,9 +44,13 @@ FILE::~FILE()
FILE* FILE::create(int fd, int mode)
{
void* file = calloc(1, sizeof(FILE));
new (file) FILE(fd, mode);
return (FILE*)file;
void* file_location = calloc(1, sizeof(FILE));
if (file_location == nullptr)
return nullptr;
auto* file = new (file_location) FILE(fd, mode);
LibC::MutexLocker locker(s_open_streams_lock);
s_open_streams->append(*file);
return file;
}
bool FILE::close()
@ -517,10 +531,14 @@ FILE* stderr = reinterpret_cast<FILE*>(&default_streams[2]);
void __stdio_init()
{
new (s_open_streams) FILE::List();
new (stdin) FILE(0, O_RDONLY);
new (stdout) FILE(1, O_WRONLY);
new (stderr) FILE(2, O_WRONLY);
stderr->setbuf(nullptr, _IONBF, 0);
s_open_streams->append(*stdin);
s_open_streams->append(*stdout);
s_open_streams->append(*stderr);
__stdio_is_initialized = true;
}
@ -568,8 +586,13 @@ int feof(FILE* stream)
int fflush(FILE* stream)
{
if (!stream) {
dbgln("FIXME: fflush(nullptr) should flush all open streams");
return 0;
int rc = 0;
LibC::MutexLocker locker(s_open_streams_lock);
for (auto& file : *s_open_streams) {
ScopedFileLock lock(&file);
rc = file.flush() ? rc : EOF;
}
return rc;
}
ScopedFileLock lock(stream);
return stream->flush() ? 0 : EOF;
@ -1070,6 +1093,10 @@ int fclose(FILE* stream)
}
ScopedValueRollback errno_restorer(errno);
{
LibC::MutexLocker locker(s_open_streams_lock);
s_open_streams->remove(*stream);
}
stream->~FILE();
if (!is_default_stream(stream))
free(stream);