NetBSD-Bugs archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

Re: lib/58729: container_of is not documented or available in userland



Here's a draft that just duplicates the include/stddef.h definition of
offsetof for now.  It coexists peacefully in the kernel with the
libkern.h definition -- with #ifndef offsetof hacks in both places.
Not great but it'll serve to address the immediate issue without
deciding how best to disentangle things.

Another thought I had is that it might be worthwhile to have
__container_of and __offsetof macros that would avoid namespace
pollution, and only expose container_of and offsetof if you explicitly
ask for a header file defined to use them.  But I don't have a use
case for this right now so I won't do anything about this.
# HG changeset patch
# User Taylor R Campbell <riastradh%NetBSD.org@localhost>
# Date 1728402416 0
#      Tue Oct 08 15:46:56 2024 +0000
# Branch trunk
# Node ID 32a19974e47ea523810619381ab6d96671c537c9
# Parent  324886ee2905fda3948217e0fd3c6ca7f4cf32dc
# EXP-Topic riastradh-pr58729-containerof
container_of: New header file sys/container_of.h for this.

PR lib/58729: container_of is not documented or available in userland

diff -r 324886ee2905 -r 32a19974e47e sys/lib/libkern/libkern.h
--- a/sys/lib/libkern/libkern.h	Tue Oct 08 12:49:01 2024 +0000
+++ b/sys/lib/libkern/libkern.h	Tue Oct 08 15:46:56 2024 +0000
@@ -323,46 +323,7 @@ tolower(int ch)
 #endif
 #endif
 
-/*
- * Return the container of an embedded struct.  Given x = &c->f,
- * container_of(x, T, f) yields c, where T is the type of c.  Example:
- *
- *	struct foo { ... };
- *	struct bar {
- *		int b_x;
- *		struct foo b_foo;
- *		...
- *	};
- *
- *	struct bar b;
- *	struct foo *fp = &b.b_foo;
- *
- * Now we can get at b from fp by:
- *
- *	struct bar *bp = container_of(fp, struct bar, b_foo);
- *
- * The 0*sizeof((PTR) - ...) causes the compiler to warn if the type of
- * *fp does not match the type of struct bar::b_foo.
- * We skip the validation for coverity runs to avoid warnings.
- */
-#if defined(__COVERITY__) || defined(__LGTM_BOT__)
-#define __validate_container_of(PTR, TYPE, FIELD) 0
-#define __validate_const_container_of(PTR, TYPE, FIELD) 0
-#else
-#define __validate_container_of(PTR, TYPE, FIELD)			\
-    (0 * sizeof((PTR) - &((TYPE *)(((char *)(PTR)) -			\
-    offsetof(TYPE, FIELD)))->FIELD))
-#define __validate_const_container_of(PTR, TYPE, FIELD)			\
-    (0 * sizeof((PTR) - &((const TYPE *)(((const char *)(PTR)) -	\
-    offsetof(TYPE, FIELD)))->FIELD))
-#endif
-
-#define	container_of(PTR, TYPE, FIELD)					\
-    ((TYPE *)(((char *)(PTR)) - offsetof(TYPE, FIELD))			\
-	+ __validate_container_of(PTR, TYPE, FIELD))
-#define	const_container_of(PTR, TYPE, FIELD)				\
-    ((const TYPE *)(((const char *)(PTR)) - offsetof(TYPE, FIELD))	\
-	+ __validate_const_container_of(PTR, TYPE, FIELD))
+#include <sys/container_of.h>
 
 /* Prototypes for which GCC built-ins exist. */
 void	*memcpy(void *, const void *, size_t);
diff -r 324886ee2905 -r 32a19974e47e sys/sys/container_of.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sys/sys/container_of.h	Tue Oct 08 15:46:56 2024 +0000
@@ -0,0 +1,101 @@
+/*	$NetBSD$	*/
+
+/*-
+ * Copyright (c) 2013 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Taylor R. Campbell.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef	_SYS_CONTAINER_OF_H_
+#define	_SYS_CONTAINER_OF_H_
+
+#include <sys/ansi.h>
+
+#ifdef	_BSD_SIZE_T_
+typedef	_BSD_SIZE_T_	size_t;
+#undef	_BSD_SIZE_T_
+#endif
+
+/*
+ * XXX Avoid duplicating this with sys/lib/libkern/libkern.h and
+ * include/stddef.h.
+ */
+#ifndef offsetof
+#if __GNUC_PREREQ__(4, 0)
+#define	offsetof(type, member)	__builtin_offsetof(type, member)
+#elif !defined(__cplusplus)
+#define	offsetof(type, member)	((size_t)(unsigned long)(&((type *)0)->member))
+#else
+#if !__GNUC_PREREQ__(3, 4)
+#define __offsetof__(a) a
+#endif
+#define	offsetof(type, member) __offsetof__((reinterpret_cast<size_t> \
+    (&reinterpret_cast<const volatile char &>(static_cast<type *>(0)->member))))
+#endif
+#endif
+
+/*
+ * Return the container of an embedded struct.  Given x = &c->f,
+ * container_of(x, T, f) yields c, where T is the type of c.  Example:
+ *
+ *	struct foo { ... };
+ *	struct bar {
+ *		int b_x;
+ *		struct foo b_foo;
+ *		...
+ *	};
+ *
+ *	struct bar b;
+ *	struct foo *fp = &b.b_foo;
+ *
+ * Now we can get at b from fp by:
+ *
+ *	struct bar *bp = container_of(fp, struct bar, b_foo);
+ *
+ * The 0*sizeof((PTR) - ...) causes the compiler to warn if the type of
+ * *fp does not match the type of struct bar::b_foo.
+ * We skip the validation for coverity runs to avoid warnings.
+ */
+#if defined(__COVERITY__) || defined(__LGTM_BOT__)
+#define __validate_container_of(PTR, TYPE, FIELD) 0
+#define __validate_const_container_of(PTR, TYPE, FIELD) 0
+#else
+#define __validate_container_of(PTR, TYPE, FIELD)			\
+    (0 * sizeof((PTR) - &((TYPE *)(((char *)(PTR)) -			\
+    offsetof(TYPE, FIELD)))->FIELD))
+#define __validate_const_container_of(PTR, TYPE, FIELD)			\
+    (0 * sizeof((PTR) - &((const TYPE *)(((const char *)(PTR)) -	\
+    offsetof(TYPE, FIELD)))->FIELD))
+#endif
+
+#define	container_of(PTR, TYPE, FIELD)					\
+    ((TYPE *)(((char *)(PTR)) - offsetof(TYPE, FIELD))			\
+	+ __validate_container_of(PTR, TYPE, FIELD))
+#define	const_container_of(PTR, TYPE, FIELD)				\
+    ((const TYPE *)(((const char *)(PTR)) - offsetof(TYPE, FIELD))	\
+	+ __validate_const_container_of(PTR, TYPE, FIELD))
+
+#endif	/* _SYS_CONTAINER_OF_H_ */
# HG changeset patch
# User Taylor R Campbell <riastradh%NetBSD.org@localhost>
# Date 1728407830 0
#      Tue Oct 08 17:17:10 2024 +0000
# Branch trunk
# Node ID 4529dd9470d4274e62fb97bbbfc358f45342be28
# Parent  32a19974e47ea523810619381ab6d96671c537c9
# EXP-Topic riastradh-pr58729-containerof
container_of(3): New man page.

PR lib/58729: container_of is not documented or available in userland

diff -r 32a19974e47e -r 4529dd9470d4 distrib/sets/lists/comp/mi
--- a/distrib/sets/lists/comp/mi	Tue Oct 08 15:46:56 2024 +0000
+++ b/distrib/sets/lists/comp/mi	Tue Oct 08 17:17:10 2024 +0000
@@ -7024,8 +7024,10 @@
 ./usr/share/man/cat3/conj.0			comp-c-catman		complex,.cat
 ./usr/share/man/cat3/conjf.0			comp-c-catman		complex,.cat
 ./usr/share/man/cat3/conjl.0			comp-c-catman		complex,.cat
+./usr/share/man/cat3/const_container_of.0	comp-c-catman		.cat
 ./usr/share/man/cat3/consttime_bcmp.0		comp-obsolete		obsolete
 ./usr/share/man/cat3/consttime_memequal.0	comp-c-catman		.cat
+./usr/share/man/cat3/container_of.0		comp-c-catman		.cat
 ./usr/share/man/cat3/copysign.0			comp-c-catman		.cat
 ./usr/share/man/cat3/copysignf.0		comp-c-catman		.cat
 ./usr/share/man/cat3/copysignl.0		comp-c-catman		.cat
@@ -15552,8 +15554,10 @@
 ./usr/share/man/html3/conj.html			comp-c-htmlman		complex,html
 ./usr/share/man/html3/conjf.html		comp-c-htmlman		complex,html
 ./usr/share/man/html3/conjl.html		comp-c-htmlman		complex,html
+./usr/share/man/html3/const_container_of.html	comp-c-htmlman		html
 ./usr/share/man/html3/consttime_bcmp.html	comp-obsolete		obsolete
 ./usr/share/man/html3/consttime_memequal.html	comp-c-htmlman		html
+./usr/share/man/html3/container_of.html		comp-c-htmlman		html
 ./usr/share/man/html3/copysign.html		comp-c-htmlman		html
 ./usr/share/man/html3/copysignf.html		comp-c-htmlman		html
 ./usr/share/man/html3/copysignl.html		comp-c-htmlman		html
@@ -24025,8 +24029,10 @@
 ./usr/share/man/man3/conj.3			comp-c-man		complex,.man
 ./usr/share/man/man3/conjf.3			comp-c-man		complex,.man
 ./usr/share/man/man3/conjl.3			comp-c-man		complex,.man
+./usr/share/man/man3/const_container_of.3	comp-c-man		.man
 ./usr/share/man/man3/consttime_bcmp.3		comp-obsolete		obsolete
 ./usr/share/man/man3/consttime_memequal.3	comp-c-man		.man
+./usr/share/man/man3/container_of.3		comp-c-man		.man
 ./usr/share/man/man3/copysign.3			comp-c-man		.man
 ./usr/share/man/man3/copysignf.3		comp-c-man		.man
 ./usr/share/man/man3/copysignl.3		comp-c-man		.man
diff -r 32a19974e47e -r 4529dd9470d4 share/man/man3/Makefile
--- a/share/man/man3/Makefile	Tue Oct 08 15:46:56 2024 +0000
+++ b/share/man/man3/Makefile	Tue Oct 08 17:17:10 2024 +0000
@@ -7,7 +7,8 @@ MAN=	_DIAGASSERT.3 __CONCAT.3 __FPTRCAST
 	__builtin_return_address.3 \
 	__builtin_types_compatible_p.3 __insn_barrier.3 \
 	assert.3 attribute.3 bitmap.3 bitops.3 bits.3 bitstring.3 \
-	cdefs.3 dirent.3 dlfcn.3 dlinfo.3 dl_iterate_phdr.3 end.3 \
+	cdefs.3 container_of.3 \
+	dirent.3 dlfcn.3 dlinfo.3 dl_iterate_phdr.3 end.3 \
 	fast_divide32.3 ffs32.3 gcq.3 \
 	ilog2.3 intro.3 inttypes.3 iso646.3 limits.3 \
 	makedev.3 offsetof.3 param.3 paths.3 queue.3 rbtree.3 sigevent.3 \
@@ -54,6 +55,7 @@ MLINKS+=bits.3 __BIT.3 \
 	bits.3 __SHIFTOUT_MASK.3
 MLINKS+=cdefs.3 __RCSID.3 \
 	cdefs.3 __KERNEL_RCSID.3
+MLINKS+=container_of.3 const_container_of.3
 MLINKS+=end.3 edata.3 end.3 etext.3
 MLINKS+=fast_divide32.3 fast_divide32_prepare.3 \
 	fast_divide32.3 fast_remainder32.3
diff -r 32a19974e47e -r 4529dd9470d4 share/man/man3/container_of.3
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/share/man/man3/container_of.3	Tue Oct 08 17:17:10 2024 +0000
@@ -0,0 +1,109 @@
+.\"	$NetBSD$
+.\"
+.\" Copyright (c) 2024 The NetBSD Foundation, Inc.
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\"    notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\"    notice, this list of conditions and the following disclaimer in the
+.\"    documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+.\" ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+.\" TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+.\" PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+.\" BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+.\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+.\" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+.\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+.\" CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+.\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+.\" POSSIBILITY OF SUCH DAMAGE.
+.\"
+.Dd October 8, 2024
+.Dt CONTAINER_OF 3
+.Os
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.Sh NAME
+.Nm container_of ,
+.Nm const_container_of
+.Nd struct container accessor macros
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.Sh SYNOPSIS
+.In sys/container_of.h
+.Ft struct_type *
+.Fn container_of "member_type *ptr" "struct_type" "member"
+.Ft const struct_type *
+.Fn const_container_of "const member_type *ptr" "struct_type" "member"
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.Sh DESCRIPTION
+Given a pointer to a member of a structure, the
+.Fn container_of
+macro returns a pointer to the containing structure.
+.Pp
+The caller must specify the containing structure's type and the name of
+the member in the containing structure, which must have type compatible
+with what the input pointer points to.
+.Pp
+The
+.Fn const_container_of
+macro does similarly for a const-qualified pointer.
+.Pp
+The call
+.Fn container_of P T M
+is essentially equivalent to
+.Dl "(" Ns Fa T Li "*)((char *)" Ns Fa P Li "-" Fn offsetof T M Ns ")" ,
+but it is safer because it checks the type of
+.Fa P
+against the type of member
+.Fa M
+of structure type
+.Fa T .
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.Sh EXAMPLES
+.Bd -literal
+/* Gizmo data structure */
+struct gizmo {
+	...
+	struct work	gz_work;
+	...
+};
+
+/* Enqueue gizmo-related work */
+	struct gizmo *gz = ...;
+	struct work = &gz->gz_work;
+
+	workqueue_enqueue(gizmo_workqueue, work, NULL);
+
+/* Function to process queued gizmo-related work */
+void
+gizmo_work(struct work *work, void *cookie)
+{
+	struct gizmo *gz = container_of(work, struct gizmo, gz_work);
+
+	...
+}
+.Ed
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.Sh SEE ALSO
+.Xr offsetof 3
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.Sh HISTORY
+The
+.Fn container_of
+and
+.Fn const_container_of
+macros first appeared in
+.Nx 8.0
+in
+.In libkern.h
+for kernel use.
+They were moved in
+.Nx 11.0
+to
+.In sys/container_of.h
+for use by both kernel and userland.


Home | Main Index | Thread Index | Old Index