Patchwork [RFC,1/2] Provide infrastructure for marking private QOM struct fields

login
register
mail settings
Submitter Peter Maydell
Date July 25, 2013, 4:42 p.m.
Message ID <1374770523-6570-2-git-send-email-peter.maydell@linaro.org>
Download mbox | patch
Permalink /patch/261796/
State New
Headers show

Comments

Peter Maydell - July 25, 2013, 4:42 p.m.
Provide infrastructure for marking private QOM struct fields,
so that a compiler warning is generated when a user of the QOM
object attempts to access them directly.

This is implemented using GCC's 'deprecated' attribute; preprocessor
macros arrange that when compiling the class implementation,
no attribute is applied to the fields; when compiling a user
of the class the fields are marked deprecated.

This allows us to have a single simple C struct defining the
object, and for users of the QOM object to be able to embed
instances of it into other structs, but still to have a guard
against users accidentally touching parts of the structure
they should not be accessing.

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
 include/qemu/compiler.h |   10 ++++++++++
 include/qom/object.h    |   47 +++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 57 insertions(+)
Edgar Iglesias - July 26, 2013, 4:39 a.m.
On Thu, Jul 25, 2013 at 05:42:02PM +0100, Peter Maydell wrote:
> Provide infrastructure for marking private QOM struct fields,
> so that a compiler warning is generated when a user of the QOM
> object attempts to access them directly.
> 
> This is implemented using GCC's 'deprecated' attribute; preprocessor
> macros arrange that when compiling the class implementation,
> no attribute is applied to the fields; when compiling a user
> of the class the fields are marked deprecated.
> 
> This allows us to have a single simple C struct defining the
> object, and for users of the QOM object to be able to embed
> instances of it into other structs, but still to have a guard
> against users accidentally touching parts of the structure
> they should not be accessing.

Very cool =)

Maybe there is a way to decrease the plain text impl footprint by
using header files?

#define im_the_implementation
#include xxx
#undef im_the_implementation

or something better...

Cheers,
Edgar

> 
> Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
> ---
>  include/qemu/compiler.h |   10 ++++++++++
>  include/qom/object.h    |   47 +++++++++++++++++++++++++++++++++++++++++++++++
>  2 files changed, 57 insertions(+)
> 
> diff --git a/include/qemu/compiler.h b/include/qemu/compiler.h
> index 155b358..d7cc153 100644
> --- a/include/qemu/compiler.h
> +++ b/include/qemu/compiler.h
> @@ -52,4 +52,14 @@
>  #define GCC_FMT_ATTR(n, m)
>  #endif
>  
> +/* An attribute usable to mark structure fields as private to the
> + * implementation; since this is only a diagnostic to catch programming
> + * errors, it's OK if it expands to nothing on non-gcc compilers.
> + */
> +#if defined __GNUC__
> +# define QEMU_PRIVATE_ATTR __attribute__((deprecated("this field is private")))
> +#else
> +# define QEMU_PRIVATE_ATTR
> +#endif
> +
>  #endif /* COMPILER_H */
> diff --git a/include/qom/object.h b/include/qom/object.h
> index 23fc048..7f02f80 100644
> --- a/include/qom/object.h
> +++ b/include/qom/object.h
> @@ -284,6 +284,53 @@ typedef struct InterfaceInfo InterfaceInfo;
>   *
>   * The first example of such a QOM method was #CPUClass.reset,
>   * another example is #DeviceClass.realize.
> + *
> + * = Marking fields as private to the class implementation =
> + *
> + * The expected code structure for QOM objects is that they should
> + * have a header file in include/ which defines the class and object
> + * structures and the typecasting macros. This header can then be
> + * included by both the source file which implements the QOM object
> + * and also by other source files which merely wish to use the object.
> + * Users of your object need the class and object structures so that
> + * they can embed instances of the object in their own structures;
> + * however they do not need to be able to access individual fields in
> + * these structures. To enforce this you should use the QEMU_PRIVATE_ATTR
> + * macro in a pattern like this:
> + *
> + * <example>
> + *   <title>Marking fields as private</title>
> + *   <programlisting>
> + * #ifdef IMPLEMENTING_MY_DEVICE
> + * # define __private
> + * #else
> + * # define __private QEMU_PRIVATE_ATTR
> + * #endif
> + *
> + * typedef struct MyDevice
> + * {
> + *     __private DeviceState parent;
> + *
> + *     __private int reg0, reg1, reg2;
> + * } MyDevice;
> + *
> + * typedef struct MyDeviceClass
> + * {
> + *     __private DeviceClass parent;
> + *
> + *     void (*frobnicate) (MyDevice *obj);
> + * } MyDeviceClass;
> + *
> + * #undef __private
> + *   </programlisting>
> + * </example>
> + *
> + * The source files which provide the implementation of your
> + * class (or of subclasses to it) should then have
> + * "#define IMPLEMENTING_MY_DEVICE" before they include any
> + * headers. Since users of the class will not define this
> + * macro, they will get a compilation warning if they access
> + * any of the private fields by mistake.
>   */
>  
>  
> -- 
> 1.7.9.5
> 
>

