Przeglądaj źródła

LibC: Make stdio thread-safe

Gunnar Beutner 4 lat temu
rodzic
commit
62ee003ef5
1 zmienionych plików z 60 dodań i 1 usunięć
  1. 60 1
      Userland/Libraries/LibC/stdio.cpp

+ 60 - 1
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();