summaryrefslogtreecommitdiff
path: root/Userland/Libraries/LibC
diff options
context:
space:
mode:
authorGunnar Beutner <gbeutner@serenityos.org>2021-04-29 21:17:32 +0200
committerAndreas Kling <kling@serenityos.org>2021-04-29 23:12:05 +0200
commit62ee003ef54b18ce23727b2b9d33137232a39fb9 (patch)
tree1426b15435b156a626d2818b2bfe5680ddeb7737 /Userland/Libraries/LibC
parentad688ffc73d79cbf61db1ceb09a233de4eb016b4 (diff)
downloadserenity-62ee003ef54b18ce23727b2b9d33137232a39fb9.zip
LibC: Make stdio thread-safe
Diffstat (limited to 'Userland/Libraries/LibC')
-rw-r--r--Userland/Libraries/LibC/stdio.cpp61
1 files changed, 60 insertions, 1 deletions
diff --git a/Userland/Libraries/LibC/stdio.cpp b/Userland/Libraries/LibC/stdio.cpp
index ecc7ec8ab2..d729222997 100644
--- a/Userland/Libraries/LibC/stdio.cpp
+++ b/Userland/Libraries/LibC/stdio.cpp
@@ -10,6 +10,7 @@
#include <AK/ScopedValueRollback.h>
#include <AK/StdLibExtras.h>
#include <AK/String.h>
+#include <LibC/bits/pthread_integration.h>
#include <assert.h>
#include <errno.h>
#include <fcntl.h>
@@ -110,12 +111,18 @@ private:
// Flush *some* data from the buffer.
bool write_from_buffer();
+ void lock();
+ void unlock();
+
int m_fd { -1 };
int m_mode { 0 };
int m_error { 0 };
bool m_eof { false };
pid_t m_popen_child { -1 };
Buffer m_buffer;
+ __pthread_mutex_t m_mutex;
+
+ friend class ScopedFileLock;
};
FILE::~FILE()
@@ -552,6 +559,33 @@ bool FILE::Buffer::enqueue_front(u8 byte)
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" {
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)
{
VERIFY(stream);
+ ScopedFileLock lock(stream);
if (mode != _IONBF && mode != _IOLBF && mode != _IOFBF) {
errno = EINVAL;
return -1;
@@ -592,12 +627,14 @@ void setlinebuf(FILE* stream)
int fileno(FILE* stream)
{
VERIFY(stream);
+ ScopedFileLock lock(stream);
return stream->fileno();
}
int feof(FILE* stream)
{
VERIFY(stream);
+ ScopedFileLock lock(stream);
return stream->eof();
}
@@ -607,12 +644,14 @@ int fflush(FILE* stream)
dbgln("FIXME: fflush(nullptr) should flush all open streams");
return 0;
}
+ ScopedFileLock lock(stream);
return stream->flush() ? 0 : EOF;
}
char* fgets(char* buffer, int size, FILE* stream)
{
VERIFY(stream);
+ ScopedFileLock lock(stream);
bool ok = stream->gets(reinterpret_cast<u8*>(buffer), size);
return ok ? buffer : nullptr;
}
@@ -634,6 +673,7 @@ int getc(FILE* stream)
int getc_unlocked(FILE* stream)
{
+ // FIXME: This currently locks the file
return fgetc(stream);
}
@@ -696,6 +736,7 @@ ssize_t getline(char** lineptr, size_t* n, FILE* stream)
int ungetc(int c, FILE* stream)
{
VERIFY(stream);
+ ScopedFileLock lock(stream);
bool ok = stream->ungetc(c);
return ok ? c : EOF;
}
@@ -704,6 +745,7 @@ int fputc(int ch, FILE* stream)
{
VERIFY(stream);
u8 byte = ch;
+ ScopedFileLock lock(stream);
size_t nwritten = stream->write(&byte, 1);
if (nwritten == 0)
return EOF;
@@ -725,6 +767,7 @@ int fputs(const char* s, FILE* stream)
{
VERIFY(stream);
size_t len = strlen(s);
+ ScopedFileLock lock(stream);
size_t nwritten = stream->write(reinterpret_cast<const u8*>(s), len);
if (nwritten < len)
return EOF;
@@ -742,12 +785,14 @@ int puts(const char* s)
void clearerr(FILE* stream)
{
VERIFY(stream);
+ ScopedFileLock lock(stream);
stream->clear_err();
}
int ferror(FILE* stream)
{
VERIFY(stream);
+ ScopedFileLock lock(stream);
return stream->error();
}
@@ -756,6 +801,7 @@ size_t fread(void* ptr, size_t size, size_t nmemb, FILE* stream)
VERIFY(stream);
VERIFY(!Checked<size_t>::multiplication_would_overflow(size, nmemb));
+ ScopedFileLock lock(stream);
size_t nread = stream->read(reinterpret_cast<u8*>(ptr), size * nmemb);
if (!nread)
return 0;
@@ -767,6 +813,7 @@ size_t fwrite(const void* ptr, size_t size, size_t nmemb, FILE* stream)
VERIFY(stream);
VERIFY(!Checked<size_t>::multiplication_would_overflow(size, nmemb));
+ ScopedFileLock lock(stream);
size_t nwritten = stream->write(reinterpret_cast<const u8*>(ptr), size * nmemb);
if (!nwritten)
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)
{
VERIFY(stream);
+ ScopedFileLock lock(stream);
return stream->seek(offset, whence);
}
int fseeko(FILE* stream, off_t offset, int whence)
{
VERIFY(stream);
+ ScopedFileLock lock(stream);
return stream->seek(offset, whence);
}
long ftell(FILE* stream)
{
VERIFY(stream);
+ ScopedFileLock lock(stream);
return stream->tell();
}
off_t ftello(FILE* stream)
{
VERIFY(stream);
+ ScopedFileLock lock(stream);
return stream->tell();
}
@@ -802,6 +853,7 @@ int fgetpos(FILE* stream, fpos_t* pos)
VERIFY(stream);
VERIFY(pos);
+ ScopedFileLock lock(stream);
off_t val = stream->tell();
if (val == -1L)
return 1;
@@ -815,12 +867,14 @@ int fsetpos(FILE* stream, const fpos_t* pos)
VERIFY(stream);
VERIFY(pos);
+ ScopedFileLock lock(stream);
return stream->seek(*pos, SEEK_SET);
}
void rewind(FILE* stream)
{
VERIFY(stream);
+ ScopedFileLock lock(stream);
int rc = stream->seek(0, SEEK_SET);
VERIFY(rc == 0);
}
@@ -1030,7 +1084,12 @@ static inline bool is_default_stream(FILE* stream)
int fclose(FILE* stream)
{
VERIFY(stream);
- bool ok = stream->close();
+ bool ok;
+
+ {
+ ScopedFileLock lock(stream);
+ ok = stream->close();
+ }
ScopedValueRollback errno_restorer(errno);
stream->~FILE();