[libc-commits] [libc] 945e022 - [libc] Add GNU extention functions fread_unlocked and fwrite_unlocked.

Siva Chandra Reddy via libc-commits libc-commits at lists.llvm.org
Wed Apr 20 08:39:58 PDT 2022


Author: Siva Chandra Reddy
Date: 2022-04-20T15:39:27Z
New Revision: 945e0220fd6f744f200ab93829b52c0c3c4031af

URL: https://github.com/llvm/llvm-project/commit/945e0220fd6f744f200ab93829b52c0c3c4031af
DIFF: https://github.com/llvm/llvm-project/commit/945e0220fd6f744f200ab93829b52c0c3c4031af.diff

LOG: [libc] Add GNU extention functions fread_unlocked and fwrite_unlocked.

POSIX locking and unlocking functions flockfile and funlockfile have
also been added. The locking is not recursive yet. A future patch will
make the underlying lock a recursive lock.

Reviewed By: lntue

Differential Revision: https://reviews.llvm.org/D123986

Added: 
    libc/src/stdio/flockfile.cpp
    libc/src/stdio/flockfile.h
    libc/src/stdio/fread_unlocked.cpp
    libc/src/stdio/fread_unlocked.h
    libc/src/stdio/funlockfile.cpp
    libc/src/stdio/funlockfile.h
    libc/src/stdio/fwrite_unlocked.cpp
    libc/src/stdio/fwrite_unlocked.h
    libc/test/src/stdio/unlocked_fileop_test.cpp

Modified: 
    libc/config/linux/x86_64/entrypoints.txt
    libc/spec/gnu_ext.td
    libc/spec/posix.td
    libc/spec/spec.td
    libc/spec/stdc.td
    libc/src/__support/File/file.cpp
    libc/src/__support/File/file.h
    libc/src/stdio/CMakeLists.txt
    libc/test/src/stdio/CMakeLists.txt

Removed: 
    


################################################################################
diff  --git a/libc/config/linux/x86_64/entrypoints.txt b/libc/config/linux/x86_64/entrypoints.txt
index 5fc5d19f75208..c7af459c36381 100644
--- a/libc/config/linux/x86_64/entrypoints.txt
+++ b/libc/config/linux/x86_64/entrypoints.txt
@@ -252,10 +252,14 @@ if(LLVM_LIBC_FULL_BUILD)
 
     # stdio.h entrypoints
     libc.src.stdio.fclose
+    libc.src.stdio.flockfile
     libc.src.stdio.fopen
     libc.src.stdio.fread
+    libc.src.stdio.fread_unlocked
     libc.src.stdio.fseek
+    libc.src.stdio.funlockfile
     libc.src.stdio.fwrite
+    libc.src.stdio.fwrite_unlocked
 
     # signal.h entrypoints
     # TODO: Enable signal.h entrypoints after fixing signal.h

diff  --git a/libc/spec/gnu_ext.td b/libc/spec/gnu_ext.td
index 99b78deed28b4..14ede61beffd9 100644
--- a/libc/spec/gnu_ext.td
+++ b/libc/spec/gnu_ext.td
@@ -65,10 +65,36 @@ def GnuExtensions : StandardSpec<"GNUExtensions"> {
       ]
   >;
 
+  HeaderSpec StdIO = HeaderSpec<
+      "stdio.h",
+      [], // Macros
+      [], // Types
+      [], // Enumerations
+      [
+          FunctionSpec<
+              "fread_unlocked",
+              RetValSpec<SizeTType>,
+              [ArgSpec<VoidRestrictedPtr>,
+               ArgSpec<SizeTType>,
+               ArgSpec<SizeTType>,
+               ArgSpec<FILERestrictedPtr>]
+          >,
+          FunctionSpec<
+              "fwrite_unlocked",
+              RetValSpec<SizeTType>,
+              [ArgSpec<ConstVoidRestrictedPtr>,
+               ArgSpec<SizeTType>,
+               ArgSpec<SizeTType>,
+               ArgSpec<FILERestrictedPtr>]
+          >,
+      ]
+   >;
+
   let Headers = [
     CType,
     FEnv,
-    Math, 
+    Math,
+    StdIO,
     String,
   ];
 }

diff  --git a/libc/spec/posix.td b/libc/spec/posix.td
index 13b4ed4ce49d3..fbb6a78225dd8 100644
--- a/libc/spec/posix.td
+++ b/libc/spec/posix.td
@@ -502,12 +502,32 @@ def POSIX : StandardSpec<"POSIX"> {
     ]
   >;
 
+  HeaderSpec StdIO = HeaderSpec<
+      "stdio.h",
+      [], // Macros
+      [], // Types
+      [], // Enumerations
+      [
+          FunctionSpec<
+              "flockfile",
+              RetValSpec<VoidType>,
+              [ArgSpec<FILEPtr>]
+          >,
+          FunctionSpec<
+              "funlockfile",
+              RetValSpec<VoidType>,
+              [ArgSpec<FILEPtr>]
+          >,
+      ]
+  >;
+
   let Headers = [
     CType,
     Errno,
     FCntl,
     PThread,
     Signal,
+    StdIO,
     StdLib,
     SysMMan,
     SysStat,

diff  --git a/libc/spec/spec.td b/libc/spec/spec.td
index 5c947e4a17cad..198900788c50e 100644
--- a/libc/spec/spec.td
+++ b/libc/spec/spec.td
@@ -103,6 +103,10 @@ def QSortCompareT : NamedType<"__qsortcompare_t">;
 
 def AtexitHandlerT : NamedType<"__atexithandler_t">;
 
+def FILE : NamedType<"FILE">;
+def FILEPtr : PtrType<FILE>;
+def FILERestrictedPtr : RestrictedPtrType<FILE>;
+
 //added because __assert_fail needs it.
 def UnsignedType : NamedType<"unsigned">;
 

diff  --git a/libc/spec/stdc.td b/libc/spec/stdc.td
index 7f57a2ddfab02..10a980bf98df3 100644
--- a/libc/spec/stdc.td
+++ b/libc/spec/stdc.td
@@ -1,8 +1,5 @@
 def StdC : StandardSpec<"stdc"> {
 
-  NamedType FILE = NamedType<"FILE">;
-  PtrType FILEPtr = PtrType<FILE>;
-  RestrictedPtrType FILERestrictedPtr = RestrictedPtrType<FILE>;
   NamedType StructTmType = NamedType<"struct tm">;
   PtrType StructTmPtr = PtrType<StructTmType>;
   PtrType TimeTTypePtr = PtrType<TimeTType>;

diff  --git a/libc/src/__support/File/file.cpp b/libc/src/__support/File/file.cpp
index 3f2928c5c32e3..95f464d1df8df 100644
--- a/libc/src/__support/File/file.cpp
+++ b/libc/src/__support/File/file.cpp
@@ -16,9 +16,7 @@
 
 namespace __llvm_libc {
 
-size_t File::write(const void *data, size_t len) {
-  FileLock lock(this);
-
+size_t File::write_unlocked(const void *data, size_t len) {
   if (!write_allowed()) {
     errno = EBADF;
     err = true;
@@ -76,9 +74,7 @@ size_t File::write(const void *data, size_t len) {
   return len;
 }
 
-size_t File::read(void *data, size_t len) {
-  FileLock lock(this);
-
+size_t File::read_unlocked(void *data, size_t len) {
   if (!read_allowed()) {
     errno = EBADF;
     err = true;

diff  --git a/libc/src/__support/File/file.h b/libc/src/__support/File/file.h
index 26849ad96b23e..fdc0d45e4c857 100644
--- a/libc/src/__support/File/file.h
+++ b/libc/src/__support/File/file.h
@@ -145,11 +145,27 @@ class File {
     f->eof = f->err = false;
   }
 
-  // Buffered write of |len| bytes from |data|.
-  size_t write(const void *data, size_t len);
+  // Buffered write of |len| bytes from |data| without the file lock.
+  size_t write_unlocked(const void *data, size_t len);
+
+  // Buffered write of |len| bytes from |data| under the file lock.
+  size_t write(const void *data, size_t len) {
+    lock();
+    size_t ret = write_unlocked(data, len);
+    unlock();
+    return ret;
+  }
+
+  // Buffered read of |len| bytes into |data| without the file lock.
+  size_t read_unlocked(void *data, size_t len);
 
-  // Buffered read of |len| bytes into |data|.
-  size_t read(void *data, size_t len);
+  // Buffered read of |len| bytes into |data| under the file lock.
+  size_t read(void *data, size_t len) {
+    lock();
+    size_t ret = read_unlocked(data, len);
+    unlock();
+    return ret;
+  }
 
   int seek(long offset, int whence);
 

diff  --git a/libc/src/stdio/CMakeLists.txt b/libc/src/stdio/CMakeLists.txt
index 19a3cd1c7f776..493244257850d 100644
--- a/libc/src/stdio/CMakeLists.txt
+++ b/libc/src/stdio/CMakeLists.txt
@@ -24,6 +24,42 @@ add_entrypoint_object(
     libc.src.__support.File.platform_file
 )
 
+add_entrypoint_object(
+  flockfile
+  SRCS
+    flockfile.cpp
+  HDRS
+    flockfile.h
+  DEPENDS
+    libc.include.stdio
+    libc.src.__support.File.file
+    libc.src.__support.File.platform_file
+)
+
+add_entrypoint_object(
+  funlockfile
+  SRCS
+    funlockfile.cpp
+  HDRS
+    funlockfile.h
+  DEPENDS
+    libc.include.stdio
+    libc.src.__support.File.file
+    libc.src.__support.File.platform_file
+)
+
+add_entrypoint_object(
+  fread_unlocked
+  SRCS
+    fread_unlocked.cpp
+  HDRS
+    fread_unlocked.h
+  DEPENDS
+    libc.include.stdio
+    libc.src.__support.File.file
+    libc.src.__support.File.platform_file
+)
+
 add_entrypoint_object(
   fread
   SRCS
@@ -36,6 +72,18 @@ add_entrypoint_object(
     libc.src.__support.File.platform_file
 )
 
+add_entrypoint_object(
+  fwrite_unlocked
+  SRCS
+    fwrite_unlocked.cpp
+  HDRS
+    fwrite_unlocked.h
+  DEPENDS
+    libc.include.stdio
+    libc.src.__support.File.file
+    libc.src.__support.File.platform_file
+)
+
 add_entrypoint_object(
   fwrite
   SRCS

diff  --git a/libc/src/stdio/flockfile.cpp b/libc/src/stdio/flockfile.cpp
new file mode 100644
index 0000000000000..3b13a6f4d813d
--- /dev/null
+++ b/libc/src/stdio/flockfile.cpp
@@ -0,0 +1,20 @@
+//===-- Implementation of flockfile ---------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "src/stdio/flockfile.h"
+#include "src/__support/File/file.h"
+
+#include <stdio.h>
+
+namespace __llvm_libc {
+
+LLVM_LIBC_FUNCTION(void, flockfile, (::FILE * stream)) {
+  reinterpret_cast<__llvm_libc::File *>(stream)->lock();
+}
+
+} // namespace __llvm_libc

diff  --git a/libc/src/stdio/flockfile.h b/libc/src/stdio/flockfile.h
new file mode 100644
index 0000000000000..961ad8f941cdf
--- /dev/null
+++ b/libc/src/stdio/flockfile.h
@@ -0,0 +1,20 @@
+//===-- Implementation header of flockfile ----------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC_STDIO_FLOCKFILE_H
+#define LLVM_LIBC_SRC_STDIO_FLOCKFILE_H
+
+#include <stdio.h>
+
+namespace __llvm_libc {
+
+void flockfile(::FILE *stream);
+
+} // namespace __llvm_libc
+
+#endif // LLVM_LIBC_SRC_STDIO_FLOCKFILE_H

diff  --git a/libc/src/stdio/fread_unlocked.cpp b/libc/src/stdio/fread_unlocked.cpp
new file mode 100644
index 0000000000000..162cc4e9a4122
--- /dev/null
+++ b/libc/src/stdio/fread_unlocked.cpp
@@ -0,0 +1,23 @@
+//===-- Implementation of fread_unlocked ----------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "src/stdio/fread_unlocked.h"
+#include "src/__support/File/file.h"
+
+#include <stdio.h>
+
+namespace __llvm_libc {
+
+LLVM_LIBC_FUNCTION(size_t, fread_unlocked,
+                   (void *__restrict buffer, size_t size, size_t nmemb,
+                    ::FILE *stream)) {
+  return reinterpret_cast<__llvm_libc::File *>(stream)->read_unlocked(
+      buffer, size * nmemb);
+}
+
+} // namespace __llvm_libc

diff  --git a/libc/src/stdio/fread_unlocked.h b/libc/src/stdio/fread_unlocked.h
new file mode 100644
index 0000000000000..5c965b0f168cd
--- /dev/null
+++ b/libc/src/stdio/fread_unlocked.h
@@ -0,0 +1,21 @@
+//===-- Implementation header of fread_unlocked -----------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC_STDIO_FREAD_UNLOCKED_H
+#define LLVM_LIBC_SRC_STDIO_FREAD_UNLOCKED_H
+
+#include <stdio.h>
+
+namespace __llvm_libc {
+
+size_t fread_unlocked(void *__restrict buffer, size_t size, size_t nmemb,
+                      ::FILE *stream);
+
+} // namespace __llvm_libc
+
+#endif // LLVM_LIBC_SRC_STDIO_FREAD_UNLOCKED_H

diff  --git a/libc/src/stdio/funlockfile.cpp b/libc/src/stdio/funlockfile.cpp
new file mode 100644
index 0000000000000..6c7dbee303cbb
--- /dev/null
+++ b/libc/src/stdio/funlockfile.cpp
@@ -0,0 +1,20 @@
+//===-- Implementation of funlockfile -------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "src/stdio/funlockfile.h"
+#include "src/__support/File/file.h"
+
+#include <stdio.h>
+
+namespace __llvm_libc {
+
+LLVM_LIBC_FUNCTION(void, funlockfile, (::FILE * stream)) {
+  reinterpret_cast<__llvm_libc::File *>(stream)->unlock();
+}
+
+} // namespace __llvm_libc

diff  --git a/libc/src/stdio/funlockfile.h b/libc/src/stdio/funlockfile.h
new file mode 100644
index 0000000000000..cb04b7e9550ec
--- /dev/null
+++ b/libc/src/stdio/funlockfile.h
@@ -0,0 +1,20 @@
+//===-- Implementation header of funlockfile --------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC_STDIO_FUNLOCKFILE_H
+#define LLVM_LIBC_SRC_STDIO_FUNLOCKFILE_H
+
+#include <stdio.h>
+
+namespace __llvm_libc {
+
+void funlockfile(::FILE *stream);
+
+} // namespace __llvm_libc
+
+#endif // LLVM_LIBC_SRC_STDIO_FUNLOCKFILE_H

diff  --git a/libc/src/stdio/fwrite_unlocked.cpp b/libc/src/stdio/fwrite_unlocked.cpp
new file mode 100644
index 0000000000000..085b77516d9eb
--- /dev/null
+++ b/libc/src/stdio/fwrite_unlocked.cpp
@@ -0,0 +1,23 @@
+//===-- Implementation of fwrite_unlocked ---------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "src/stdio/fwrite_unlocked.h"
+#include "src/__support/File/file.h"
+
+#include <stdio.h>
+
+namespace __llvm_libc {
+
+LLVM_LIBC_FUNCTION(size_t, fwrite_unlocked,
+                   (const void *__restrict buffer, size_t size, size_t nmemb,
+                    ::FILE *stream)) {
+  return reinterpret_cast<__llvm_libc::File *>(stream)->write_unlocked(
+      buffer, size * nmemb);
+}
+
+} // namespace __llvm_libc

diff  --git a/libc/src/stdio/fwrite_unlocked.h b/libc/src/stdio/fwrite_unlocked.h
new file mode 100644
index 0000000000000..33bcc219d2efa
--- /dev/null
+++ b/libc/src/stdio/fwrite_unlocked.h
@@ -0,0 +1,21 @@
+//===-- Implementation header of fwrite_unlocked ----------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC_STDIO_FWRITE_UNLOCKED_H
+#define LLVM_LIBC_SRC_STDIO_FWRITE_UNLOCKED_H
+
+#include <stdio.h>
+
+namespace __llvm_libc {
+
+size_t fwrite_unlocked(const void *__restrict ptr, size_t size, size_t nmemb,
+                       ::FILE *__restrict stream);
+
+} // namespace __llvm_libc
+
+#endif // LLVM_LIBC_SRC_STDIO_FWRITE_UNLOCKED_H

diff  --git a/libc/test/src/stdio/CMakeLists.txt b/libc/test/src/stdio/CMakeLists.txt
index 45717593007b3..6a955ba742c70 100644
--- a/libc/test/src/stdio/CMakeLists.txt
+++ b/libc/test/src/stdio/CMakeLists.txt
@@ -14,6 +14,21 @@ add_libc_unittest(
     libc.src.stdio.fwrite
 )
 
+add_libc_unittest(
+  unlocked_fileop_test
+  SUITE
+    libc_stdio_unittests
+  SRCS
+    unlocked_fileop_test.cpp
+  DEPENDS
+    libc.src.stdio.fclose
+    libc.src.stdio.flockfile
+    libc.src.stdio.fopen
+    libc.src.stdio.fread_unlocked
+    libc.src.stdio.funlockfile
+    libc.src.stdio.fwrite_unlocked
+)
+
 add_subdirectory(printf_core)
 
 add_subdirectory(testdata)

diff  --git a/libc/test/src/stdio/unlocked_fileop_test.cpp b/libc/test/src/stdio/unlocked_fileop_test.cpp
new file mode 100644
index 0000000000000..6e936efd7b8bd
--- /dev/null
+++ b/libc/test/src/stdio/unlocked_fileop_test.cpp
@@ -0,0 +1,44 @@
+//===-- Unittests for file operations like fopen, flcose etc --------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "src/stdio/fclose.h"
+#include "src/stdio/flockfile.h"
+#include "src/stdio/fopen.h"
+#include "src/stdio/fread_unlocked.h"
+#include "src/stdio/funlockfile.h"
+#include "src/stdio/fwrite_unlocked.h"
+#include "utils/UnitTest/Test.h"
+
+#include <stdio.h>
+
+TEST(LlvmLibcFILETest, UnlockedReadAndWrite) {
+  constexpr char FILENAME[] = "testdata/unlocked_read_and_write.test";
+  ::FILE *file = __llvm_libc::fopen(FILENAME, "w");
+  ASSERT_FALSE(file == nullptr);
+  constexpr char CONTENT[] = "1234567890987654321";
+  __llvm_libc::flockfile(file);
+  ASSERT_EQ(sizeof(CONTENT) - 1, __llvm_libc::fwrite_unlocked(
+                                     CONTENT, 1, sizeof(CONTENT) - 1, file));
+  __llvm_libc::funlockfile(file);
+  ASSERT_EQ(0, __llvm_libc::fclose(file));
+
+  file = __llvm_libc::fopen(FILENAME, "r");
+  ASSERT_FALSE(file == nullptr);
+
+  constexpr size_t READ_SIZE = 5;
+  char data[READ_SIZE * 2 + 1];
+  data[READ_SIZE * 2] = '\0';
+  __llvm_libc::flockfile(file);
+  ASSERT_EQ(__llvm_libc::fread_unlocked(data, 1, READ_SIZE, file), READ_SIZE);
+  ASSERT_EQ(__llvm_libc::fread_unlocked(data + READ_SIZE, 1, READ_SIZE, file),
+            READ_SIZE);
+  __llvm_libc::funlockfile(file);
+  ASSERT_STREQ(data, "1234567890");
+
+  ASSERT_EQ(__llvm_libc::fclose(file), 0);
+}


        


More information about the libc-commits mailing list