[libc-commits] [libc] [libc] Add `shm_open/shm_unlink` (PR #84974)

Schrodinger ZHU Yifan via libc-commits libc-commits at lists.llvm.org
Tue Mar 12 12:12:45 PDT 2024


https://github.com/SchrodingerZhu updated https://github.com/llvm/llvm-project/pull/84974

>From 2dd697565fbdf6ecd50d051a41513e819067f3bb Mon Sep 17 00:00:00 2001
From: Schrodinger ZHU Yifan <yifanzhu at rochester.edu>
Date: Tue, 12 Mar 2024 12:35:39 -0400
Subject: [PATCH 1/2] [libc] add shm_open

---
 libc/config/linux/aarch64/entrypoints.txt   |  2 +
 libc/config/linux/api.td                    |  2 +-
 libc/config/linux/riscv/entrypoints.txt     |  2 +
 libc/config/linux/x86_64/entrypoints.txt    |  2 +
 libc/spec/posix.td                          | 11 +++
 libc/src/__support/CPP/string_view.h        |  9 +++
 libc/src/sys/mman/CMakeLists.txt            | 14 ++++
 libc/src/sys/mman/linux/CMakeLists.txt      | 37 ++++++++++
 libc/src/sys/mman/linux/shm_common.h        | 51 +++++++++++++
 libc/src/sys/mman/linux/shm_open.cpp        | 27 +++++++
 libc/src/sys/mman/linux/shm_unlink.cpp      | 24 +++++++
 libc/src/sys/mman/shm_open.h                | 20 ++++++
 libc/src/sys/mman/shm_unlink.h              | 19 +++++
 libc/test/src/sys/mman/linux/CMakeLists.txt | 20 ++++++
 libc/test/src/sys/mman/linux/shm_test.cpp   | 79 +++++++++++++++++++++
 15 files changed, 318 insertions(+), 1 deletion(-)
 create mode 100644 libc/src/sys/mman/linux/shm_common.h
 create mode 100644 libc/src/sys/mman/linux/shm_open.cpp
 create mode 100644 libc/src/sys/mman/linux/shm_unlink.cpp
 create mode 100644 libc/src/sys/mman/shm_open.h
 create mode 100644 libc/src/sys/mman/shm_unlink.h
 create mode 100644 libc/test/src/sys/mman/linux/shm_test.cpp

diff --git a/libc/config/linux/aarch64/entrypoints.txt b/libc/config/linux/aarch64/entrypoints.txt
index b447b5dfe0989e..bfaee0cecf38ff 100644
--- a/libc/config/linux/aarch64/entrypoints.txt
+++ b/libc/config/linux/aarch64/entrypoints.txt
@@ -186,6 +186,8 @@ set(TARGET_LIBC_ENTRYPOINTS
     libc.src.sys.mman.mlockall
     libc.src.sys.mman.munlockall
     libc.src.sys.mman.msync
+    libc.src.sys.mman.shm_open
+    libc.src.sys.mman.shm_unlink
 
     # sys/random.h entrypoints
     libc.src.sys.random.getrandom
diff --git a/libc/config/linux/api.td b/libc/config/linux/api.td
index 75432a2a298652..96fea3bbac94e5 100644
--- a/libc/config/linux/api.td
+++ b/libc/config/linux/api.td
@@ -118,7 +118,7 @@ def SchedAPI : PublicAPI<"sched.h"> {
 }
 
 def SysMManAPI : PublicAPI<"sys/mman.h"> {
-  let Types = ["off_t", "size_t"];
+  let Types = ["off_t", "size_t", "mode_t"];
 }
 
 def SignalAPI : PublicAPI<"signal.h"> {
diff --git a/libc/config/linux/riscv/entrypoints.txt b/libc/config/linux/riscv/entrypoints.txt
index 5175b14adf2e74..c3d4afe6b043f3 100644
--- a/libc/config/linux/riscv/entrypoints.txt
+++ b/libc/config/linux/riscv/entrypoints.txt
@@ -191,6 +191,8 @@ set(TARGET_LIBC_ENTRYPOINTS
     libc.src.sys.mman.mlockall
     libc.src.sys.mman.munlockall
     libc.src.sys.mman.msync
+    libc.src.sys.mman.shm_open
+    libc.src.sys.mman.shm_unlink
 
     # sys/random.h entrypoints
     libc.src.sys.random.getrandom
diff --git a/libc/config/linux/x86_64/entrypoints.txt b/libc/config/linux/x86_64/entrypoints.txt
index b8bec14a3d2a6d..5779945bfee563 100644
--- a/libc/config/linux/x86_64/entrypoints.txt
+++ b/libc/config/linux/x86_64/entrypoints.txt
@@ -229,6 +229,8 @@ set(TARGET_LIBC_ENTRYPOINTS
     libc.src.sys.mman.mlockall
     libc.src.sys.mman.munlockall
     libc.src.sys.mman.msync
+    libc.src.sys.mman.shm_open
+    libc.src.sys.mman.shm_unlink
 
     # sys/random.h entrypoints
     libc.src.sys.random.getrandom
diff --git a/libc/spec/posix.td b/libc/spec/posix.td
index d0f5a4584dd45b..d4187a7252d976 100644
--- a/libc/spec/posix.td
+++ b/libc/spec/posix.td
@@ -250,6 +250,7 @@ def POSIX : StandardSpec<"POSIX"> {
       [
         SizeTType,
         OffTType,
+        ModeTType,
       ],
       [], // Enumerations
       [
@@ -314,6 +315,16 @@ def POSIX : StandardSpec<"POSIX"> {
           RetValSpec<IntType>,
           [ArgSpec<VoidPtr>, ArgSpec<SizeTType>, ArgSpec<IntType>]
         >,
+        FunctionSpec<
+          "shm_open",
+          RetValSpec<IntType>,
+          [ArgSpec<ConstCharPtr>, ArgSpec<IntType>, ArgSpec<ModeTType>]
+        >,
+        FunctionSpec<
+          "shm_unlink",
+          RetValSpec<IntType>,
+          [ArgSpec<ConstCharPtr>]
+        >,
       ]
   >;
 
diff --git a/libc/src/__support/CPP/string_view.h b/libc/src/__support/CPP/string_view.h
index d23aa261ca0614..4a90de0f9a3a06 100644
--- a/libc/src/__support/CPP/string_view.h
+++ b/libc/src/__support/CPP/string_view.h
@@ -194,6 +194,15 @@ class string_view {
         return End - 1;
     return npos;
   }
+
+  // Finds the frist character not equal to c in this view, starting at position
+  // From.
+  LIBC_INLINE size_t find_first_not_of(const char c, size_t From = 0) const {
+    for (size_t Pos = From; Pos < size(); ++Pos)
+      if ((*this)[Pos] != c)
+        return Pos;
+    return npos;
+  }
 };
 
 } // namespace cpp
diff --git a/libc/src/sys/mman/CMakeLists.txt b/libc/src/sys/mman/CMakeLists.txt
index b49f73873c2006..9c74202a09f035 100644
--- a/libc/src/sys/mman/CMakeLists.txt
+++ b/libc/src/sys/mman/CMakeLists.txt
@@ -85,3 +85,17 @@ add_entrypoint_object(
   DEPENDS
     .${LIBC_TARGET_OS}.msync
 )
+
+add_entrypoint_object(
+  shm_open
+  ALIAS
+  DEPENDS
+    .${LIBC_TARGET_OS}.shm_open
+)
+
+add_entrypoint_object(
+  shm_unlink
+  ALIAS
+  DEPENDS
+    .${LIBC_TARGET_OS}.shm_unlink
+)
diff --git a/libc/src/sys/mman/linux/CMakeLists.txt b/libc/src/sys/mman/linux/CMakeLists.txt
index 04086ee5d33254..01ea19ad9793ba 100644
--- a/libc/src/sys/mman/linux/CMakeLists.txt
+++ b/libc/src/sys/mman/linux/CMakeLists.txt
@@ -152,3 +152,40 @@ add_entrypoint_object(
     libc.src.__support.OSUtil.osutil
     libc.src.errno.errno
 )
+
+add_header_library(
+  shm_common
+  HDRS
+    shm_common.h
+  DEPENDS
+    libc.src.__support.CPP.array
+    libc.src.__support.CPP.string_view
+    libc.src.__support.CPP.optional
+    libc.src.__support.common
+    libc.src.errno.errno
+    libc.src.string.memcpy
+    libc.src.string.memchr
+)
+
+add_entrypoint_object(
+  shm_open
+  SRCS
+    shm_open.cpp
+  HDRS
+    ../shm_open.h
+  DEPENDS
+    libc.src.fcntl.open
+    libc.include.fcntl
+    .shm_common
+)
+
+add_entrypoint_object(
+  shm_unlink
+  SRCS
+    shm_unlink.cpp
+  HDRS
+    ../shm_unlink.h
+  DEPENDS
+    libc.src.unistd.unlink
+    .shm_common
+)
diff --git a/libc/src/sys/mman/linux/shm_common.h b/libc/src/sys/mman/linux/shm_common.h
new file mode 100644
index 00000000000000..f938fe474c2070
--- /dev/null
+++ b/libc/src/sys/mman/linux/shm_common.h
@@ -0,0 +1,51 @@
+//===---------- Shared implementations for shm_open/shm_unlink ------------===//
+//
+// 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/__support/CPP/array.h"
+#include "src/__support/CPP/optional.h"
+#include "src/__support/CPP/string_view.h"
+#include "src/errno/libc_errno.h"
+#include "src/string/memchr.h"
+#include "src/string/memcpy.h"
+#include <asm/errno.h>
+#include <linux/limits.h>
+
+namespace LIBC_NAMESPACE {
+
+LIBC_INLINE_VAR constexpr cpp::string_view SHM_PREFIX = "/dev/shm/";
+using SHMPath = cpp::array<char, NAME_MAX + SHM_PREFIX.size() + 1>;
+
+LIBC_INLINE cpp::optional<SHMPath> get_shm_name(cpp::string_view name) {
+  // trim leading slashes
+  size_t offset = name.find_first_not_of('/');
+  if (offset == cpp::string_view::npos) {
+    libc_errno = EINVAL;
+    return cpp::nullopt;
+  }
+  name = name.substr(offset);
+
+  // check the name
+  if (name.size() > NAME_MAX) {
+    libc_errno = ENAMETOOLONG;
+    return cpp::nullopt;
+  }
+  if (name == "." || name == ".." ||
+      memchr(name.data(), '/', name.size()) != nullptr) {
+    libc_errno = EINVAL;
+    return cpp::nullopt;
+  }
+
+  // prepend the prefix
+  SHMPath buffer;
+  memcpy(buffer.data(), SHM_PREFIX.data(), SHM_PREFIX.size());
+  memcpy(buffer.data() + SHM_PREFIX.size(), name.data(), name.size());
+  buffer[SHM_PREFIX.size() + name.size()] = '\0';
+  return buffer;
+}
+
+} // namespace LIBC_NAMESPACE
diff --git a/libc/src/sys/mman/linux/shm_open.cpp b/libc/src/sys/mman/linux/shm_open.cpp
new file mode 100644
index 00000000000000..220c97be73ae65
--- /dev/null
+++ b/libc/src/sys/mman/linux/shm_open.cpp
@@ -0,0 +1,27 @@
+//===---------- Linux implementation of the shm_open function -------------===//
+//
+// 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/sys/mman/shm_open.h"
+#include "src/fcntl/open.h"
+#include "src/sys/mman/linux/shm_common.h"
+#include <asm/fcntl.h>
+#include <linux/limits.h>
+
+namespace LIBC_NAMESPACE {
+
+static constexpr int DEFAULT_OFLAGS = O_NOFOLLOW | O_CLOEXEC | O_NONBLOCK;
+
+LLVM_LIBC_FUNCTION(int, shm_open, (const char *name, int oflags, mode_t mode)) {
+  auto buffer = get_shm_name(name);
+  if (!buffer.has_value()) {
+    return -1;
+  }
+  return open(buffer->data(), oflags | DEFAULT_OFLAGS, mode);
+}
+
+} // namespace LIBC_NAMESPACE
diff --git a/libc/src/sys/mman/linux/shm_unlink.cpp b/libc/src/sys/mman/linux/shm_unlink.cpp
new file mode 100644
index 00000000000000..cb6f5b9163d249
--- /dev/null
+++ b/libc/src/sys/mman/linux/shm_unlink.cpp
@@ -0,0 +1,24 @@
+//===---------- Linux implementation of the shm_unlink function
+//-------------===//
+//
+// 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/sys/mman/shm_unlink.h"
+#include "src/sys/mman/linux/shm_common.h"
+#include "src/unistd/unlink.h"
+
+namespace LIBC_NAMESPACE {
+
+LLVM_LIBC_FUNCTION(int, shm_unlink, (const char *name)) {
+  auto buffer = get_shm_name(name);
+  if (!buffer.has_value()) {
+    return -1;
+  }
+  return unlink(buffer->data());
+}
+
+} // namespace LIBC_NAMESPACE
diff --git a/libc/src/sys/mman/shm_open.h b/libc/src/sys/mman/shm_open.h
new file mode 100644
index 00000000000000..97a2b641450d88
--- /dev/null
+++ b/libc/src/sys/mman/shm_open.h
@@ -0,0 +1,20 @@
+//===-- Implementation header for shm_open function -------------*- 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_SYS_MMAN_SHM_OPEN_H
+#define LLVM_LIBC_SRC_SYS_MMAN_SHM_OPEN_H
+
+#include <fcntl.h> // For mode_t.
+
+namespace LIBC_NAMESPACE {
+
+int shm_open(const char *name, int oflag, mode_t mode);
+
+} // namespace LIBC_NAMESPACE
+
+#endif // LLVM_LIBC_SRC_SYS_MMAN_SHM_OPEN_H
diff --git a/libc/src/sys/mman/shm_unlink.h b/libc/src/sys/mman/shm_unlink.h
new file mode 100644
index 00000000000000..9c40917405fbce
--- /dev/null
+++ b/libc/src/sys/mman/shm_unlink.h
@@ -0,0 +1,19 @@
+//===-- Implementation header for shm_unlink function -------------*- 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_SYS_MMAN_SHM_UNLINK_H
+#define LLVM_LIBC_SRC_SYS_MMAN_SHM_UNLINK_H
+
+namespace LIBC_NAMESPACE {
+
+int shm_unlink(const char *name);
+
+} // namespace LIBC_NAMESPACE
+
+#endif // LLVM_LIBC_SRC_SYS_MMAN_SHM_UNLINK_H
diff --git a/libc/test/src/sys/mman/linux/CMakeLists.txt b/libc/test/src/sys/mman/linux/CMakeLists.txt
index 6f7fc34d8d3ce3..0762a2d846a8e0 100644
--- a/libc/test/src/sys/mman/linux/CMakeLists.txt
+++ b/libc/test/src/sys/mman/linux/CMakeLists.txt
@@ -127,3 +127,23 @@ add_libc_unittest(
     libc.src.unistd.sysconf
     libc.test.UnitTest.ErrnoSetterMatcher
 )
+
+add_libc_unittest(
+  shm_test
+  SUITE
+    libc_sys_mman_unittests
+  SRCS
+    shm_test.cpp
+  DEPENDS
+    libc.include.sys_mman
+    libc.include.sys_syscall
+    libc.src.errno.errno
+    libc.src.sys.mman.shm_open
+    libc.src.sys.mman.shm_unlink
+    libc.src.sys.mman.mmap
+    libc.src.sys.mman.munmap
+    libc.src.unistd.ftruncate
+    libc.src.unistd.close
+    libc.src.__support.OSUtil.osutil
+    libc.test.UnitTest.ErrnoSetterMatcher
+)
diff --git a/libc/test/src/sys/mman/linux/shm_test.cpp b/libc/test/src/sys/mman/linux/shm_test.cpp
new file mode 100644
index 00000000000000..9d05066f778288
--- /dev/null
+++ b/libc/test/src/sys/mman/linux/shm_test.cpp
@@ -0,0 +1,79 @@
+//===-- Unittests for shm_open/shm_unlink ---------------------------------===//
+//
+// 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/__support/OSUtil/syscall.h"
+#include "src/sys/mman/mmap.h"
+#include "src/sys/mman/munmap.h"
+#include "src/sys/mman/shm_open.h"
+#include "src/sys/mman/shm_unlink.h"
+#include "src/unistd/close.h"
+#include "src/unistd/ftruncate.h"
+#include "test/UnitTest/ErrnoSetterMatcher.h"
+#include "test/UnitTest/LibcTest.h"
+#include <asm-generic/fcntl.h>
+#include <sys/syscall.h>
+
+using namespace LIBC_NAMESPACE::testing::ErrnoSetterMatcher;
+// since shm_open/shm_unlink are wrappers around open/unlink, we only focus on
+// testing basic cases and name conversions.
+
+TEST(LlvmLibcShmTest, Basic) {
+  const char *name = "/test_shm_open";
+  int fd;
+  ASSERT_THAT(fd = LIBC_NAMESPACE::shm_open(name, O_CREAT | O_RDWR, 0666),
+              returns(GE(0)).with_errno(EQ(0)));
+
+  // check that FD_CLOEXEC is set by default.
+  // TODO: use fcntl when implemented.
+  // https://github.com/llvm/llvm-project/issues/84968
+  long flag = LIBC_NAMESPACE::syscall_impl(SYS_fcntl, fd, F_GETFD);
+  ASSERT_GE(static_cast<int>(flag), 0);
+  EXPECT_NE(static_cast<int>(flag) & FD_CLOEXEC, 0);
+
+  // allocate space using ftruncate
+  ASSERT_THAT(LIBC_NAMESPACE::ftruncate(fd, 4096), Succeeds());
+  // map the shared memory
+  void *addr = LIBC_NAMESPACE::mmap(nullptr, 4096, PROT_READ | PROT_WRITE,
+                                    MAP_SHARED, fd, 0);
+  ASSERT_NE(addr, MAP_FAILED);
+  // just write random data to the shared memory
+  char data[] = "Despite its name, LLVM has little to do with traditional "
+                "virtual machines.";
+  for (size_t i = 0; i < sizeof(data); ++i) {
+    static_cast<char *>(addr)[i] = data[i];
+  }
+
+  // close fd does not affect the mapping
+  ASSERT_THAT(LIBC_NAMESPACE::close(fd), Succeeds());
+  for (size_t i = 0; i < sizeof(data); ++i) {
+    EXPECT_EQ(static_cast<char *>(addr)[i], data[i]);
+  }
+
+  // unmap the shared memory
+  ASSERT_THAT(LIBC_NAMESPACE::munmap(addr, 4096), Succeeds());
+  // remove the shared memory
+  ASSERT_THAT(LIBC_NAMESPACE::shm_unlink(name), Succeeds());
+}
+
+TEST(LlvmLibcShmTest, NameConversion) {
+  const char *name = "////test_shm_open";
+  int fd;
+  ASSERT_THAT(fd = LIBC_NAMESPACE::shm_open(name, O_CREAT | O_RDWR, 0666),
+              returns(GE(0)).with_errno(EQ(0)));
+  ASSERT_THAT(LIBC_NAMESPACE::close(fd), Succeeds());
+  ASSERT_THAT(LIBC_NAMESPACE::shm_unlink(name), Succeeds());
+
+  ASSERT_THAT(LIBC_NAMESPACE::shm_open("/123/123", O_CREAT | O_RDWR, 0666),
+              Fails(EINVAL));
+
+  ASSERT_THAT(LIBC_NAMESPACE::shm_open("/.", O_CREAT | O_RDWR, 0666),
+              Fails(EINVAL));
+
+  ASSERT_THAT(LIBC_NAMESPACE::shm_open("/..", O_CREAT | O_RDWR, 0666),
+              Fails(EINVAL));
+}

>From 628c04b2969dbbc81df0bf113f1dace4fd35b30d Mon Sep 17 00:00:00 2001
From: Schrodinger ZHU Yifan <yifanzhu at rochester.edu>
Date: Tue, 12 Mar 2024 15:12:31 -0400
Subject: [PATCH 2/2] fix header

---
 libc/src/sys/mman/linux/shm_unlink.cpp | 3 +--
 libc/src/sys/mman/shm_unlink.h         | 3 +--
 2 files changed, 2 insertions(+), 4 deletions(-)

diff --git a/libc/src/sys/mman/linux/shm_unlink.cpp b/libc/src/sys/mman/linux/shm_unlink.cpp
index cb6f5b9163d249..952415c3959052 100644
--- a/libc/src/sys/mman/linux/shm_unlink.cpp
+++ b/libc/src/sys/mman/linux/shm_unlink.cpp
@@ -1,5 +1,4 @@
-//===---------- Linux implementation of the shm_unlink function
-//-------------===//
+//===---------- Linux implementation of the shm_unlink function -----------===//
 //
 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
 // See https://llvm.org/LICENSE.txt for license information.
diff --git a/libc/src/sys/mman/shm_unlink.h b/libc/src/sys/mman/shm_unlink.h
index 9c40917405fbce..c38c06adbaa292 100644
--- a/libc/src/sys/mman/shm_unlink.h
+++ b/libc/src/sys/mman/shm_unlink.h
@@ -1,5 +1,4 @@
-//===-- Implementation header for shm_unlink function -------------*- C++
-//-*-===//
+//===-- Implementation header for shm_unlink function ------------*- C++-*-===//
 //
 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
 // See https://llvm.org/LICENSE.txt for license information.



More information about the libc-commits mailing list