Patch

diff --git a/include/qemu/compiler.h b/include/qemu/compiler.h
index 155b358..d7cc153 100644
--- a/include/qemu/compiler.h
+++ b/include/qemu/compiler.h
@@ -52,4 +52,14 @@ 
 #define GCC_FMT_ATTR(n, m)
 #endif
 
+/* An attribute usable to mark structure fields as private to the
+ * implementation; since this is only a diagnostic to catch programming
+ * errors, it's OK if it expands to nothing on non-gcc compilers.
+ */
+#if defined __GNUC__
+# define QEMU_PRIVATE_ATTR __attribute__((deprecated("this field is private")))
+#else
+# define QEMU_PRIVATE_ATTR
+#endif
+
 #endif /* COMPILER_H */
diff --git a/include/qom/object.h b/include/qom/object.h
index 23fc048..7f02f80 100644
--- a/include/qom/object.h
+++ b/include/qom/object.h
@@ -284,6 +284,53 @@  typedef struct InterfaceInfo InterfaceInfo;
  *
  * The first example of such a QOM method was #CPUClass.reset,
  * another example is #DeviceClass.realize.
+ *
+ * = Marking fields as private to the class implementation =
+ *
+ * The expected code structure for QOM objects is that they should
+ * have a header file in include/ which defines the class and object
+ * structures and the typecasting macros. This header can then be
+ * included by both the source file which implements the QOM object
+ * and also by other source files which merely wish to use the object.
+ * Users of your object need the class and object structures so that
+ * they can embed instances of the object in their own structures;
+ * however they do not need to be able to access individual fields in
+ * these structures. To enforce this you should use the QEMU_PRIVATE_ATTR
+ * macro in a pattern like this:
+ *
+ * <example>
+ *   <title>Marking fields as private</title>
+ *   <programlisting>
+ * #ifdef IMPLEMENTING_MY_DEVICE
+ * # define __private
+ * #else
+ * # define __private QEMU_PRIVATE_ATTR
+ * #endif
+ *
+ * typedef struct MyDevice
+ * {
+ *     __private DeviceState parent;
+ *
+ *     __private int reg0, reg1, reg2;
+ * } MyDevice;
+ *
+ * typedef struct MyDeviceClass
+ * {
+ *     __private DeviceClass parent;
+ *
+ *     void (*frobnicate) (MyDevice *obj);
+ * } MyDeviceClass;
+ *
+ * #undef __private
+ *   </programlisting>
+ * </example>
+ *
+ * The source files which provide the implementation of your
+ * class (or of subclasses to it) should then have
+ * "#define IMPLEMENTING_MY_DEVICE" before they include any
+ * headers. Since users of the class will not define this
+ * macro, they will get a compilation warning if they access
+ * any of the private fields by mistake.
  */