mirror of
https://github.com/RGBCube/serenity
synced 2025-05-31 13:48:12 +00:00
LibC: Make stdio thread-safe
This commit is contained in:
parent
ad688ffc73
commit
62ee003ef5
1 changed files with 60 additions and 1 deletions
|
@ -10,6 +10,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/pthread_integration.h>
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
|
@ -110,12 +111,18 @@ private:
|
||||||
// Flush *some* data from the buffer.
|
// Flush *some* data from the buffer.
|
||||||
bool write_from_buffer();
|
bool write_from_buffer();
|
||||||
|
|
||||||
|
void lock();
|
||||||
|
void unlock();
|
||||||
|
|
||||||
int m_fd { -1 };
|
int m_fd { -1 };
|
||||||
int m_mode { 0 };
|
int m_mode { 0 };
|
||||||
int m_error { 0 };
|
int m_error { 0 };
|
||||||
bool m_eof { false };
|
bool m_eof { false };
|
||||||
pid_t m_popen_child { -1 };
|
pid_t m_popen_child { -1 };
|
||||||
Buffer m_buffer;
|
Buffer m_buffer;
|
||||||
|
__pthread_mutex_t m_mutex;
|
||||||
|
|
||||||
|
friend class ScopedFileLock;
|
||||||
};
|
};
|
||||||
|
|
||||||
FILE::~FILE()
|
FILE::~FILE()
|
||||||
|
@ -552,6 +559,33 @@ bool FILE::Buffer::enqueue_front(u8 byte)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void FILE::lock()
|
||||||
|
{
|
||||||
|
__pthread_mutex_lock(&m_mutex);
|
||||||
|
}
|
||||||
|
|
||||||
|
void FILE::unlock()
|
||||||
|
{
|
||||||
|
__pthread_mutex_unlock(&m_mutex);
|
||||||
|
}
|
||||||
|
|
||||||
|
class ScopedFileLock {
|
||||||
|
public:
|
||||||
|
ScopedFileLock(FILE* file)
|
||||||
|
: m_file(file)
|
||||||
|
{
|
||||||
|
m_file->lock();
|
||||||
|
}
|
||||||
|
|
||||||
|
~ScopedFileLock()
|
||||||
|
{
|
||||||
|
m_file->unlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
FILE* m_file;
|
||||||
|
};
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
|
|
||||||
static u8 default_streams[3][sizeof(FILE)];
|
static u8 default_streams[3][sizeof(FILE)];
|
||||||
|
@ -571,6 +605,7 @@ void __stdio_init()
|
||||||
int setvbuf(FILE* stream, char* buf, int mode, size_t size)
|
int setvbuf(FILE* stream, char* buf, int mode, size_t size)
|
||||||
{
|
{
|
||||||
VERIFY(stream);
|
VERIFY(stream);
|
||||||
|
ScopedFileLock lock(stream);
|
||||||
if (mode != _IONBF && mode != _IOLBF && mode != _IOFBF) {
|
if (mode != _IONBF && mode != _IOLBF && mode != _IOFBF) {
|
||||||
errno = EINVAL;
|
errno = EINVAL;
|
||||||
return -1;
|
return -1;
|
||||||
|
@ -592,12 +627,14 @@ void setlinebuf(FILE* stream)
|
||||||
int fileno(FILE* stream)
|
int fileno(FILE* stream)
|
||||||
{
|
{
|
||||||
VERIFY(stream);
|
VERIFY(stream);
|
||||||
|
ScopedFileLock lock(stream);
|
||||||
return stream->fileno();
|
return stream->fileno();
|
||||||
}
|
}
|
||||||
|
|
||||||
int feof(FILE* stream)
|
int feof(FILE* stream)
|
||||||
{
|
{
|
||||||
VERIFY(stream);
|
VERIFY(stream);
|
||||||
|
ScopedFileLock lock(stream);
|
||||||
return stream->eof();
|
return stream->eof();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -607,12 +644,14 @@ int fflush(FILE* stream)
|
||||||
dbgln("FIXME: fflush(nullptr) should flush all open streams");
|
dbgln("FIXME: fflush(nullptr) should flush all open streams");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
ScopedFileLock lock(stream);
|
||||||
return stream->flush() ? 0 : EOF;
|
return stream->flush() ? 0 : EOF;
|
||||||
}
|
}
|
||||||
|
|
||||||
char* fgets(char* buffer, int size, FILE* stream)
|
char* fgets(char* buffer, int size, FILE* stream)
|
||||||
{
|
{
|
||||||
VERIFY(stream);
|
VERIFY(stream);
|
||||||
|
ScopedFileLock lock(stream);
|
||||||
bool ok = stream->gets(reinterpret_cast<u8*>(buffer), size);
|
bool ok = stream->gets(reinterpret_cast<u8*>(buffer), size);
|
||||||
return ok ? buffer : nullptr;
|
return ok ? buffer : nullptr;
|
||||||
}
|
}
|
||||||
|
@ -634,6 +673,7 @@ int getc(FILE* stream)
|
||||||
|
|
||||||
int getc_unlocked(FILE* stream)
|
int getc_unlocked(FILE* stream)
|
||||||
{
|
{
|
||||||
|
// FIXME: This currently locks the file
|
||||||
return fgetc(stream);
|
return fgetc(stream);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -696,6 +736,7 @@ ssize_t getline(char** lineptr, size_t* n, FILE* stream)
|
||||||
int ungetc(int c, FILE* stream)
|
int ungetc(int c, FILE* stream)
|
||||||
{
|
{
|
||||||
VERIFY(stream);
|
VERIFY(stream);
|
||||||
|
ScopedFileLock lock(stream);
|
||||||
bool ok = stream->ungetc(c);
|
bool ok = stream->ungetc(c);
|
||||||
return ok ? c : EOF;
|
return ok ? c : EOF;
|
||||||
}
|
}
|
||||||
|
@ -704,6 +745,7 @@ int fputc(int ch, FILE* stream)
|
||||||
{
|
{
|
||||||
VERIFY(stream);
|
VERIFY(stream);
|
||||||
u8 byte = ch;
|
u8 byte = ch;
|
||||||
|
ScopedFileLock lock(stream);
|
||||||
size_t nwritten = stream->write(&byte, 1);
|
size_t nwritten = stream->write(&byte, 1);
|
||||||
if (nwritten == 0)
|
if (nwritten == 0)
|
||||||
return EOF;
|
return EOF;
|
||||||
|
@ -725,6 +767,7 @@ int fputs(const char* s, FILE* stream)
|
||||||
{
|
{
|
||||||
VERIFY(stream);
|
VERIFY(stream);
|
||||||
size_t len = strlen(s);
|
size_t len = strlen(s);
|
||||||
|
ScopedFileLock lock(stream);
|
||||||
size_t nwritten = stream->write(reinterpret_cast<const u8*>(s), len);
|
size_t nwritten = stream->write(reinterpret_cast<const u8*>(s), len);
|
||||||
if (nwritten < len)
|
if (nwritten < len)
|
||||||
return EOF;
|
return EOF;
|
||||||
|
@ -742,12 +785,14 @@ int puts(const char* s)
|
||||||
void clearerr(FILE* stream)
|
void clearerr(FILE* stream)
|
||||||
{
|
{
|
||||||
VERIFY(stream);
|
VERIFY(stream);
|
||||||
|
ScopedFileLock lock(stream);
|
||||||
stream->clear_err();
|
stream->clear_err();
|
||||||
}
|
}
|
||||||
|
|
||||||
int ferror(FILE* stream)
|
int ferror(FILE* stream)
|
||||||
{
|
{
|
||||||
VERIFY(stream);
|
VERIFY(stream);
|
||||||
|
ScopedFileLock lock(stream);
|
||||||
return stream->error();
|
return stream->error();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -756,6 +801,7 @@ size_t fread(void* ptr, size_t size, size_t nmemb, FILE* stream)
|
||||||
VERIFY(stream);
|
VERIFY(stream);
|
||||||
VERIFY(!Checked<size_t>::multiplication_would_overflow(size, nmemb));
|
VERIFY(!Checked<size_t>::multiplication_would_overflow(size, nmemb));
|
||||||
|
|
||||||
|
ScopedFileLock lock(stream);
|
||||||
size_t nread = stream->read(reinterpret_cast<u8*>(ptr), size * nmemb);
|
size_t nread = stream->read(reinterpret_cast<u8*>(ptr), size * nmemb);
|
||||||
if (!nread)
|
if (!nread)
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -767,6 +813,7 @@ size_t fwrite(const void* ptr, size_t size, size_t nmemb, FILE* stream)
|
||||||
VERIFY(stream);
|
VERIFY(stream);
|
||||||
VERIFY(!Checked<size_t>::multiplication_would_overflow(size, nmemb));
|
VERIFY(!Checked<size_t>::multiplication_would_overflow(size, nmemb));
|
||||||
|
|
||||||
|
ScopedFileLock lock(stream);
|
||||||
size_t nwritten = stream->write(reinterpret_cast<const u8*>(ptr), size * nmemb);
|
size_t nwritten = stream->write(reinterpret_cast<const u8*>(ptr), size * nmemb);
|
||||||
if (!nwritten)
|
if (!nwritten)
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -776,24 +823,28 @@ size_t fwrite(const void* ptr, size_t size, size_t nmemb, FILE* stream)
|
||||||
int fseek(FILE* stream, long offset, int whence)
|
int fseek(FILE* stream, long offset, int whence)
|
||||||
{
|
{
|
||||||
VERIFY(stream);
|
VERIFY(stream);
|
||||||
|
ScopedFileLock lock(stream);
|
||||||
return stream->seek(offset, whence);
|
return stream->seek(offset, whence);
|
||||||
}
|
}
|
||||||
|
|
||||||
int fseeko(FILE* stream, off_t offset, int whence)
|
int fseeko(FILE* stream, off_t offset, int whence)
|
||||||
{
|
{
|
||||||
VERIFY(stream);
|
VERIFY(stream);
|
||||||
|
ScopedFileLock lock(stream);
|
||||||
return stream->seek(offset, whence);
|
return stream->seek(offset, whence);
|
||||||
}
|
}
|
||||||
|
|
||||||
long ftell(FILE* stream)
|
long ftell(FILE* stream)
|
||||||
{
|
{
|
||||||
VERIFY(stream);
|
VERIFY(stream);
|
||||||
|
ScopedFileLock lock(stream);
|
||||||
return stream->tell();
|
return stream->tell();
|
||||||
}
|
}
|
||||||
|
|
||||||
off_t ftello(FILE* stream)
|
off_t ftello(FILE* stream)
|
||||||
{
|
{
|
||||||
VERIFY(stream);
|
VERIFY(stream);
|
||||||
|
ScopedFileLock lock(stream);
|
||||||
return stream->tell();
|
return stream->tell();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -802,6 +853,7 @@ int fgetpos(FILE* stream, fpos_t* pos)
|
||||||
VERIFY(stream);
|
VERIFY(stream);
|
||||||
VERIFY(pos);
|
VERIFY(pos);
|
||||||
|
|
||||||
|
ScopedFileLock lock(stream);
|
||||||
off_t val = stream->tell();
|
off_t val = stream->tell();
|
||||||
if (val == -1L)
|
if (val == -1L)
|
||||||
return 1;
|
return 1;
|
||||||
|
@ -815,12 +867,14 @@ int fsetpos(FILE* stream, const fpos_t* pos)
|
||||||
VERIFY(stream);
|
VERIFY(stream);
|
||||||
VERIFY(pos);
|
VERIFY(pos);
|
||||||
|
|
||||||
|
ScopedFileLock lock(stream);
|
||||||
return stream->seek(*pos, SEEK_SET);
|
return stream->seek(*pos, SEEK_SET);
|
||||||
}
|
}
|
||||||
|
|
||||||
void rewind(FILE* stream)
|
void rewind(FILE* stream)
|
||||||
{
|
{
|
||||||
VERIFY(stream);
|
VERIFY(stream);
|
||||||
|
ScopedFileLock lock(stream);
|
||||||
int rc = stream->seek(0, SEEK_SET);
|
int rc = stream->seek(0, SEEK_SET);
|
||||||
VERIFY(rc == 0);
|
VERIFY(rc == 0);
|
||||||
}
|
}
|
||||||
|
@ -1030,7 +1084,12 @@ static inline bool is_default_stream(FILE* stream)
|
||||||
int fclose(FILE* stream)
|
int fclose(FILE* stream)
|
||||||
{
|
{
|
||||||
VERIFY(stream);
|
VERIFY(stream);
|
||||||
bool ok = stream->close();
|
bool ok;
|
||||||
|
|
||||||
|
{
|
||||||
|
ScopedFileLock lock(stream);
|
||||||
|
ok = stream->close();
|
||||||
|
}
|
||||||
ScopedValueRollback errno_restorer(errno);
|
ScopedValueRollback errno_restorer(errno);
|
||||||
|
|
||||||
stream->~FILE();
|
stream->~FILE();
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue