diff options
author | Gunnar Beutner <gbeutner@serenityos.org> | 2021-04-29 21:17:32 +0200 |
---|---|---|
committer | Andreas Kling <kling@serenityos.org> | 2021-04-29 23:12:05 +0200 |
commit | 62ee003ef54b18ce23727b2b9d33137232a39fb9 (patch) | |
tree | 1426b15435b156a626d2818b2bfe5680ddeb7737 /Userland/Libraries/LibC | |
parent | ad688ffc73d79cbf61db1ceb09a233de4eb016b4 (diff) | |
download | serenity-62ee003ef54b18ce23727b2b9d33137232a39fb9.zip |
LibC: Make stdio thread-safe
Diffstat (limited to 'Userland/Libraries/LibC')
-rw-r--r-- | Userland/Libraries/LibC/stdio.cpp | 61 |
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(); |