mirror of
https://github.com/RGBCube/serenity
synced 2025-07-26 04:37:44 +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:
parent
b4e864d02d
commit
6a6dbf5b0b
3 changed files with 72 additions and 5 deletions
35
Userland/Libraries/LibC/bits/mutex_locker.h
Normal file
35
Userland/Libraries/LibC/bits/mutex_locker.h
Normal 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;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
|
@ -5,6 +5,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <AK/Array.h>
|
#include <AK/Array.h>
|
||||||
|
#include <AK/IntrusiveList.h>
|
||||||
#include <AK/Types.h>
|
#include <AK/Types.h>
|
||||||
#include <LibC/bits/FILE.h>
|
#include <LibC/bits/FILE.h>
|
||||||
#include <LibC/bits/pthread_integration.h>
|
#include <LibC/bits/pthread_integration.h>
|
||||||
|
@ -127,6 +128,10 @@ private:
|
||||||
pid_t m_popen_child { -1 };
|
pid_t m_popen_child { -1 };
|
||||||
Buffer m_buffer;
|
Buffer m_buffer;
|
||||||
__pthread_mutex_t m_mutex;
|
__pthread_mutex_t m_mutex;
|
||||||
|
IntrusiveListNode<FILE> m_list_node;
|
||||||
|
|
||||||
|
public:
|
||||||
|
using List = IntrusiveList<&FILE::m_list_node>;
|
||||||
};
|
};
|
||||||
|
|
||||||
class ScopedFileLock {
|
class ScopedFileLock {
|
||||||
|
|
|
@ -11,6 +11,7 @@
|
||||||
#include <AK/ScopedValueRollback.h>
|
#include <AK/ScopedValueRollback.h>
|
||||||
#include <AK/StdLibExtras.h>
|
#include <AK/StdLibExtras.h>
|
||||||
#include <AK/String.h>
|
#include <AK/String.h>
|
||||||
|
#include <LibC/bits/mutex_locker.h>
|
||||||
#include <LibC/bits/stdio_file_implementation.h>
|
#include <LibC/bits/stdio_file_implementation.h>
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
@ -26,6 +27,15 @@
|
||||||
#include <syscall.h>
|
#include <syscall.h>
|
||||||
#include <unistd.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()
|
FILE::~FILE()
|
||||||
{
|
{
|
||||||
bool already_closed = m_fd == -1;
|
bool already_closed = m_fd == -1;
|
||||||
|
@ -34,9 +44,13 @@ FILE::~FILE()
|
||||||
|
|
||||||
FILE* FILE::create(int fd, int mode)
|
FILE* FILE::create(int fd, int mode)
|
||||||
{
|
{
|
||||||
void* file = calloc(1, sizeof(FILE));
|
void* file_location = calloc(1, sizeof(FILE));
|
||||||
new (file) FILE(fd, mode);
|
if (file_location == nullptr)
|
||||||
return (FILE*)file;
|
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()
|
bool FILE::close()
|
||||||
|
@ -517,10 +531,14 @@ FILE* stderr = reinterpret_cast<FILE*>(&default_streams[2]);
|
||||||
|
|
||||||
void __stdio_init()
|
void __stdio_init()
|
||||||
{
|
{
|
||||||
|
new (s_open_streams) FILE::List();
|
||||||
new (stdin) FILE(0, O_RDONLY);
|
new (stdin) FILE(0, O_RDONLY);
|
||||||
new (stdout) FILE(1, O_WRONLY);
|
new (stdout) FILE(1, O_WRONLY);
|
||||||
new (stderr) FILE(2, O_WRONLY);
|
new (stderr) FILE(2, O_WRONLY);
|
||||||
stderr->setbuf(nullptr, _IONBF, 0);
|
stderr->setbuf(nullptr, _IONBF, 0);
|
||||||
|
s_open_streams->append(*stdin);
|
||||||
|
s_open_streams->append(*stdout);
|
||||||
|
s_open_streams->append(*stderr);
|
||||||
__stdio_is_initialized = true;
|
__stdio_is_initialized = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -568,8 +586,13 @@ int feof(FILE* stream)
|
||||||
int fflush(FILE* stream)
|
int fflush(FILE* stream)
|
||||||
{
|
{
|
||||||
if (!stream) {
|
if (!stream) {
|
||||||
dbgln("FIXME: fflush(nullptr) should flush all open streams");
|
int rc = 0;
|
||||||
return 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);
|
ScopedFileLock lock(stream);
|
||||||
return stream->flush() ? 0 : EOF;
|
return stream->flush() ? 0 : EOF;
|
||||||
|
@ -1070,6 +1093,10 @@ int fclose(FILE* stream)
|
||||||
}
|
}
|
||||||
ScopedValueRollback errno_restorer(errno);
|
ScopedValueRollback errno_restorer(errno);
|
||||||
|
|
||||||
|
{
|
||||||
|
LibC::MutexLocker locker(s_open_streams_lock);
|
||||||
|
s_open_streams->remove(*stream);
|
||||||
|
}
|
||||||
stream->~FILE();
|
stream->~FILE();
|
||||||
if (!is_default_stream(stream))
|
if (!is_default_stream(stream))
|
||||||
free(stream);
|
free(stream);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue