From f6dff2c3bdbcb392d629ee851eac70b054536fbd Mon Sep 17 00:00:00 2001 From: =?utf8?q?J=C3=A9r=C3=A9mie=20Galarneau?= Date: Fri, 22 May 2020 22:04:31 +0000 Subject: [PATCH] Backport LTTNG_OPTIONAL util MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit A follow-up fix makes use of the LTTNG_OPTIONAL utility. optional.h is identical to the version found in 3e778ab02. Change-Id: I98a3efefe1ab6193e0d3c9c16d00f797551f36d9 Signed-off-by: Jérémie Galarneau --- src/common/Makefile.am | 3 +- src/common/optional.h | 91 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 93 insertions(+), 1 deletion(-) create mode 100644 src/common/optional.h diff --git a/src/common/Makefile.am b/src/common/Makefile.am index 0feb0a0d1..e3feaa38f 100644 --- a/src/common/Makefile.am +++ b/src/common/Makefile.am @@ -72,7 +72,8 @@ libcommon_la_SOURCES = error.h error.c utils.c utils.h runas.c runas.h \ dynamic-buffer.h dynamic-buffer.c \ buffer-view.h buffer-view.c \ unix.c unix.h \ - filter.c filter.h context.c context.h + filter.c filter.h context.c context.h \ + optional.h libcommon_la_LIBADD = \ $(top_builddir)/src/common/config/libconfig.la diff --git a/src/common/optional.h b/src/common/optional.h new file mode 100644 index 000000000..05f6054da --- /dev/null +++ b/src/common/optional.h @@ -0,0 +1,91 @@ +/* + * Copyright (C) 2019 Jérémie Galarneau + * + * SPDX-License-Identifier: GPL-2.0-only + * + */ + +#ifndef LTTNG_OPTIONAL_H +#define LTTNG_OPTIONAL_H + +#include +#include + +/* + * Define wrapper structure representing an optional value. + * + * This macro defines an "is_set" boolean field that must be checked + * when accessing the optional field. This "is_set" field provides + * the semantics that would be expected of a typical "raw pointer" field + * which would be checked for NULL. + * + * Prefer using this macro where "special" values would be used, e.g. + * -1ULL for uint64_t types. + * + * Declaration example: + * struct my_struct { + * int a; + * LTTNG_OPTIONAL(int, b); + * }; + * + * Usage example: + * struct my_struct foo = LTTNG_OPTIONAL_INIT; + * + * LTTNG_OPTIONAL_SET(&foo.b, 42); + * if (foo.b.is_set) { + * printf("%d", foo.b.value); + * } + * + * LTTNG_OPTIONAL_UNSET(&foo.b); + */ +#define LTTNG_OPTIONAL(type) \ + struct { \ + uint8_t is_set; \ + type value; \ + } + +/* + * Alias used for communication structures. If the layout of an LTTNG_OPTIONAL + * is changed, the original layout should still be used for communication + * purposes. + * + * LTTNG_OPTIONAL_COMM should be combined with the LTTNG_PACKED macro when + * used for IPC / network communication. + */ +#define LTTNG_OPTIONAL_COMM LTTNG_OPTIONAL + +/* + * This macro is available as a 'convenience' to allow sites that assume + * an optional value is set to assert() that it is set when accessing it. + * + * Since this returns the 'optional' by value, it is not suitable for all + * wrapped optional types. It is meant to be used with PODs. + */ +#define LTTNG_OPTIONAL_GET(optional) \ + ({ \ + assert((optional).is_set); \ + (optional).value; \ + }) + +/* + * Initialize an optional field. + * + * The wrapped field is set to the value it would gave if it had static storage + * duration. + */ +#define LTTNG_OPTIONAL_INIT { .is_set = 0 } + +/* Set the value of an optional field. */ +#define LTTNG_OPTIONAL_SET(field_ptr, val) \ + do { \ + (field_ptr)->value = (val); \ + (field_ptr)->is_set = 1; \ + } while (0) + +/* Put an optional field in the "unset" (NULL-ed) state. */ +#define LTTNG_OPTIONAL_UNSET(field_ptr) \ + do { \ + (field_ptr)->is_set = 0; \ + } while (0) + +#endif /* LTTNG_OPTIONAL_H */ -- 2.34.1