[libc-commits] [libc] [libc] Provide sys/queue.h (PR #78081)
Petr Hosek via libc-commits
libc-commits at lists.llvm.org
Thu Jan 18 19:24:56 PST 2024
https://github.com/petrhosek updated https://github.com/llvm/llvm-project/pull/78081
>From 7c725a98e7ede888b0540b2bdcbc103d598b2df3 Mon Sep 17 00:00:00 2001
From: Petr Hosek <phosek at google.com>
Date: Sun, 14 Jan 2024 04:37:41 +0000
Subject: [PATCH 1/6] [libc] Provide sys/queue.h
This header first appeared in 4.4BSD and is provided by a number of C
libraries including Newlib. Several of our embedded projects use this
header and so to make LLVM libc a drop-in replacement, we need to
provide it as well.
For the initial commit, we only implement singly linked variants (SLIST
and STAILQ). The doubly linked variants (LIST, TAILQ and CIRCLEQ) can be
implemented in the future as needed.
---
libc/config/baremetal/arm/headers.txt | 1 +
libc/config/baremetal/riscv/headers.txt | 1 +
libc/include/CMakeLists.txt | 8 ++
libc/include/sys/queue.h | 161 ++++++++++++++++++++++++
libc/test/CMakeLists.txt | 1 +
libc/test/include/CMakeLists.txt | 13 ++
libc/test/include/sys/queue_test.cpp | 123 ++++++++++++++++++
7 files changed, 308 insertions(+)
create mode 100644 libc/include/sys/queue.h
create mode 100644 libc/test/include/CMakeLists.txt
create mode 100644 libc/test/include/sys/queue_test.cpp
diff --git a/libc/config/baremetal/arm/headers.txt b/libc/config/baremetal/arm/headers.txt
index e7be1fd80e8754..6ff51f9786772b 100644
--- a/libc/config/baremetal/arm/headers.txt
+++ b/libc/config/baremetal/arm/headers.txt
@@ -8,4 +8,5 @@ set(TARGET_PUBLIC_HEADERS
libc.include.stdlib
libc.include.string
libc.include.strings
+ libc.include.sys_queue
)
diff --git a/libc/config/baremetal/riscv/headers.txt b/libc/config/baremetal/riscv/headers.txt
index e7be1fd80e8754..6ff51f9786772b 100644
--- a/libc/config/baremetal/riscv/headers.txt
+++ b/libc/config/baremetal/riscv/headers.txt
@@ -8,4 +8,5 @@ set(TARGET_PUBLIC_HEADERS
libc.include.stdlib
libc.include.string
libc.include.strings
+ libc.include.sys_queue
)
diff --git a/libc/include/CMakeLists.txt b/libc/include/CMakeLists.txt
index 2c2d1b9b0fd155..cc846a25e85d65 100644
--- a/libc/include/CMakeLists.txt
+++ b/libc/include/CMakeLists.txt
@@ -345,6 +345,14 @@ add_gen_header(
.llvm_libc_common_h
)
+add_header(
+ sys_queue
+ HDR
+ sys/queue.h
+ DEPENDS
+ .llvm-libc-macros.null_macro
+)
+
add_gen_header(
sys_random
DEF_FILE sys/random.h.def
diff --git a/libc/include/sys/queue.h b/libc/include/sys/queue.h
new file mode 100644
index 00000000000000..4eab6ef91f183c
--- /dev/null
+++ b/libc/include/sys/queue.h
@@ -0,0 +1,161 @@
+//===-- Macros defined in sys/queue.h header file -------------------------===//
+//
+// 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_MACROS_SYS_QUEUE_MACROS_H
+#define __LLVM_LIBC_MACROS_SYS_QUEUE_MACROS_H
+
+#include <llvm-libc-macros/null-macro.h>
+
+// Singly-linked list definitions.
+
+#define SLIST_HEAD(name, type) \
+ struct name { \
+ struct type *first; \
+ }
+
+#define SLIST_HEAD_INITIALIZER(head) \
+ { NULL }
+
+#define SLIST_ENTRY(type) \
+ struct { \
+ struct type *next; \
+ }
+
+// Singly-linked list access methods.
+
+#define SLIST_EMPTY(head) ((head)->first == NULL)
+#define SLIST_FIRST(head) ((head)->first)
+#define SLIST_NEXT(elem, field) ((elem)->field.next)
+
+#define SLIST_FOREACH(var, head, field) \
+ for ((var) = SLIST_FIRST(head); (var); (var) = SLIST_NEXT(var, field))
+
+#define SLIST_FOREACH_SAFE(var, head, field, tvar) \
+ for ((var) = SLIST_FIRST(head); \
+ (var) && ((tvar) = SLIST_NEXT(var, field), 1); (var) = (tvar))
+
+// Singly-linked list functions.
+
+#define SLIST_INIT(head) \
+ do { \
+ SLIST_FIRST(head) = NULL; \
+ } while (0)
+
+#define SLIST_INSERT_HEAD(head, elem, field) \
+ do { \
+ SLIST_NEXT(elem, field) = SLIST_FIRST(head); \
+ SLIST_FIRST(head) = (elem); \
+ } while (0)
+
+#define SLIST_INSERT_AFTER(slistelem, elem, field) \
+ do { \
+ SLIST_NEXT(elem, field) = SLIST_NEXT(slistelem, field); \
+ SLIST_NEXT(slistelem, field) = (elem); \
+ } while (0)
+
+#define SLIST_REMOVE_HEAD(head, field) \
+ do { \
+ SLIST_FIRST(head) = SLIST_NEXT(SLIST_FIRST(head), field); \
+ } while (0)
+
+#define SLIST_REMOVE_AFTER(elem, field) \
+ do { \
+ SLIST_NEXT(elem, field) = SLIST_NEXT(SLIST_NEXT(elem, field), field); \
+ } while (0)
+
+#define SLIST_REMOVE(head, elem, type, field) \
+ do { \
+ if (SLIST_FIRST(head) == (elem)) { \
+ SLIST_REMOVE_HEAD(head, field); \
+ } else { \
+ struct type *cur = SLIST_FIRST(head); \
+ while (SLIST_NEXT(elem, field) != (elem)) \
+ cur = SLIST_NEXT(elem, field); \
+ SLIST_REMOVE_AFTER(cur, field); \
+ } \
+ } while (0)
+
+// Singly-linked tail queue definitions.
+
+#define STAILQ_HEAD(name, type) \
+ struct name { \
+ struct type *first; \
+ struct type **last; \
+ }
+
+#define STAILQ_HEAD_INITIALIZER(head) \
+ { NULL, &(head).first }
+
+#define STAILQ_ENTRY(type) \
+ struct { \
+ struct type *next; \
+ }
+
+// Singly-linked tail queue access methods.
+
+#define STAILQ_EMPTY(head) ((head)->first == NULL)
+#define STAILQ_FIRST(head) ((head)->first)
+#define STAILQ_NEXT(elem, field) ((elem)->field.next)
+
+#define STAILQ_FOREACH(var, head, field) \
+ for ((var) = STAILQ_FIRST(head); (var); (var) = STAILQ_NEXT(var, field))
+
+#define STAILQ_FOREACH_SAFE(var, head, field, tvar) \
+ for ((var) = STAILQ_FIRST(head); \
+ (var) && ((tvar) = STAILQ_NEXT(var, field), 1); (var) = (tvar))
+
+// Singly-linked tail queue functions.
+
+#define STAILQ_INIT(head) \
+ do { \
+ STAILQ_FIRST(head) = NULL; \
+ (head)->last = &STAILQ_FIRST(head); \
+ } while (0)
+
+#define STAILQ_INSERT_HEAD(head, elem, field) \
+ do { \
+ if ((STAILQ_NEXT(elem, field) = STAILQ_FIRST(head)) == NULL) \
+ (head)->last = &STAILQ_NEXT(elem, field); \
+ STAILQ_FIRST(head) = (elem); \
+ } while (0)
+
+#define STAILQ_INSERT_TAIL(head, elem, field) \
+ do { \
+ STAILQ_NEXT(elem, field) = NULL; \
+ *(head)->last = (elem); \
+ (head)->last = &STAILQ_NEXT(elem, field); \
+ } while (0)
+
+#define STAILQ_INSERT_AFTER(head, listelem, elem, field) \
+ do { \
+ if ((STAILQ_NEXT(elem, field) = STAILQ_NEXT(listelem, field)) == NULL) \
+ (head)->last = &STAILQ_NEXT(elem, field); \
+ STAILQ_NEXT(listelem, next) = (elem); \
+ } while (0)
+
+#define STAILQ_REMOVE_HEAD(head, field) \
+ do { \
+ if ((STAILQ_FIRST(head) = STAILQ_NEXT(STAILQ_FIRST(head), field)) == NULL) \
+ (head)->last = &STAILQ_FIRST(head); \
+ } while (0)
+
+#define STAILQ_REMOVE(head, elem, type, field) \
+ do { \
+ if (STAILQ_FIRST(head) == (elem)) { \
+ STAILQ_REMOVE_HEAD(head, field); \
+ } else { \
+ struct type *cur = STAILQ_FIRST(head); \
+ while (STAILQ_NEXT(elem, field) != (elem)) \
+ cur = STAILQ_NEXT(cur, field); \
+ if ((STAILQ_NEXT(cur, field) = \
+ STAILQ_NEXT(STAILQ_NEXT(cur, field), field)) == NULL) \
+ (head)->last = &STAILQ_NEXT(cur, field); \
+ } \
+ } while (0)
+
+#endif // __LLVM_LIBC_MACROS_SYS_QUEUE_MACROS_H
diff --git a/libc/test/CMakeLists.txt b/libc/test/CMakeLists.txt
index 5e8231ef27f461..f22f2b183aca92 100644
--- a/libc/test/CMakeLists.txt
+++ b/libc/test/CMakeLists.txt
@@ -14,6 +14,7 @@ if(LIBC_TARGET_ARCHITECTURE_IS_GPU AND
return()
endif()
+add_subdirectory(include)
add_subdirectory(src)
add_subdirectory(utils)
diff --git a/libc/test/include/CMakeLists.txt b/libc/test/include/CMakeLists.txt
new file mode 100644
index 00000000000000..ea1942befa5952
--- /dev/null
+++ b/libc/test/include/CMakeLists.txt
@@ -0,0 +1,13 @@
+add_custom_target(libc_include_tests)
+
+add_libc_test(
+ sys_queue_test
+ SUITE
+ libc_include_tests
+ SRCS
+ sys/queue_test.cpp
+ DEPENDS
+ libc.include.sys_queue
+ libc.src.__support.char_vector
+ libc.src.__support.CPP.string
+)
diff --git a/libc/test/include/sys/queue_test.cpp b/libc/test/include/sys/queue_test.cpp
new file mode 100644
index 00000000000000..4d0daf6190f12d
--- /dev/null
+++ b/libc/test/include/sys/queue_test.cpp
@@ -0,0 +1,123 @@
+//===-- Unittests for queue -----------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDSList-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "src/__support/CPP/string.h"
+#include "src/__support/char_vector.h"
+#include "test/UnitTest/Test.h"
+
+#include <sys/queue.h>
+
+using LIBC_NAMESPACE::CharVector;
+using LIBC_NAMESPACE::cpp::string;
+
+namespace LIBC_NAMESPACE {
+
+TEST(LlvmLibcQueueTest, SList) {
+ struct Contrived {
+ char c;
+ SLIST_ENTRY(Contrived) entry;
+ };
+
+ SLIST_HEAD(Head, Contrived) head = SLIST_HEAD_INITIALIZER(head);
+
+ struct Contains : public testing::Matcher<Head> {
+ string s;
+ Contains(string s) : s(s) {}
+ bool match(Head head) {
+ Contrived *e;
+ CharVector v;
+ SLIST_FOREACH(e, &head, entry) { v.append(e->c); }
+ return s == v.c_str();
+ }
+ };
+
+ SLIST_INIT(&head);
+ ASSERT_TRUE(SLIST_EMPTY(&head));
+
+ Contrived e1 = {'a', {NULL}};
+ SLIST_INSERT_HEAD(&head, &e1, entry);
+
+ ASSERT_THAT(head, Contains("a"));
+
+ Contrived e2 = {'b', {NULL}};
+ SLIST_INSERT_AFTER(&e1, &e2, entry);
+
+ ASSERT_THAT(head, Contains("ab"));
+
+ Contrived *e, *tmp = NULL;
+ SLIST_FOREACH_SAFE(e, &head, entry, tmp) {
+ if (e == &e2) {
+ SLIST_REMOVE(&head, e, Contrived, entry);
+ }
+ }
+
+ ASSERT_THAT(head, Contains("a"));
+
+ while (!SLIST_EMPTY(&head)) {
+ e = SLIST_FIRST(&head);
+ SLIST_REMOVE_HEAD(&head, entry);
+ }
+
+ ASSERT_TRUE(SLIST_EMPTY(&head));
+}
+
+TEST(LlvmLibcQueueTest, STailQ) {
+ struct Contrived {
+ char c;
+ STAILQ_ENTRY(Contrived) entry;
+ };
+
+ STAILQ_HEAD(Head, Contrived) head = STAILQ_HEAD_INITIALIZER(head);
+
+ struct Contains : public testing::Matcher<Head> {
+ string s;
+ Contains(string s) : s(s) {}
+ bool match(Head head) {
+ Contrived *e;
+ CharVector v;
+ STAILQ_FOREACH(e, &head, entry) { v.append(e->c); }
+ return s == v.c_str();
+ }
+ };
+
+ STAILQ_INIT(&head);
+ ASSERT_TRUE(STAILQ_EMPTY(&head));
+
+ Contrived e1 = {'a', {NULL}};
+ STAILQ_INSERT_HEAD(&head, &e1, entry);
+
+ ASSERT_THAT(head, Contains("a"));
+
+ Contrived e2 = {'b', {NULL}};
+ STAILQ_INSERT_TAIL(&head, &e2, entry);
+
+ ASSERT_THAT(head, Contains("ab"));
+
+ Contrived e3 = {'c', {NULL}};
+ SLIST_INSERT_AFTER(&e2, &e3, entry);
+
+ ASSERT_THAT(head, Contains("abc"));
+
+ Contrived *e, *tmp = NULL;
+ STAILQ_FOREACH_SAFE(e, &head, entry, tmp) {
+ if (e == &e2) {
+ STAILQ_REMOVE(&head, e, Contrived, entry);
+ }
+ }
+
+ ASSERT_THAT(head, Contains("ac"));
+
+ while (!STAILQ_EMPTY(&head)) {
+ e = STAILQ_FIRST(&head);
+ STAILQ_REMOVE_HEAD(&head, entry);
+ }
+
+ ASSERT_TRUE(STAILQ_EMPTY(&head));
+}
+
+} // namespace LIBC_NAMESPACE
>From fe8a1d1a868039a77c3a8cf45ed65e7be4229e66 Mon Sep 17 00:00:00 2001
From: Petr Hosek <phosek at google.com>
Date: Wed, 17 Jan 2024 07:52:21 +0000
Subject: [PATCH 2/6] Implement the remaining SLIST and STAILQ macros
This matches the BSD and newlib implementations.
---
libc/include/CMakeLists.txt | 1 +
libc/include/llvm-libc-macros/CMakeLists.txt | 6 +
.../include/llvm-libc-macros/offsetof-macro.h | 15 ++
libc/include/sys/queue.h | 152 ++++++++++++++----
libc/test/include/sys/queue_test.cpp | 111 +++++++++----
5 files changed, 225 insertions(+), 60 deletions(-)
create mode 100644 libc/include/llvm-libc-macros/offsetof-macro.h
diff --git a/libc/include/CMakeLists.txt b/libc/include/CMakeLists.txt
index cc846a25e85d65..4a2880b6ca70a6 100644
--- a/libc/include/CMakeLists.txt
+++ b/libc/include/CMakeLists.txt
@@ -351,6 +351,7 @@ add_header(
sys/queue.h
DEPENDS
.llvm-libc-macros.null_macro
+ .llvm-libc-macros.offsetof_macro
)
add_gen_header(
diff --git a/libc/include/llvm-libc-macros/CMakeLists.txt b/libc/include/llvm-libc-macros/CMakeLists.txt
index 9c9e6bfd125645..ab4c0d73950923 100644
--- a/libc/include/llvm-libc-macros/CMakeLists.txt
+++ b/libc/include/llvm-libc-macros/CMakeLists.txt
@@ -70,6 +70,12 @@ add_macro_header(
math-macros.h
)
+add_macro_header(
+ offsetof_macro
+ HDR
+ offsetof-macro.h
+)
+
add_macro_header(
sched_macros
HDR
diff --git a/libc/include/llvm-libc-macros/offsetof-macro.h b/libc/include/llvm-libc-macros/offsetof-macro.h
new file mode 100644
index 00000000000000..eeceb3db110b6b
--- /dev/null
+++ b/libc/include/llvm-libc-macros/offsetof-macro.h
@@ -0,0 +1,15 @@
+//===-- Definition of the offsetof macro ----------------------------------===//
+//
+// 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_MACROS_OFFSETOF_MACRO_H
+#define __LLVM_LIBC_MACROS_OFFSETOF_MACRO_H
+
+#define __need_offsetof
+#include <stddef.h>
+
+#endif // __LLVM_LIBC_MACROS_OFFSETOF_MACRO_H
diff --git a/libc/include/sys/queue.h b/libc/include/sys/queue.h
index 4eab6ef91f183c..7769f291b152c5 100644
--- a/libc/include/sys/queue.h
+++ b/libc/include/sys/queue.h
@@ -10,6 +10,13 @@
#define __LLVM_LIBC_MACROS_SYS_QUEUE_MACROS_H
#include <llvm-libc-macros/null-macro.h>
+#include <llvm-libc-macros/offsetof-macro.h>
+
+#ifdef __cplusplus
+#define QUEUE_TYPEOF(type) type
+#else
+#define QUEUE_TYPEOF(type) struct type
+#endif
// Singly-linked list definitions.
@@ -18,6 +25,11 @@
struct type *first; \
}
+#define SLIST_CLASS_HEAD(name, type) \
+ struct name { \
+ class type *first; \
+ }
+
#define SLIST_HEAD_INITIALIZER(head) \
{ NULL }
@@ -26,6 +38,11 @@
struct type *next; \
}
+#define SLIST_CLASS_ENTRY(type) \
+ struct { \
+ class type *next; \
+ }
+
// Singly-linked list access methods.
#define SLIST_EMPTY(head) ((head)->first == NULL)
@@ -35,21 +52,37 @@
#define SLIST_FOREACH(var, head, field) \
for ((var) = SLIST_FIRST(head); (var); (var) = SLIST_NEXT(var, field))
+#define SLIST_FOREACH_FROM(var, head, field) \
+ for ((var) = ((var) ? (var) : SLIST_FIRST(head)); (var); \
+ (var) = SLIST_NEXT(var, field))
+
#define SLIST_FOREACH_SAFE(var, head, field, tvar) \
for ((var) = SLIST_FIRST(head); \
(var) && ((tvar) = SLIST_NEXT(var, field), 1); (var) = (tvar))
+#define SLIST_FOREACH_FROM_SAFE(var, head, field, tvar) \
+ for ((var) = ((var) ? (var) : SLIST_FIRST(head)); \
+ (var) && ((tvar) = SLIST_NEXT(var, field), 1); (var) = (tvar))
+
// Singly-linked list functions.
-#define SLIST_INIT(head) \
+#define SLIST_CONCAT(head1, head2, type, field) \
do { \
- SLIST_FIRST(head) = NULL; \
+ if (SLIST_EMPTY(head1)) { \
+ if ((SLIST_FIRST(head1) = SLIST_FIRST(head2)) != NULL) \
+ SLIST_INIT(head2); \
+ } else if (!SLIST_EMPTY(head2)) { \
+ QUEUE_TYPEOF(type) *cur = SLIST_FIRST(head1); \
+ while (SLIST_NEXT(cur, field) != NULL) \
+ cur = SLIST_NEXT(cur, field); \
+ SLIST_NEXT(cur, field) = SLIST_FIRST(head2); \
+ SLIST_INIT(head2); \
+ } \
} while (0)
-#define SLIST_INSERT_HEAD(head, elem, field) \
+#define SLIST_INIT(head) \
do { \
- SLIST_NEXT(elem, field) = SLIST_FIRST(head); \
- SLIST_FIRST(head) = (elem); \
+ SLIST_FIRST(head) = NULL; \
} while (0)
#define SLIST_INSERT_AFTER(slistelem, elem, field) \
@@ -58,14 +91,10 @@
SLIST_NEXT(slistelem, field) = (elem); \
} while (0)
-#define SLIST_REMOVE_HEAD(head, field) \
- do { \
- SLIST_FIRST(head) = SLIST_NEXT(SLIST_FIRST(head), field); \
- } while (0)
-
-#define SLIST_REMOVE_AFTER(elem, field) \
+#define SLIST_INSERT_HEAD(head, elem, field) \
do { \
- SLIST_NEXT(elem, field) = SLIST_NEXT(SLIST_NEXT(elem, field), field); \
+ SLIST_NEXT(elem, field) = SLIST_FIRST(head); \
+ SLIST_FIRST(head) = (elem); \
} while (0)
#define SLIST_REMOVE(head, elem, type, field) \
@@ -73,13 +102,30 @@
if (SLIST_FIRST(head) == (elem)) { \
SLIST_REMOVE_HEAD(head, field); \
} else { \
- struct type *cur = SLIST_FIRST(head); \
+ QUEUE_TYPEOF(type) *cur = SLIST_FIRST(head); \
while (SLIST_NEXT(elem, field) != (elem)) \
cur = SLIST_NEXT(elem, field); \
SLIST_REMOVE_AFTER(cur, field); \
} \
} while (0)
+#define SLIST_REMOVE_AFTER(elem, field) \
+ do { \
+ SLIST_NEXT(elem, field) = SLIST_NEXT(SLIST_NEXT(elem, field), field); \
+ } while (0)
+
+#define SLIST_REMOVE_HEAD(head, field) \
+ do { \
+ SLIST_FIRST(head) = SLIST_NEXT(SLIST_FIRST(head), field); \
+ } while (0)
+
+#define SLIST_SWAP(head1, head2, type) \
+ do { \
+ QUEUE_TYPEOF(type) *first = SLIST_FIRST(head1); \
+ SLIST_FIRST(head1) = SLIST_FIRST(head2); \
+ SLIST_FIRST(head2) = first; \
+ } while (0)
+
// Singly-linked tail queue definitions.
#define STAILQ_HEAD(name, type) \
@@ -88,6 +134,12 @@
struct type **last; \
}
+#define STAILQ_CLASS_HEAD(name, type) \
+ struct name { \
+ class type *first; \
+ class type **last; \
+ }
+
#define STAILQ_HEAD_INITIALIZER(head) \
{ NULL, &(head).first }
@@ -96,27 +148,61 @@
struct type *next; \
}
+#define STAILQ_CLASS_ENTRY(type) \
+ struct { \
+ class type *next; \
+ }
+
// Singly-linked tail queue access methods.
#define STAILQ_EMPTY(head) ((head)->first == NULL)
#define STAILQ_FIRST(head) ((head)->first)
+#define STAILQ_LAST(head, type, field) \
+ STAILQ_EMPTY(head) \
+ ? NULL \
+ : (QUEUE_TYPEOF(type) *)((char *)(head)->last - \
+ offsetof(QUEUE_TYPEOF(type), field))
#define STAILQ_NEXT(elem, field) ((elem)->field.next)
#define STAILQ_FOREACH(var, head, field) \
for ((var) = STAILQ_FIRST(head); (var); (var) = STAILQ_NEXT(var, field))
+#define STAILQ_FOREACH_FROM(var, head, field) \
+ for ((var) = ((var) ? (var) : STAILQ_FIRST(head)); (var); \
+ (var) = STAILQ_NEXT(var, field))
+
#define STAILQ_FOREACH_SAFE(var, head, field, tvar) \
for ((var) = STAILQ_FIRST(head); \
(var) && ((tvar) = STAILQ_NEXT(var, field), 1); (var) = (tvar))
+#define STAILQ_FOREACH_SAFE(var, head, field, tvar) \
+ for ((var) = ((var) ? (var) : STAILQ_FIRST(head)); \
+ (var) && ((tvar) = STAILQ_NEXT(var, field), 1); (var) = (tvar))
+
// Singly-linked tail queue functions.
+#define STAILQ_CONCAT(head1, head2, type, field) \
+ do { \
+ if (!STAILQ_EMPTY(head2)) { \
+ *(head1)->last = (head2)->first; \
+ (head1)->last = (head2)->last; \
+ STAILQ_INIT(head2); \
+ } \
+ } while (0)
+
#define STAILQ_INIT(head) \
do { \
STAILQ_FIRST(head) = NULL; \
(head)->last = &STAILQ_FIRST(head); \
} while (0)
+#define STAILQ_INSERT_AFTER(head, listelem, elem, field) \
+ do { \
+ if ((STAILQ_NEXT(elem, field) = STAILQ_NEXT(listelem, field)) == NULL) \
+ (head)->last = &STAILQ_NEXT(elem, field); \
+ STAILQ_NEXT(listelem, field) = (elem); \
+ } while (0)
+
#define STAILQ_INSERT_HEAD(head, elem, field) \
do { \
if ((STAILQ_NEXT(elem, field) = STAILQ_FIRST(head)) == NULL) \
@@ -131,11 +217,23 @@
(head)->last = &STAILQ_NEXT(elem, field); \
} while (0)
-#define STAILQ_INSERT_AFTER(head, listelem, elem, field) \
+#define STAILQ_REMOVE(head, elem, type, field) \
do { \
- if ((STAILQ_NEXT(elem, field) = STAILQ_NEXT(listelem, field)) == NULL) \
+ if (STAILQ_FIRST(head) == (elem)) { \
+ STAILQ_REMOVE_HEAD(head, field); \
+ } else { \
+ QUEUE_TYPEOF(type) *cur = STAILQ_FIRST(head); \
+ while (STAILQ_NEXT(elem, field) != (elem)) \
+ cur = STAILQ_NEXT(cur, field); \
+ STAILQ_REMOVE_AFTER(head, cur, field); \
+ } \
+ } while (0)
+
+#define STAILQ_REMOVE_AFTER(head, elem, field) \
+ do { \
+ if ((STAILQ_NEXT(elem, field) = \
+ STAILQ_NEXT(STAILQ_NEXT(elem, field), field)) == NULL) \
(head)->last = &STAILQ_NEXT(elem, field); \
- STAILQ_NEXT(listelem, next) = (elem); \
} while (0)
#define STAILQ_REMOVE_HEAD(head, field) \
@@ -144,18 +242,18 @@
(head)->last = &STAILQ_FIRST(head); \
} while (0)
-#define STAILQ_REMOVE(head, elem, type, field) \
+#define STAILQ_SWAP(head1, head2, type) \
do { \
- if (STAILQ_FIRST(head) == (elem)) { \
- STAILQ_REMOVE_HEAD(head, field); \
- } else { \
- struct type *cur = STAILQ_FIRST(head); \
- while (STAILQ_NEXT(elem, field) != (elem)) \
- cur = STAILQ_NEXT(cur, field); \
- if ((STAILQ_NEXT(cur, field) = \
- STAILQ_NEXT(STAILQ_NEXT(cur, field), field)) == NULL) \
- (head)->last = &STAILQ_NEXT(cur, field); \
- } \
+ QUEUE_TYPEOF(type) *first = STAILQ_FIRST(head1); \
+ QUEUE_TYPEOF(type) **last = (head1)->last; \
+ STAILQ_FIRST(head1) = STAILQ_FIRST(head2); \
+ (head1)->last = (head2)->last; \
+ STAILQ_FIRST(head2) = first; \
+ (head2)->last = last; \
+ if (STAILQ_EMPTY(head1)) \
+ (head1)->last = &STAILQ_FIRST(head1); \
+ if (STAILQ_EMPTY(head2)) \
+ (head2)->last = &STAILQ_FIRST(head2); \
} while (0)
#endif // __LLVM_LIBC_MACROS_SYS_QUEUE_MACROS_H
diff --git a/libc/test/include/sys/queue_test.cpp b/libc/test/include/sys/queue_test.cpp
index 4d0daf6190f12d..bcb9fcaf287373 100644
--- a/libc/test/include/sys/queue_test.cpp
+++ b/libc/test/include/sys/queue_test.cpp
@@ -18,69 +18,89 @@ using LIBC_NAMESPACE::cpp::string;
namespace LIBC_NAMESPACE {
TEST(LlvmLibcQueueTest, SList) {
- struct Contrived {
+ struct Entry {
char c;
- SLIST_ENTRY(Contrived) entry;
+ SLIST_ENTRY(Entry) entries;
};
- SLIST_HEAD(Head, Contrived) head = SLIST_HEAD_INITIALIZER(head);
+ SLIST_HEAD(Head, Entry);
+
+ Head head = SLIST_HEAD_INITIALIZER(head);
struct Contains : public testing::Matcher<Head> {
string s;
Contains(string s) : s(s) {}
bool match(Head head) {
- Contrived *e;
+ Entry *e;
CharVector v;
- SLIST_FOREACH(e, &head, entry) { v.append(e->c); }
+ SLIST_FOREACH(e, &head, entries) { v.append(e->c); }
return s == v.c_str();
}
};
- SLIST_INIT(&head);
- ASSERT_TRUE(SLIST_EMPTY(&head));
-
- Contrived e1 = {'a', {NULL}};
- SLIST_INSERT_HEAD(&head, &e1, entry);
+ Entry e1 = {'a', {NULL}};
+ SLIST_INSERT_HEAD(&head, &e1, entries);
ASSERT_THAT(head, Contains("a"));
- Contrived e2 = {'b', {NULL}};
- SLIST_INSERT_AFTER(&e1, &e2, entry);
+ Entry e2 = {'b', {NULL}};
+ SLIST_INSERT_AFTER(&e1, &e2, entries);
ASSERT_THAT(head, Contains("ab"));
- Contrived *e, *tmp = NULL;
- SLIST_FOREACH_SAFE(e, &head, entry, tmp) {
+ Head head2 = SLIST_HEAD_INITIALIZER(head);
+
+ Entry e3 = {'c', {NULL}};
+ SLIST_INSERT_HEAD(&head2, &e3, entries);
+
+ ASSERT_THAT(head2, Contains("c"));
+
+ SLIST_SWAP(&head, &head2, Entry);
+
+ ASSERT_THAT(head2, Contains("ab"));
+
+ SLIST_CONCAT(&head2, &head, Entry, entries);
+
+ ASSERT_THAT(head2, Contains("abc"));
+
+ SLIST_CONCAT(&head, &head2, Entry, entries);
+
+ ASSERT_THAT(head, Contains("abc"));
+
+ Entry *e = NULL, *tmp = NULL;
+ SLIST_FOREACH_SAFE(e, &head, entries, tmp) {
if (e == &e2) {
- SLIST_REMOVE(&head, e, Contrived, entry);
+ SLIST_REMOVE(&head, e, Entry, entries);
}
}
- ASSERT_THAT(head, Contains("a"));
+ ASSERT_THAT(head, Contains("ac"));
while (!SLIST_EMPTY(&head)) {
e = SLIST_FIRST(&head);
- SLIST_REMOVE_HEAD(&head, entry);
+ SLIST_REMOVE_HEAD(&head, entries);
}
ASSERT_TRUE(SLIST_EMPTY(&head));
}
TEST(LlvmLibcQueueTest, STailQ) {
- struct Contrived {
+ struct Entry {
char c;
- STAILQ_ENTRY(Contrived) entry;
+ STAILQ_ENTRY(Entry) entries;
};
- STAILQ_HEAD(Head, Contrived) head = STAILQ_HEAD_INITIALIZER(head);
+ STAILQ_HEAD(Head, Entry);
+
+ Head head = STAILQ_HEAD_INITIALIZER(head);
struct Contains : public testing::Matcher<Head> {
string s;
Contains(string s) : s(s) {}
bool match(Head head) {
- Contrived *e;
+ Entry *e;
CharVector v;
- STAILQ_FOREACH(e, &head, entry) { v.append(e->c); }
+ STAILQ_FOREACH(e, &head, entries) { v.append(e->c); }
return s == v.c_str();
}
};
@@ -88,33 +108,58 @@ TEST(LlvmLibcQueueTest, STailQ) {
STAILQ_INIT(&head);
ASSERT_TRUE(STAILQ_EMPTY(&head));
- Contrived e1 = {'a', {NULL}};
- STAILQ_INSERT_HEAD(&head, &e1, entry);
+ Entry e1 = {'a', {NULL}};
+ STAILQ_INSERT_HEAD(&head, &e1, entries);
ASSERT_THAT(head, Contains("a"));
- Contrived e2 = {'b', {NULL}};
- STAILQ_INSERT_TAIL(&head, &e2, entry);
+ Entry e2 = {'b', {NULL}};
+ STAILQ_INSERT_TAIL(&head, &e2, entries);
ASSERT_THAT(head, Contains("ab"));
- Contrived e3 = {'c', {NULL}};
- SLIST_INSERT_AFTER(&e2, &e3, entry);
+ Entry e3 = {'c', {NULL}};
+ STAILQ_INSERT_AFTER(&head, &e2, &e3, entries);
ASSERT_THAT(head, Contains("abc"));
- Contrived *e, *tmp = NULL;
- STAILQ_FOREACH_SAFE(e, &head, entry, tmp) {
+ Head head2 = STAILQ_HEAD_INITIALIZER(head);
+
+ Entry e4 = {'d', {NULL}};
+ STAILQ_INSERT_HEAD(&head2, &e4, entries);
+
+ ASSERT_THAT(head2, Contains("d"));
+
+ STAILQ_SWAP(&head, &head2, Entry);
+
+ ASSERT_THAT(head2, Contains("abc"));
+
+ STAILQ_CONCAT(&head2, &head, Entry, entries);
+
+ ASSERT_EQ(STAILQ_FIRST(&head2), &e1);
+ ASSERT_EQ(STAILQ_LAST(&head2, Entry, entries), &e4);
+
+ ASSERT_THAT(head2, Contains("abcd"));
+
+ STAILQ_CONCAT(&head, &head2, Entry, entries);
+
+ ASSERT_EQ(STAILQ_FIRST(&head), &e1);
+ ASSERT_EQ(STAILQ_LAST(&head, Entry, entries), &e4);
+
+ ASSERT_THAT(head, Contains("abcd"));
+
+ Entry *e = NULL, *tmp = NULL;
+ STAILQ_FOREACH_SAFE(e, &head, entries, tmp) {
if (e == &e2) {
- STAILQ_REMOVE(&head, e, Contrived, entry);
+ STAILQ_REMOVE(&head, e, Entry, entries);
}
}
- ASSERT_THAT(head, Contains("ac"));
+ ASSERT_THAT(head, Contains("acd"));
while (!STAILQ_EMPTY(&head)) {
e = STAILQ_FIRST(&head);
- STAILQ_REMOVE_HEAD(&head, entry);
+ STAILQ_REMOVE_HEAD(&head, entries);
}
ASSERT_TRUE(STAILQ_EMPTY(&head));
>From 9a13c0a46017169ddf4fe31e73f1681d06037c6f Mon Sep 17 00:00:00 2001
From: Petr Hosek <phosek at google.com>
Date: Thu, 18 Jan 2024 06:32:20 +0000
Subject: [PATCH 3/6] Address review feedback
---
libc/config/linux/riscv/headers.txt | 1 +
libc/config/linux/x86_64/headers.txt | 1 +
libc/include/CMakeLists.txt | 2 +-
libc/include/llvm-libc-macros/CMakeLists.txt | 19 +-
.../llvm-libc-macros/containerof-macro.h | 20 ++
.../llvm-libc-macros/sys-queue-macros.h | 260 ++++++++++++++++++
libc/include/sys/queue.h | 255 +----------------
libc/test/include/CMakeLists.txt | 4 +-
libc/test/include/sys/queue_test.cpp | 3 +-
9 files changed, 311 insertions(+), 254 deletions(-)
create mode 100644 libc/include/llvm-libc-macros/containerof-macro.h
create mode 100644 libc/include/llvm-libc-macros/sys-queue-macros.h
diff --git a/libc/config/linux/riscv/headers.txt b/libc/config/linux/riscv/headers.txt
index 3e2b1630f1695e..9c70a3bde74f05 100644
--- a/libc/config/linux/riscv/headers.txt
+++ b/libc/config/linux/riscv/headers.txt
@@ -31,6 +31,7 @@ set(TARGET_PUBLIC_HEADERS
libc.include.sys_mman
libc.include.sys_prctl
libc.include.sys_random
+ libc.include.sys_queue
libc.include.sys_resource
libc.include.sys_select
libc.include.sys_socket
diff --git a/libc/config/linux/x86_64/headers.txt b/libc/config/linux/x86_64/headers.txt
index 3e2b1630f1695e..a85f87b2a3ee98 100644
--- a/libc/config/linux/x86_64/headers.txt
+++ b/libc/config/linux/x86_64/headers.txt
@@ -30,6 +30,7 @@ set(TARGET_PUBLIC_HEADERS
libc.include.sys_ioctl
libc.include.sys_mman
libc.include.sys_prctl
+ libc.include.sys_queue
libc.include.sys_random
libc.include.sys_resource
libc.include.sys_select
diff --git a/libc/include/CMakeLists.txt b/libc/include/CMakeLists.txt
index 4a2880b6ca70a6..2ff9c65ddf0802 100644
--- a/libc/include/CMakeLists.txt
+++ b/libc/include/CMakeLists.txt
@@ -351,7 +351,7 @@ add_header(
sys/queue.h
DEPENDS
.llvm-libc-macros.null_macro
- .llvm-libc-macros.offsetof_macro
+ .llvm-libc-macros.containerof_macro
)
add_gen_header(
diff --git a/libc/include/llvm-libc-macros/CMakeLists.txt b/libc/include/llvm-libc-macros/CMakeLists.txt
index ab4c0d73950923..15f8b37acaf164 100644
--- a/libc/include/llvm-libc-macros/CMakeLists.txt
+++ b/libc/include/llvm-libc-macros/CMakeLists.txt
@@ -4,7 +4,7 @@ function(add_macro_header name)
"MACRO_HEADER"
"" # Optional arguments
"HDR" # Single value arguments
- "" # Multi-value arguments
+ "DEPENDS" # Multi-value arguments
${ARGN}
)
if(TARGET libc.include.llvm-libc-macros.${LIBC_TARGET_OS}.${name})
@@ -14,12 +14,15 @@ function(add_macro_header name)
${MACRO_HEADER_HDR}
DEPENDS
.${LIBC_TARGET_OS}.${name}
+ ${MACRO_HEADER_DEPENDS}
)
else()
add_header(
${name}
HDR
${MACRO_HEADER_HDR}
+ DEPENDS
+ ${MACRO_HEADER_DEPENDS}
)
endif()
endfunction(add_macro_header)
@@ -76,6 +79,14 @@ add_macro_header(
offsetof-macro.h
)
+add_macro_header(
+ containerof_macro
+ HDR
+ containerof-macro.h
+ DEPENDS
+ .offsetof_macro
+)
+
add_macro_header(
sched_macros
HDR
@@ -124,6 +135,12 @@ add_macro_header(
sys-mman-macros.h
)
+add_macro_header(
+ sys_queue_macros
+ HDR
+ sys-queue-macros.h
+)
+
add_macro_header(
sys_random_macros
HDR
diff --git a/libc/include/llvm-libc-macros/containerof-macro.h b/libc/include/llvm-libc-macros/containerof-macro.h
new file mode 100644
index 00000000000000..14c0217fc1d45e
--- /dev/null
+++ b/libc/include/llvm-libc-macros/containerof-macro.h
@@ -0,0 +1,20 @@
+//===-- Definition of the containerof macro -------------------------------===//
+//
+// 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_MACROS_CONTAINEROF_MACRO_H
+#define __LLVM_LIBC_MACROS_CONTAINEROF_MACRO_H
+
+#include <llvm-libc-macros/offsetof-macro.h>
+
+#define __containerof(ptr, type, member) \
+ ({ \
+ const __typeof(((type *)0)->member) *__ptr = ptr; \
+ (type *)(void *)((const char *)__ptr - offsetof(type, member)); \
+ })
+
+#endif // __LLVM_LIBC_MACROS_CONTAINEROF_MACRO_H
diff --git a/libc/include/llvm-libc-macros/sys-queue-macros.h b/libc/include/llvm-libc-macros/sys-queue-macros.h
new file mode 100644
index 00000000000000..b34283573dc26f
--- /dev/null
+++ b/libc/include/llvm-libc-macros/sys-queue-macros.h
@@ -0,0 +1,260 @@
+//===-- Macros defined in sys/queue.h header file -------------------------===//
+//
+// 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_MACROS_SYS_QUEUE_MACROS_H
+#define __LLVM_LIBC_MACROS_SYS_QUEUE_MACROS_H
+
+#include <llvm-libc-macros/containerof-macro.h>
+#include <llvm-libc-macros/null-macro.h>
+
+#ifdef __cplusplus
+#define QUEUE_TYPEOF(type) type
+#else
+#define QUEUE_TYPEOF(type) struct type
+#endif
+
+// Singly-linked list definitions.
+
+#define SLIST_HEAD(name, type) \
+ struct name { \
+ struct type *first; \
+ }
+
+#define SLIST_CLASS_HEAD(name, type) \
+ struct name { \
+ class type *first; \
+ }
+
+#define SLIST_HEAD_INITIALIZER(head) \
+ { NULL }
+
+#define SLIST_ENTRY(type) \
+ struct { \
+ struct type *next; \
+ }
+
+#define SLIST_CLASS_ENTRY(type) \
+ struct { \
+ class type *next; \
+ }
+
+// Singly-linked list access methods.
+
+#define SLIST_EMPTY(head) ((head)->first == NULL)
+#define SLIST_FIRST(head) ((head)->first)
+#define SLIST_NEXT(elem, field) ((elem)->field.next)
+
+#define SLIST_FOREACH(var, head, field) \
+ for ((var) = SLIST_FIRST(head); (var); (var) = SLIST_NEXT(var, field))
+
+#define SLIST_FOREACH_FROM(var, head, field) \
+ if (!(var)) \
+ (var) = SLIST_FIRST(head); \
+ for (; (var); (var) = SLIST_NEXT(var, field))
+
+#define SLIST_FOREACH_SAFE(var, head, field, tvar) \
+ for ((var) = SLIST_FIRST(head); \
+ (var) && ((tvar) = SLIST_NEXT(var, field), 1); (var) = (tvar))
+
+#define SLIST_FOREACH_FROM_SAFE(var, head, field, tvar) \
+ if (!(var)) \
+ (var) = SLIST_FIRST(head); \
+ for (; (var) && ((tvar) = SLIST_NEXT(var, field), 1); (var) = (tvar))
+
+// Singly-linked list functions.
+
+#define SLIST_CONCAT(head1, head2, type, field) \
+ do { \
+ if (SLIST_EMPTY(head1)) { \
+ if ((SLIST_FIRST(head1) = SLIST_FIRST(head2)) != NULL) \
+ SLIST_INIT(head2); \
+ } else if (!SLIST_EMPTY(head2)) { \
+ QUEUE_TYPEOF(type) *cur = SLIST_FIRST(head1); \
+ while (SLIST_NEXT(cur, field) != NULL) \
+ cur = SLIST_NEXT(cur, field); \
+ SLIST_NEXT(cur, field) = SLIST_FIRST(head2); \
+ SLIST_INIT(head2); \
+ } \
+ } while (0)
+
+#define SLIST_INIT(head) \
+ do { \
+ SLIST_FIRST(head) = NULL; \
+ } while (0)
+
+#define SLIST_INSERT_AFTER(slistelem, elem, field) \
+ do { \
+ SLIST_NEXT(elem, field) = SLIST_NEXT(slistelem, field); \
+ SLIST_NEXT(slistelem, field) = (elem); \
+ } while (0)
+
+#define SLIST_INSERT_HEAD(head, elem, field) \
+ do { \
+ SLIST_NEXT(elem, field) = SLIST_FIRST(head); \
+ SLIST_FIRST(head) = (elem); \
+ } while (0)
+
+#define SLIST_REMOVE(head, elem, type, field) \
+ do { \
+ if (SLIST_FIRST(head) == (elem)) { \
+ SLIST_REMOVE_HEAD(head, field); \
+ } else { \
+ QUEUE_TYPEOF(type) *cur = SLIST_FIRST(head); \
+ while (SLIST_NEXT(elem, field) != (elem)) \
+ cur = SLIST_NEXT(elem, field); \
+ SLIST_REMOVE_AFTER(cur, field); \
+ } \
+ } while (0)
+
+#define SLIST_REMOVE_AFTER(elem, field) \
+ do { \
+ SLIST_NEXT(elem, field) = SLIST_NEXT(SLIST_NEXT(elem, field), field); \
+ } while (0)
+
+#define SLIST_REMOVE_HEAD(head, field) \
+ do { \
+ SLIST_FIRST(head) = SLIST_NEXT(SLIST_FIRST(head), field); \
+ } while (0)
+
+#define SLIST_SWAP(head1, head2, type) \
+ do { \
+ QUEUE_TYPEOF(type) *first = SLIST_FIRST(head1); \
+ SLIST_FIRST(head1) = SLIST_FIRST(head2); \
+ SLIST_FIRST(head2) = first; \
+ } while (0)
+
+// Singly-linked tail queue definitions.
+
+#define STAILQ_HEAD(name, type) \
+ struct name { \
+ struct type *first; \
+ struct type **last; \
+ }
+
+#define STAILQ_CLASS_HEAD(name, type) \
+ struct name { \
+ class type *first; \
+ class type **last; \
+ }
+
+#define STAILQ_HEAD_INITIALIZER(head) \
+ { NULL, &(head).first }
+
+#define STAILQ_ENTRY(type) \
+ struct { \
+ struct type *next; \
+ }
+
+#define STAILQ_CLASS_ENTRY(type) \
+ struct { \
+ class type *next; \
+ }
+
+// Singly-linked tail queue access methods.
+
+#define STAILQ_EMPTY(head) ((head)->first == NULL)
+#define STAILQ_FIRST(head) ((head)->first)
+#define STAILQ_LAST(head, type, field) \
+ (STAILQ_EMPTY(head) ? NULL : __containerof((head)->last, type, field.next))
+#define STAILQ_NEXT(elem, field) ((elem)->field.next)
+
+#define STAILQ_FOREACH(var, head, field) \
+ for ((var) = STAILQ_FIRST(head); (var); (var) = STAILQ_NEXT(var, field))
+
+#define STAILQ_FOREACH_FROM(var, head, field) \
+ if (!(var)) \
+ (var) = STAILQ_FIRST(head); \
+ for (; (var); (var) = STAILQ_NEXT(var, field))
+
+#define STAILQ_FOREACH_SAFE(var, head, field, tvar) \
+ for ((var) = STAILQ_FIRST(head); \
+ (var) && ((tvar) = STAILQ_NEXT(var, field), 1); (var) = (tvar))
+
+#define STAILQ_FOREACH_FROM_SAFE(var, head, field, tvar) \
+ if (!(var)) \
+ (var) = STAILQ_FIRST(head); \
+ for (; (var) && ((tvar) = STAILQ_NEXT(var, field), 1); (var) = (tvar))
+
+// Singly-linked tail queue functions.
+
+#define STAILQ_CONCAT(head1, head2, type, field) \
+ do { \
+ if (!STAILQ_EMPTY(head2)) { \
+ *(head1)->last = (head2)->first; \
+ (head1)->last = (head2)->last; \
+ STAILQ_INIT(head2); \
+ } \
+ } while (0)
+
+#define STAILQ_INIT(head) \
+ do { \
+ STAILQ_FIRST(head) = NULL; \
+ (head)->last = &STAILQ_FIRST(head); \
+ } while (0)
+
+#define STAILQ_INSERT_AFTER(head, listelem, elem, field) \
+ do { \
+ if ((STAILQ_NEXT(elem, field) = STAILQ_NEXT(listelem, field)) == NULL) \
+ (head)->last = &STAILQ_NEXT(elem, field); \
+ STAILQ_NEXT(listelem, field) = (elem); \
+ } while (0)
+
+#define STAILQ_INSERT_HEAD(head, elem, field) \
+ do { \
+ if ((STAILQ_NEXT(elem, field) = STAILQ_FIRST(head)) == NULL) \
+ (head)->last = &STAILQ_NEXT(elem, field); \
+ STAILQ_FIRST(head) = (elem); \
+ } while (0)
+
+#define STAILQ_INSERT_TAIL(head, elem, field) \
+ do { \
+ STAILQ_NEXT(elem, field) = NULL; \
+ *(head)->last = (elem); \
+ (head)->last = &STAILQ_NEXT(elem, field); \
+ } while (0)
+
+#define STAILQ_REMOVE(head, elem, type, field) \
+ do { \
+ if (STAILQ_FIRST(head) == (elem)) { \
+ STAILQ_REMOVE_HEAD(head, field); \
+ } else { \
+ QUEUE_TYPEOF(type) *cur = STAILQ_FIRST(head); \
+ while (STAILQ_NEXT(cur, field) != (elem)) \
+ cur = STAILQ_NEXT(cur, field); \
+ STAILQ_REMOVE_AFTER(head, cur, field); \
+ } \
+ } while (0)
+
+#define STAILQ_REMOVE_AFTER(head, elem, field) \
+ do { \
+ if ((STAILQ_NEXT(elem, field) = \
+ STAILQ_NEXT(STAILQ_NEXT(elem, field), field)) == NULL) \
+ (head)->last = &STAILQ_NEXT(elem, field); \
+ } while (0)
+
+#define STAILQ_REMOVE_HEAD(head, field) \
+ do { \
+ if ((STAILQ_FIRST(head) = STAILQ_NEXT(STAILQ_FIRST(head), field)) == NULL) \
+ (head)->last = &STAILQ_FIRST(head); \
+ } while (0)
+
+#define STAILQ_SWAP(head1, head2, type) \
+ do { \
+ QUEUE_TYPEOF(type) *first = STAILQ_FIRST(head1); \
+ QUEUE_TYPEOF(type) **last = (head1)->last; \
+ STAILQ_FIRST(head1) = STAILQ_FIRST(head2); \
+ (head1)->last = (head2)->last; \
+ STAILQ_FIRST(head2) = first; \
+ (head2)->last = last; \
+ if (STAILQ_EMPTY(head1)) \
+ (head1)->last = &STAILQ_FIRST(head1); \
+ if (STAILQ_EMPTY(head2)) \
+ (head2)->last = &STAILQ_FIRST(head2); \
+ } while (0)
+
+#endif // __LLVM_LIBC_MACROS_SYS_QUEUE_MACROS_H
diff --git a/libc/include/sys/queue.h b/libc/include/sys/queue.h
index 7769f291b152c5..3804a563da34d5 100644
--- a/libc/include/sys/queue.h
+++ b/libc/include/sys/queue.h
@@ -1,4 +1,4 @@
-//===-- Macros defined in sys/queue.h header file -------------------------===//
+//===-- BSD sys/queue.h ---------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
@@ -6,254 +6,11 @@
//
//===----------------------------------------------------------------------===//
-#ifndef __LLVM_LIBC_MACROS_SYS_QUEUE_MACROS_H
-#define __LLVM_LIBC_MACROS_SYS_QUEUE_MACROS_H
+#ifndef LLVM_LIBC_SYS_QUEUE_H
+#define LLVM_LIBC_SYS_QUEUE_H
-#include <llvm-libc-macros/null-macro.h>
-#include <llvm-libc-macros/offsetof-macro.h>
+#include <__llvm-libc-common.h>
-#ifdef __cplusplus
-#define QUEUE_TYPEOF(type) type
-#else
-#define QUEUE_TYPEOF(type) struct type
-#endif
+#include <llvm-libc-macros/sys-queue-macros.h>
-// Singly-linked list definitions.
-
-#define SLIST_HEAD(name, type) \
- struct name { \
- struct type *first; \
- }
-
-#define SLIST_CLASS_HEAD(name, type) \
- struct name { \
- class type *first; \
- }
-
-#define SLIST_HEAD_INITIALIZER(head) \
- { NULL }
-
-#define SLIST_ENTRY(type) \
- struct { \
- struct type *next; \
- }
-
-#define SLIST_CLASS_ENTRY(type) \
- struct { \
- class type *next; \
- }
-
-// Singly-linked list access methods.
-
-#define SLIST_EMPTY(head) ((head)->first == NULL)
-#define SLIST_FIRST(head) ((head)->first)
-#define SLIST_NEXT(elem, field) ((elem)->field.next)
-
-#define SLIST_FOREACH(var, head, field) \
- for ((var) = SLIST_FIRST(head); (var); (var) = SLIST_NEXT(var, field))
-
-#define SLIST_FOREACH_FROM(var, head, field) \
- for ((var) = ((var) ? (var) : SLIST_FIRST(head)); (var); \
- (var) = SLIST_NEXT(var, field))
-
-#define SLIST_FOREACH_SAFE(var, head, field, tvar) \
- for ((var) = SLIST_FIRST(head); \
- (var) && ((tvar) = SLIST_NEXT(var, field), 1); (var) = (tvar))
-
-#define SLIST_FOREACH_FROM_SAFE(var, head, field, tvar) \
- for ((var) = ((var) ? (var) : SLIST_FIRST(head)); \
- (var) && ((tvar) = SLIST_NEXT(var, field), 1); (var) = (tvar))
-
-// Singly-linked list functions.
-
-#define SLIST_CONCAT(head1, head2, type, field) \
- do { \
- if (SLIST_EMPTY(head1)) { \
- if ((SLIST_FIRST(head1) = SLIST_FIRST(head2)) != NULL) \
- SLIST_INIT(head2); \
- } else if (!SLIST_EMPTY(head2)) { \
- QUEUE_TYPEOF(type) *cur = SLIST_FIRST(head1); \
- while (SLIST_NEXT(cur, field) != NULL) \
- cur = SLIST_NEXT(cur, field); \
- SLIST_NEXT(cur, field) = SLIST_FIRST(head2); \
- SLIST_INIT(head2); \
- } \
- } while (0)
-
-#define SLIST_INIT(head) \
- do { \
- SLIST_FIRST(head) = NULL; \
- } while (0)
-
-#define SLIST_INSERT_AFTER(slistelem, elem, field) \
- do { \
- SLIST_NEXT(elem, field) = SLIST_NEXT(slistelem, field); \
- SLIST_NEXT(slistelem, field) = (elem); \
- } while (0)
-
-#define SLIST_INSERT_HEAD(head, elem, field) \
- do { \
- SLIST_NEXT(elem, field) = SLIST_FIRST(head); \
- SLIST_FIRST(head) = (elem); \
- } while (0)
-
-#define SLIST_REMOVE(head, elem, type, field) \
- do { \
- if (SLIST_FIRST(head) == (elem)) { \
- SLIST_REMOVE_HEAD(head, field); \
- } else { \
- QUEUE_TYPEOF(type) *cur = SLIST_FIRST(head); \
- while (SLIST_NEXT(elem, field) != (elem)) \
- cur = SLIST_NEXT(elem, field); \
- SLIST_REMOVE_AFTER(cur, field); \
- } \
- } while (0)
-
-#define SLIST_REMOVE_AFTER(elem, field) \
- do { \
- SLIST_NEXT(elem, field) = SLIST_NEXT(SLIST_NEXT(elem, field), field); \
- } while (0)
-
-#define SLIST_REMOVE_HEAD(head, field) \
- do { \
- SLIST_FIRST(head) = SLIST_NEXT(SLIST_FIRST(head), field); \
- } while (0)
-
-#define SLIST_SWAP(head1, head2, type) \
- do { \
- QUEUE_TYPEOF(type) *first = SLIST_FIRST(head1); \
- SLIST_FIRST(head1) = SLIST_FIRST(head2); \
- SLIST_FIRST(head2) = first; \
- } while (0)
-
-// Singly-linked tail queue definitions.
-
-#define STAILQ_HEAD(name, type) \
- struct name { \
- struct type *first; \
- struct type **last; \
- }
-
-#define STAILQ_CLASS_HEAD(name, type) \
- struct name { \
- class type *first; \
- class type **last; \
- }
-
-#define STAILQ_HEAD_INITIALIZER(head) \
- { NULL, &(head).first }
-
-#define STAILQ_ENTRY(type) \
- struct { \
- struct type *next; \
- }
-
-#define STAILQ_CLASS_ENTRY(type) \
- struct { \
- class type *next; \
- }
-
-// Singly-linked tail queue access methods.
-
-#define STAILQ_EMPTY(head) ((head)->first == NULL)
-#define STAILQ_FIRST(head) ((head)->first)
-#define STAILQ_LAST(head, type, field) \
- STAILQ_EMPTY(head) \
- ? NULL \
- : (QUEUE_TYPEOF(type) *)((char *)(head)->last - \
- offsetof(QUEUE_TYPEOF(type), field))
-#define STAILQ_NEXT(elem, field) ((elem)->field.next)
-
-#define STAILQ_FOREACH(var, head, field) \
- for ((var) = STAILQ_FIRST(head); (var); (var) = STAILQ_NEXT(var, field))
-
-#define STAILQ_FOREACH_FROM(var, head, field) \
- for ((var) = ((var) ? (var) : STAILQ_FIRST(head)); (var); \
- (var) = STAILQ_NEXT(var, field))
-
-#define STAILQ_FOREACH_SAFE(var, head, field, tvar) \
- for ((var) = STAILQ_FIRST(head); \
- (var) && ((tvar) = STAILQ_NEXT(var, field), 1); (var) = (tvar))
-
-#define STAILQ_FOREACH_SAFE(var, head, field, tvar) \
- for ((var) = ((var) ? (var) : STAILQ_FIRST(head)); \
- (var) && ((tvar) = STAILQ_NEXT(var, field), 1); (var) = (tvar))
-
-// Singly-linked tail queue functions.
-
-#define STAILQ_CONCAT(head1, head2, type, field) \
- do { \
- if (!STAILQ_EMPTY(head2)) { \
- *(head1)->last = (head2)->first; \
- (head1)->last = (head2)->last; \
- STAILQ_INIT(head2); \
- } \
- } while (0)
-
-#define STAILQ_INIT(head) \
- do { \
- STAILQ_FIRST(head) = NULL; \
- (head)->last = &STAILQ_FIRST(head); \
- } while (0)
-
-#define STAILQ_INSERT_AFTER(head, listelem, elem, field) \
- do { \
- if ((STAILQ_NEXT(elem, field) = STAILQ_NEXT(listelem, field)) == NULL) \
- (head)->last = &STAILQ_NEXT(elem, field); \
- STAILQ_NEXT(listelem, field) = (elem); \
- } while (0)
-
-#define STAILQ_INSERT_HEAD(head, elem, field) \
- do { \
- if ((STAILQ_NEXT(elem, field) = STAILQ_FIRST(head)) == NULL) \
- (head)->last = &STAILQ_NEXT(elem, field); \
- STAILQ_FIRST(head) = (elem); \
- } while (0)
-
-#define STAILQ_INSERT_TAIL(head, elem, field) \
- do { \
- STAILQ_NEXT(elem, field) = NULL; \
- *(head)->last = (elem); \
- (head)->last = &STAILQ_NEXT(elem, field); \
- } while (0)
-
-#define STAILQ_REMOVE(head, elem, type, field) \
- do { \
- if (STAILQ_FIRST(head) == (elem)) { \
- STAILQ_REMOVE_HEAD(head, field); \
- } else { \
- QUEUE_TYPEOF(type) *cur = STAILQ_FIRST(head); \
- while (STAILQ_NEXT(elem, field) != (elem)) \
- cur = STAILQ_NEXT(cur, field); \
- STAILQ_REMOVE_AFTER(head, cur, field); \
- } \
- } while (0)
-
-#define STAILQ_REMOVE_AFTER(head, elem, field) \
- do { \
- if ((STAILQ_NEXT(elem, field) = \
- STAILQ_NEXT(STAILQ_NEXT(elem, field), field)) == NULL) \
- (head)->last = &STAILQ_NEXT(elem, field); \
- } while (0)
-
-#define STAILQ_REMOVE_HEAD(head, field) \
- do { \
- if ((STAILQ_FIRST(head) = STAILQ_NEXT(STAILQ_FIRST(head), field)) == NULL) \
- (head)->last = &STAILQ_FIRST(head); \
- } while (0)
-
-#define STAILQ_SWAP(head1, head2, type) \
- do { \
- QUEUE_TYPEOF(type) *first = STAILQ_FIRST(head1); \
- QUEUE_TYPEOF(type) **last = (head1)->last; \
- STAILQ_FIRST(head1) = STAILQ_FIRST(head2); \
- (head1)->last = (head2)->last; \
- STAILQ_FIRST(head2) = first; \
- (head2)->last = last; \
- if (STAILQ_EMPTY(head1)) \
- (head1)->last = &STAILQ_FIRST(head1); \
- if (STAILQ_EMPTY(head2)) \
- (head2)->last = &STAILQ_FIRST(head2); \
- } while (0)
-
-#endif // __LLVM_LIBC_MACROS_SYS_QUEUE_MACROS_H
+#endif // LLVM_LIBC_SYS_QUEUE_H
diff --git a/libc/test/include/CMakeLists.txt b/libc/test/include/CMakeLists.txt
index ea1942befa5952..2c6ab017c47ade 100644
--- a/libc/test/include/CMakeLists.txt
+++ b/libc/test/include/CMakeLists.txt
@@ -7,7 +7,9 @@ add_libc_test(
SRCS
sys/queue_test.cpp
DEPENDS
- libc.include.sys_queue
+ libc.include.sys.sys_queue_macros
libc.src.__support.char_vector
libc.src.__support.CPP.string
+ COMPILE_OPTIONS
+ -Wno-gnu-statement-expression-from-macro-expansion
)
diff --git a/libc/test/include/sys/queue_test.cpp b/libc/test/include/sys/queue_test.cpp
index bcb9fcaf287373..f3bf3a5c7055c4 100644
--- a/libc/test/include/sys/queue_test.cpp
+++ b/libc/test/include/sys/queue_test.cpp
@@ -6,12 +6,11 @@
//
//===----------------------------------------------------------------------===//
+#include "llvm-libc-macros/sys-queue-macros.h"
#include "src/__support/CPP/string.h"
#include "src/__support/char_vector.h"
#include "test/UnitTest/Test.h"
-#include <sys/queue.h>
-
using LIBC_NAMESPACE::CharVector;
using LIBC_NAMESPACE::cpp::string;
>From 5b89ca8280fc52ace64a201aa3616f6cf0b2cbed Mon Sep 17 00:00:00 2001
From: Petr Hosek <phosek at google.com>
Date: Thu, 18 Jan 2024 06:47:33 +0000
Subject: [PATCH 4/6] Fix tests
---
libc/include/CMakeLists.txt | 1 +
libc/test/include/CMakeLists.txt | 4 ++--
libc/test/include/sys/queue_test.cpp | 3 ++-
3 files changed, 5 insertions(+), 3 deletions(-)
diff --git a/libc/include/CMakeLists.txt b/libc/include/CMakeLists.txt
index 2ff9c65ddf0802..500f5ccc9cc69d 100644
--- a/libc/include/CMakeLists.txt
+++ b/libc/include/CMakeLists.txt
@@ -352,6 +352,7 @@ add_header(
DEPENDS
.llvm-libc-macros.null_macro
.llvm-libc-macros.containerof_macro
+ .llvm-libc-macros.sys_queue_macros
)
add_gen_header(
diff --git a/libc/test/include/CMakeLists.txt b/libc/test/include/CMakeLists.txt
index 2c6ab017c47ade..99e932151d5c04 100644
--- a/libc/test/include/CMakeLists.txt
+++ b/libc/test/include/CMakeLists.txt
@@ -1,13 +1,13 @@
add_custom_target(libc_include_tests)
-add_libc_test(
+add_libc_unittest(
sys_queue_test
SUITE
libc_include_tests
SRCS
sys/queue_test.cpp
DEPENDS
- libc.include.sys.sys_queue_macros
+ libc.include.llvm-libc-macros.sys_queue_macros
libc.src.__support.char_vector
libc.src.__support.CPP.string
COMPILE_OPTIONS
diff --git a/libc/test/include/sys/queue_test.cpp b/libc/test/include/sys/queue_test.cpp
index f3bf3a5c7055c4..48c0e811c61542 100644
--- a/libc/test/include/sys/queue_test.cpp
+++ b/libc/test/include/sys/queue_test.cpp
@@ -6,11 +6,12 @@
//
//===----------------------------------------------------------------------===//
-#include "llvm-libc-macros/sys-queue-macros.h"
#include "src/__support/CPP/string.h"
#include "src/__support/char_vector.h"
#include "test/UnitTest/Test.h"
+#include "llvm-libc-macros/sys-queue-macros.h"
+
using LIBC_NAMESPACE::CharVector;
using LIBC_NAMESPACE::cpp::string;
>From 668192b94c378ba52bcd62da55aed59cd6e54eea Mon Sep 17 00:00:00 2001
From: Petr Hosek <phosek at google.com>
Date: Thu, 18 Jan 2024 21:40:47 +0000
Subject: [PATCH 5/6] Address review feedback
---
libc/include/CMakeLists.txt | 2 --
libc/include/llvm-libc-macros/CMakeLists.txt | 3 +++
libc/include/llvm-libc-macros/sys-queue-macros.h | 4 ++--
libc/include/sys/queue.h | 3 +--
4 files changed, 6 insertions(+), 6 deletions(-)
diff --git a/libc/include/CMakeLists.txt b/libc/include/CMakeLists.txt
index 500f5ccc9cc69d..9a06f829eee18a 100644
--- a/libc/include/CMakeLists.txt
+++ b/libc/include/CMakeLists.txt
@@ -350,8 +350,6 @@ add_header(
HDR
sys/queue.h
DEPENDS
- .llvm-libc-macros.null_macro
- .llvm-libc-macros.containerof_macro
.llvm-libc-macros.sys_queue_macros
)
diff --git a/libc/include/llvm-libc-macros/CMakeLists.txt b/libc/include/llvm-libc-macros/CMakeLists.txt
index 15f8b37acaf164..7b2616d4311d94 100644
--- a/libc/include/llvm-libc-macros/CMakeLists.txt
+++ b/libc/include/llvm-libc-macros/CMakeLists.txt
@@ -139,6 +139,9 @@ add_macro_header(
sys_queue_macros
HDR
sys-queue-macros.h
+ DEPENDS
+ .null_macro
+ .containerof_macro
)
add_macro_header(
diff --git a/libc/include/llvm-libc-macros/sys-queue-macros.h b/libc/include/llvm-libc-macros/sys-queue-macros.h
index b34283573dc26f..f41e7363e418bf 100644
--- a/libc/include/llvm-libc-macros/sys-queue-macros.h
+++ b/libc/include/llvm-libc-macros/sys-queue-macros.h
@@ -105,8 +105,8 @@
SLIST_REMOVE_HEAD(head, field); \
} else { \
QUEUE_TYPEOF(type) *cur = SLIST_FIRST(head); \
- while (SLIST_NEXT(elem, field) != (elem)) \
- cur = SLIST_NEXT(elem, field); \
+ while (SLIST_NEXT(cur, field) != (elem)) \
+ cur = SLIST_NEXT(cur, field); \
SLIST_REMOVE_AFTER(cur, field); \
} \
} while (0)
diff --git a/libc/include/sys/queue.h b/libc/include/sys/queue.h
index 3804a563da34d5..b98b15bdffcf8d 100644
--- a/libc/include/sys/queue.h
+++ b/libc/include/sys/queue.h
@@ -9,8 +9,7 @@
#ifndef LLVM_LIBC_SYS_QUEUE_H
#define LLVM_LIBC_SYS_QUEUE_H
-#include <__llvm-libc-common.h>
-
#include <llvm-libc-macros/sys-queue-macros.h>
#endif // LLVM_LIBC_SYS_QUEUE_H
+
>From 6230748ddaee62e4a9b59bbca157a05d0f5c1d84 Mon Sep 17 00:00:00 2001
From: Petr Hosek <phosek at google.com>
Date: Fri, 19 Jan 2024 03:24:32 +0000
Subject: [PATCH 6/6] Address review feedback
---
libc/include/llvm-libc-macros/containerof-macro.h | 2 +-
libc/include/sys/queue.h | 1 -
libc/test/include/CMakeLists.txt | 1 +
3 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/libc/include/llvm-libc-macros/containerof-macro.h b/libc/include/llvm-libc-macros/containerof-macro.h
index 14c0217fc1d45e..ea91fa7097a4f2 100644
--- a/libc/include/llvm-libc-macros/containerof-macro.h
+++ b/libc/include/llvm-libc-macros/containerof-macro.h
@@ -13,7 +13,7 @@
#define __containerof(ptr, type, member) \
({ \
- const __typeof(((type *)0)->member) *__ptr = ptr; \
+ const __typeof(((type *)0)->member) *__ptr = (ptr); \
(type *)(void *)((const char *)__ptr - offsetof(type, member)); \
})
diff --git a/libc/include/sys/queue.h b/libc/include/sys/queue.h
index b98b15bdffcf8d..2a4dc37712d6d9 100644
--- a/libc/include/sys/queue.h
+++ b/libc/include/sys/queue.h
@@ -12,4 +12,3 @@
#include <llvm-libc-macros/sys-queue-macros.h>
#endif // LLVM_LIBC_SYS_QUEUE_H
-
diff --git a/libc/test/include/CMakeLists.txt b/libc/test/include/CMakeLists.txt
index 99e932151d5c04..95a3aba9d95d90 100644
--- a/libc/test/include/CMakeLists.txt
+++ b/libc/test/include/CMakeLists.txt
@@ -11,5 +11,6 @@ add_libc_unittest(
libc.src.__support.char_vector
libc.src.__support.CPP.string
COMPILE_OPTIONS
+ # This is needed because the __containerof macro uses statement expression.
-Wno-gnu-statement-expression-from-macro-expansion
)
More information about the libc-commits
mailing list