From 686bbf1e7ff7492a86f48d4b9877c2cfb5deca53 Mon Sep 17 00:00:00 2001 From: Daan De Meyer Date: Tue, 13 May 2025 11:50:05 +0200 Subject: [PATCH] Introduce forward.h header with forward declarations In preparation for adopting forward declarations to reduce unnecessary transitive includes across the tree, let's introduce a forward.h header with forward declarations for all libc, libsystemd, basic and shared types. Additionally, this header exports all basic integer types and errno constants, as well as all macros including assertions macros. These header files contain types often used in headers and are always included in every source file one way or another anyway. To avoid having to include memory-util.h and alloc-util.h in forward.h, we split off the parts we need from both into cleanup-util.h and only include cleanup-util.h in forward.h. To keep this commit self-contained, we include cleanup-fundamental.h and cleanup-util.h from the headers that originally contained the same macros. We'll remove these again in a later commit that optimizes the includes in src/basic and src/fundamental. Split out of #37364 --- docs/CODING_STYLE.md | 47 +++- src/basic/alloc-util.h | 25 +- src/basic/cleanup-util.h | 81 ++++++ src/basic/forward.h | 295 ++++++++++++++++++++++ src/basic/memory-util.h | 54 +--- src/fundamental/cleanup-fundamental.h | 75 ++++++ src/fundamental/macro-fundamental.h | 7 + src/fundamental/memory-util-fundamental.h | 73 +----- 8 files changed, 495 insertions(+), 162 deletions(-) create mode 100644 src/basic/cleanup-util.h create mode 100644 src/basic/forward.h create mode 100644 src/fundamental/cleanup-fundamental.h diff --git a/docs/CODING_STYLE.md b/docs/CODING_STYLE.md index efc9d2ae3e6..82b33029532 100644 --- a/docs/CODING_STYLE.md +++ b/docs/CODING_STYLE.md @@ -249,6 +249,9 @@ SPDX-License-Identifier: LGPL-2.1-or-later inline functions that require the full definition of a struct into the implementation file so that only a forward declaration of the struct is required and not the full definition. + - `src/basic/forward.h` contains forward declarations for common types. If + possible, only include `forward.h` in header files which makes circular + header dependencies a non-issue. Bad: @@ -306,24 +309,40 @@ SPDX-License-Identifier: LGPL-2.1-or-later the implementation (.c) file over implementing them in the corresponding header file. Inline functions in the header are allowed if they are just a few lines and don't require including any extra header files that would otherwise - not have to be included. Similarly, prefer forward declarations of structs - over including the corresponding header file. Keeping header files as lean as - possible speeds up incremental builds when header files are changed (either by - yourself when working on a pull request or as part of rebasing onto the main - branch) as each file that (transitively) includes a header that was changed - needs to be recompiled. By keeping the number of header files included by - other header files low, we reduce the impact of modifying header files on + not have to be included. Keeping header files as lean as possible speeds up + incremental builds when header files are changed (either by yourself when + working on a pull request or as part of rebasing onto the main branch) as each + file that (transitively) includes a header that was changed needs to be + recompiled. By keeping the number of header files included by other header + files low, we reduce the impact of modifying header files on incremental builds as much as possible. + To avoid having to include other headers in header files, always include + `forward.h` in each header file and then add other required includes as + needed. `forward.h` already includes generic headers and contains forward + declarations for common types which should be sufficient for most header + files. For each extra include you add on top of `forward.h`, check if it can + be replaced by adding another forward declaration to `forward.h`. Depending on + the daemon, there might be a specific forward header to include (e.g. + `resolved-forward.h` for systemd-resolved header files). + + Header files that extend other header files can include the original header + file. For example, `iovec-util.h` includes `iovec-fundamental.h` and + `sys/uio.h`. To identify headers that are exported from other headers, add a + `IWYU pragma: export` comment to the includes so that these exports are + recognized by clang static analysis tooling. + Bad: ```c // source.h + #include + #include "log.h" - static inline void my_function_that_logs(void) { - log_error("oops"); + static inline void my_function_that_logs(size_t sz) { + log_error("oops: %zu", sz); } ``` @@ -332,15 +351,17 @@ SPDX-License-Identifier: LGPL-2.1-or-later ```c // source.h - void my_function_that_logs(void); + #include "forward.h" + + void my_function_that_logs(size_t sz); // source.c - #include "header.h" + #include "source.h" #include "log.h" - void my_function_that_logs(void) { - log_error("oops"); + void my_function_that_logs(size_t sz) { + log_error("oops: %zu", sz); } ``` diff --git a/src/basic/alloc-util.h b/src/basic/alloc-util.h index 7cf10ef4f3c..ec5b1059a84 100644 --- a/src/basic/alloc-util.h +++ b/src/basic/alloc-util.h @@ -7,6 +7,7 @@ #include #include "assert-util.h" +#include "cleanup-util.h" #include "macro.h" #include "memory-util.h" @@ -14,9 +15,6 @@ # include #endif -typedef void (*free_func_t)(void *p); -typedef void* (*mfree_func_t)(void *p); - /* If for some reason more than 4M are allocated on the stack, let's abort immediately. It's better than * proceeding and smashing the stack limits. Note that by default RLIMIT_STACK is 8M on Linux. */ #define ALLOCA_MAX (4U*1024U*1024U) @@ -52,30 +50,9 @@ typedef void* (*mfree_func_t)(void *p); #define malloc0(n) (calloc(1, (n) ?: 1)) -#define free_and_replace_full(a, b, free_func) \ - ({ \ - typeof(a)* _a = &(a); \ - typeof(b)* _b = &(b); \ - free_func(*_a); \ - *_a = *_b; \ - *_b = NULL; \ - 0; \ - }) - #define free_and_replace(a, b) \ free_and_replace_full(a, b, free) -/* This is similar to free_and_replace_full(), but NULL is not assigned to 'b', and its reference counter is - * increased. */ -#define unref_and_replace_full(a, b, ref_func, unref_func) \ - ({ \ - typeof(a)* _a = &(a); \ - typeof(b) _b = ref_func(b); \ - unref_func(*_a); \ - *_a = _b; \ - 0; \ - }) - void* memdup(const void *p, size_t l) _alloc_(2); void* memdup_suffix0(const void *p, size_t l); /* We can't use _alloc_() here, since we return a buffer one byte larger than the specified size */ diff --git a/src/basic/cleanup-util.h b/src/basic/cleanup-util.h new file mode 100644 index 00000000000..2d58b6654ab --- /dev/null +++ b/src/basic/cleanup-util.h @@ -0,0 +1,81 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +#pragma once + +#include "cleanup-fundamental.h" /* IWYU pragma: export */ + +typedef void (*free_func_t)(void *p); +typedef void* (*mfree_func_t)(void *p); + +#define free_and_replace_full(a, b, free_func) \ + ({ \ + typeof(a)* _a = &(a); \ + typeof(b)* _b = &(b); \ + free_func(*_a); \ + *_a = *_b; \ + *_b = NULL; \ + 0; \ + }) + +/* This is similar to free_and_replace_full(), but NULL is not assigned to 'b', and its reference counter is + * increased. */ +#define unref_and_replace_full(a, b, ref_func, unref_func) \ + ({ \ + typeof(a)* _a = &(a); \ + typeof(b) _b = ref_func(b); \ + unref_func(*_a); \ + *_a = _b; \ + 0; \ + }) + +#define _DEFINE_TRIVIAL_REF_FUNC(type, name, scope) \ + scope type *name##_ref(type *p) { \ + if (!p) \ + return NULL; \ + \ + /* For type check. */ \ + unsigned *q = &p->n_ref; \ + assert(*q > 0); \ + assert_se(*q < UINT_MAX); \ + \ + (*q)++; \ + return p; \ + } + +#define _DEFINE_TRIVIAL_UNREF_FUNC(type, name, free_func, scope) \ + scope type *name##_unref(type *p) { \ + if (!p) \ + return NULL; \ + \ + assert(p->n_ref > 0); \ + p->n_ref--; \ + if (p->n_ref > 0) \ + return NULL; \ + \ + return free_func(p); \ + } + +#define DEFINE_TRIVIAL_REF_FUNC(type, name) \ + _DEFINE_TRIVIAL_REF_FUNC(type, name,) +#define DEFINE_PRIVATE_TRIVIAL_REF_FUNC(type, name) \ + _DEFINE_TRIVIAL_REF_FUNC(type, name, static) +#define DEFINE_PUBLIC_TRIVIAL_REF_FUNC(type, name) \ + _DEFINE_TRIVIAL_REF_FUNC(type, name, _public_) + +#define DEFINE_TRIVIAL_UNREF_FUNC(type, name, free_func) \ + _DEFINE_TRIVIAL_UNREF_FUNC(type, name, free_func,) +#define DEFINE_PRIVATE_TRIVIAL_UNREF_FUNC(type, name, free_func) \ + _DEFINE_TRIVIAL_UNREF_FUNC(type, name, free_func, static) +#define DEFINE_PUBLIC_TRIVIAL_UNREF_FUNC(type, name, free_func) \ + _DEFINE_TRIVIAL_UNREF_FUNC(type, name, free_func, _public_) + +#define DEFINE_TRIVIAL_REF_UNREF_FUNC(type, name, free_func) \ + DEFINE_TRIVIAL_REF_FUNC(type, name); \ + DEFINE_TRIVIAL_UNREF_FUNC(type, name, free_func); + +#define DEFINE_PRIVATE_TRIVIAL_REF_UNREF_FUNC(type, name, free_func) \ + DEFINE_PRIVATE_TRIVIAL_REF_FUNC(type, name); \ + DEFINE_PRIVATE_TRIVIAL_UNREF_FUNC(type, name, free_func); + +#define DEFINE_PUBLIC_TRIVIAL_REF_UNREF_FUNC(type, name, free_func) \ + DEFINE_PUBLIC_TRIVIAL_REF_FUNC(type, name); \ + DEFINE_PUBLIC_TRIVIAL_UNREF_FUNC(type, name, free_func); diff --git a/src/basic/forward.h b/src/basic/forward.h new file mode 100644 index 00000000000..dda17ffcde1 --- /dev/null +++ b/src/basic/forward.h @@ -0,0 +1,295 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +#pragma once + +#include /* IWYU pragma: export */ +#include /* IWYU pragma: export */ +#include /* IWYU pragma: export */ +#include /* IWYU pragma: export */ +#include /* IWYU pragma: export */ +#include /* IWYU pragma: export */ +#include /* IWYU pragma: export */ +#include /* IWYU pragma: export */ +#include /* IWYU pragma: export */ + +#include "assert-util.h" /* IWYU pragma: export */ +#include "cleanup-util.h" /* IWYU pragma: export */ +#include "macro.h" /* IWYU pragma: export */ + +/* Generic types */ + +typedef uint64_t usec_t; +typedef uint64_t nsec_t; + +/* Libc forward declarations */ + +struct dirent; +struct ether_addr; +struct file_handle; +struct glob_t; +struct group; +struct icmp6_hdr; +struct in_addr; +struct in6_addr; +struct inotify_event; +struct iovec; +struct msghdr; +struct passwd; +struct pollfd; +struct rlimit; +struct sgrp; +struct shadow; +struct signalfd_siginfo; +struct siphash; +struct sockaddr; +struct spwd; +struct stat; +struct statfs; +struct statx_timestamp; +struct statx; +struct termios; +struct tm; +struct ucred; + +/* To forward declare FILE and DIR, we have to declare the internal struct names for them. Since these are + * used for C++ symbol name mangling, they're effectively part of the ABI and won't actually change. */ +typedef struct _IO_FILE FILE; +typedef struct __dirstream DIR; +typedef __socklen_t socklen_t; + +/* 3rd-party library forward declarations */ + +struct fdisk_context; +struct fdisk_table; +struct crypt_device; + +/* basic/ forward declarations */ + +typedef void (*hash_func_t)(const void *p, struct siphash *state); +typedef int (*compare_func_t)(const void *a, const void *b); +typedef compare_func_t comparison_fn_t; +typedef int (*comparison_userdata_fn_t)(const void *, const void *, void *); + +struct hash_ops; +struct hw_addr_data; +struct in_addr_data; +struct iovec_wrapper; +union in_addr_union; +union sockaddr_union; + +typedef enum JobMode JobMode; +typedef enum RuntimeScope RuntimeScope; +typedef enum TimestampStyle TimestampStyle; +typedef enum UnitActiveState UnitActiveState; +typedef enum UnitDependency UnitDependency; + +typedef struct Hashmap Hashmap; +typedef struct HashmapBase HashmapBase; +typedef struct IteratedCache IteratedCache; +typedef struct Iterator Iterator; +typedef struct OrderedHashmap OrderedHashmap; +typedef struct OrderedSet OrderedSet; +typedef struct Set Set; + +typedef struct dual_timestamp dual_timestamp; +typedef struct triple_timestamp triple_timestamp; +typedef struct PidRef PidRef; +typedef struct Prioq Prioq; +typedef struct RateLimit RateLimit; +typedef struct SocketAddress SocketAddress; + +/* libsystemd/ and libsystemd-network/ forward declarations */ + +typedef void (*_sd_destroy_t)(void *userdata); + +typedef union sd_id128 sd_id128_t; + +typedef struct sd_event sd_event; +typedef struct sd_event_source sd_event_source; + +typedef int (*sd_event_handler_t)(sd_event_source *s, void *userdata); +typedef int (*sd_event_io_handler_t)(sd_event_source *s, int fd, uint32_t revents, void *userdata); +typedef int (*sd_event_time_handler_t)(sd_event_source *s, uint64_t usec, void *userdata); +typedef int (*sd_event_signal_handler_t)(sd_event_source *s, const struct signalfd_siginfo *si, void *userdata); +typedef int (*sd_event_inotify_handler_t)(sd_event_source *s, const struct inotify_event *event, void *userdata); +typedef _sd_destroy_t sd_event_destroy_t; + +enum ENUM_TYPE_S64(sd_json_format_flags_t); +enum ENUM_TYPE_S64(sd_json_dispatch_flags_t); +enum ENUM_TYPE_S64(sd_json_variant_type_t); +enum ENUM_TYPE_S64(sd_json_parse_flags_t); + +typedef enum sd_json_format_flags_t sd_json_format_flags_t; +typedef enum sd_json_dispatch_flags_t sd_json_dispatch_flags_t; +typedef enum sd_json_variant_type_t sd_json_variant_type_t; +typedef enum sd_json_parse_flags_t sd_json_parse_flags_t; + +typedef struct sd_json_variant sd_json_variant; + +typedef struct sd_bus sd_bus; +typedef struct sd_bus_error sd_bus_error; +typedef struct sd_bus_error_map sd_bus_error_map; +typedef struct sd_bus_message sd_bus_message; +typedef struct sd_bus_slot sd_bus_slot; +typedef struct sd_bus_creds sd_bus_creds; +typedef struct sd_bus_track sd_bus_track; +typedef struct sd_bus_vtable sd_bus_vtable; + +typedef int (*sd_bus_message_handler_t)(sd_bus_message *m, void *userdata, sd_bus_error *ret_error); +typedef int (*sd_bus_property_get_t)(sd_bus *bus, const char *path, const char *interface, const char *property, sd_bus_message *reply, void *userdata, sd_bus_error *ret_error); +typedef int (*sd_bus_property_set_t)(sd_bus *bus, const char *path, const char *interface, const char *property, sd_bus_message *value, void *userdata, sd_bus_error *ret_error); +typedef int (*sd_bus_object_find_t)(sd_bus *bus, const char *path, const char *interface, void *userdata, void **ret_found, sd_bus_error *ret_error); +typedef int (*sd_bus_node_enumerator_t)(sd_bus *bus, const char *prefix, void *userdata, char ***ret_nodes, sd_bus_error *ret_error); +typedef int (*sd_bus_track_handler_t)(sd_bus_track *track, void *userdata); +typedef _sd_destroy_t sd_bus_destroy_t; + +enum ENUM_TYPE_S64(sd_device_action_t); + +typedef enum sd_device_action_t sd_device_action_t; + +typedef struct sd_device sd_device; +typedef struct sd_device_enumerator sd_device_enumerator; +typedef struct sd_device_monitor sd_device_monitor; + +typedef struct sd_netlink sd_netlink; +typedef struct sd_netlink_message sd_netlink_message; +typedef struct sd_netlink_slot sd_netlink_slot; + +typedef int (*sd_netlink_message_handler_t)(sd_netlink *nl, sd_netlink_message *m, void *userdata); +typedef _sd_destroy_t sd_netlink_destroy_t; + +typedef struct sd_network_monitor sd_network_monitor; + +enum ENUM_TYPE_S64(sd_dhcp_lease_server_type_t); +enum ENUM_TYPE_S64(sd_lldp_rx_event_t); +enum ENUM_TYPE_S64(sd_lldp_multicast_mode_t); +enum ENUM_TYPE_S64(sd_ndisc_event_t); + +typedef enum sd_dhcp_lease_server_type_t sd_dhcp_lease_server_type_t; +typedef enum sd_lldp_rx_event_t sd_lldp_rx_event_t; +typedef enum sd_lldp_multicast_mode_t sd_lldp_multicast_mode_t; +typedef enum sd_ndisc_event_t sd_ndisc_event_t; + +typedef struct sd_ipv4ll sd_ipv4ll; +typedef struct sd_dhcp_client sd_dhcp_client; +typedef struct sd_dhcp_lease sd_dhcp_lease; +typedef struct sd_dhcp_route sd_dhcp_route; +typedef struct sd_dns_resolver sd_dns_resolver; +typedef struct sd_dhcp_server sd_dhcp_server; +typedef struct sd_ndisc sd_ndisc; +typedef struct sd_radv sd_radv; +typedef struct sd_dhcp6_client sd_dhcp6_client; +typedef struct sd_dhcp6_lease sd_dhcp6_lease; +typedef struct sd_lldp_tx sd_lldp_tx; +typedef struct sd_lldp_rx sd_lldp_rx; +typedef struct sd_lldp_neighbor sd_lldp_neighbor; + +typedef struct ICMP6Packet ICMP6Packet; + +enum ENUM_TYPE_S64(sd_varlink_method_flags_t); +enum ENUM_TYPE_S64(sd_varlink_interface_flags_t); +enum ENUM_TYPE_S64(sd_varlink_symbol_type_t); +enum ENUM_TYPE_S64(sd_varlink_field_type_t); +enum ENUM_TYPE_S64(sd_varlink_field_direction_t); +enum ENUM_TYPE_S64(sd_varlink_field_flags_t); +enum ENUM_TYPE_S64(sd_varlink_idl_format_flags_t); +enum ENUM_TYPE_S64(sd_varlink_reply_flags_t); +enum ENUM_TYPE_S64(sd_varlink_server_flags_t); +enum ENUM_TYPE_S64(sd_varlink_invocation_flags_t); + +typedef enum sd_varlink_method_flags_t sd_varlink_method_flags_t; +typedef enum sd_varlink_interface_flags_t sd_varlink_interface_flags_t; +typedef enum sd_varlink_symbol_type_t sd_varlink_symbol_type_t; +typedef enum sd_varlink_field_type_t sd_varlink_field_type_t; +typedef enum sd_varlink_field_direction_t sd_varlink_field_direction_t; +typedef enum sd_varlink_field_flags_t sd_varlink_field_flags_t; +typedef enum sd_varlink_idl_format_flags_t sd_varlink_idl_format_flags_t; +typedef enum sd_varlink_reply_flags_t sd_varlink_reply_flags_t; +typedef enum sd_varlink_server_flags_t sd_varlink_server_flags_t; +typedef enum sd_varlink_invocation_flags_t sd_varlink_invocation_flags_t; + +typedef struct sd_varlink sd_varlink; +typedef struct sd_varlink_server sd_varlink_server; +typedef struct sd_varlink_field sd_varlink_field; +typedef struct sd_varlink_symbol sd_varlink_symbol; +typedef struct sd_varlink_interface sd_varlink_interface; + +typedef struct sd_journal sd_journal; + +typedef struct sd_resolve sd_resolve; +typedef struct sd_resolve_query sd_resolve_query; + +typedef struct sd_hwdb sd_hwdb; + +/* shared/ forward declarations */ + +struct local_address; +struct in_addr_prefix; + +typedef enum AskPasswordFlags AskPasswordFlags; +typedef enum BootEntryTokenType BootEntryTokenType; +typedef enum BusPrintPropertyFlags BusPrintPropertyFlags; +typedef enum BusTransport BusTransport; +typedef enum CatFlags CatFlags; +typedef enum CertificateSourceType CertificateSourceType; +typedef enum DnsCacheMode DnsCacheMode; +typedef enum DnsOverTlsMode DnsOverTlsMode; +typedef enum DnssecMode DnssecMode; +typedef enum Fido2EnrollFlags Fido2EnrollFlags; +typedef enum KeySourceType KeySourceType; +typedef enum MountInNamespaceFlags MountInNamespaceFlags; +typedef enum NamePolicy NamePolicy; +typedef enum OutputMode OutputMode; +typedef enum PagerFlags PagerFlags; +typedef enum PatternCompileCase PatternCompileCase; +typedef enum ResolveSupport ResolveSupport; +typedef enum TPM2Flags TPM2Flags; +typedef enum UnitFileFlags UnitFileFlags; +typedef enum UnitFilePresetMode UnitFilePresetMode; +typedef enum UnitFileState UnitFileState; +typedef enum UserRecordLoadFlags UserRecordLoadFlags; +typedef enum UserStorage UserStorage; + +typedef struct Bitmap Bitmap; +typedef struct BPFProgram BPFProgram; +typedef struct CalendarSpec CalendarSpec; +typedef struct Condition Condition; +typedef struct ConfigSection ConfigSection; +typedef struct ConfigTableItem ConfigTableItem; +typedef struct CPUSet CPUSet; +typedef struct FDSet FDSet; +typedef struct Fido2HmacSalt Fido2HmacSalt; +typedef struct FirewallContext FirewallContext; +typedef struct GroupRecord GroupRecord; +typedef struct Image Image; +typedef struct ImagePolicy ImagePolicy; +typedef struct LookupPaths LookupPaths; +typedef struct LoopDevice LoopDevice; +typedef struct MountOptions MountOptions; +typedef struct OpenFile OpenFile; +typedef struct Pkcs11EncryptedKey Pkcs11EncryptedKey; +typedef struct Table Table; +typedef struct Tpm2PCRValue Tpm2PCRValue; +typedef struct UnitInfo UnitInfo; +typedef struct UserRecord UserRecord; +typedef struct VeritySettings VeritySettings; + +/* Constants */ + +/* We duplicate various commonly used constants here so we can keep most static inline functions without + * having to include the full header that provides these constants. */ + +#define AT_FDCWD -100 +#define AT_EMPTY_PATH 0x1000 +#define AT_SYMLINK_FOLLOW 0x400 +#define AT_SYMLINK_NOFOLLOW 0x100 + +#define MODE_INVALID ((mode_t) -1) + +#define UID_INVALID ((uid_t) -1) +#define GID_INVALID ((gid_t) -1) + +#define USEC_INFINITY ((usec_t) UINT64_MAX) +#define NSEC_INFINITY ((nsec_t) UINT64_MAX) + +/* MAX_ERRNO is defined as 4095 in linux/err.h. We use the same value here. */ +#define ERRNO_MAX 4095 diff --git a/src/basic/memory-util.h b/src/basic/memory-util.h index 7a86cac5bc9..523486db1ff 100644 --- a/src/basic/memory-util.h +++ b/src/basic/memory-util.h @@ -8,6 +8,7 @@ #include #include +#include "cleanup-util.h" #include "macro.h" #include "memory-util-fundamental.h" @@ -111,56 +112,3 @@ static inline void erase_char(char *p) { /* Makes a copy of the buffer with reversed order of bytes */ void* memdup_reverse(const void *mem, size_t size); - -#define _DEFINE_TRIVIAL_REF_FUNC(type, name, scope) \ - scope type *name##_ref(type *p) { \ - if (!p) \ - return NULL; \ - \ - /* For type check. */ \ - unsigned *q = &p->n_ref; \ - assert(*q > 0); \ - assert_se(*q < UINT_MAX); \ - \ - (*q)++; \ - return p; \ - } - -#define _DEFINE_TRIVIAL_UNREF_FUNC(type, name, free_func, scope) \ - scope type *name##_unref(type *p) { \ - if (!p) \ - return NULL; \ - \ - assert(p->n_ref > 0); \ - p->n_ref--; \ - if (p->n_ref > 0) \ - return NULL; \ - \ - return free_func(p); \ - } - -#define DEFINE_TRIVIAL_REF_FUNC(type, name) \ - _DEFINE_TRIVIAL_REF_FUNC(type, name,) -#define DEFINE_PRIVATE_TRIVIAL_REF_FUNC(type, name) \ - _DEFINE_TRIVIAL_REF_FUNC(type, name, static) -#define DEFINE_PUBLIC_TRIVIAL_REF_FUNC(type, name) \ - _DEFINE_TRIVIAL_REF_FUNC(type, name, _public_) - -#define DEFINE_TRIVIAL_UNREF_FUNC(type, name, free_func) \ - _DEFINE_TRIVIAL_UNREF_FUNC(type, name, free_func,) -#define DEFINE_PRIVATE_TRIVIAL_UNREF_FUNC(type, name, free_func) \ - _DEFINE_TRIVIAL_UNREF_FUNC(type, name, free_func, static) -#define DEFINE_PUBLIC_TRIVIAL_UNREF_FUNC(type, name, free_func) \ - _DEFINE_TRIVIAL_UNREF_FUNC(type, name, free_func, _public_) - -#define DEFINE_TRIVIAL_REF_UNREF_FUNC(type, name, free_func) \ - DEFINE_TRIVIAL_REF_FUNC(type, name); \ - DEFINE_TRIVIAL_UNREF_FUNC(type, name, free_func); - -#define DEFINE_PRIVATE_TRIVIAL_REF_UNREF_FUNC(type, name, free_func) \ - DEFINE_PRIVATE_TRIVIAL_REF_FUNC(type, name); \ - DEFINE_PRIVATE_TRIVIAL_UNREF_FUNC(type, name, free_func); - -#define DEFINE_PUBLIC_TRIVIAL_REF_UNREF_FUNC(type, name, free_func) \ - DEFINE_PUBLIC_TRIVIAL_REF_FUNC(type, name); \ - DEFINE_PUBLIC_TRIVIAL_UNREF_FUNC(type, name, free_func); diff --git a/src/fundamental/cleanup-fundamental.h b/src/fundamental/cleanup-fundamental.h new file mode 100644 index 00000000000..244699105a6 --- /dev/null +++ b/src/fundamental/cleanup-fundamental.h @@ -0,0 +1,75 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +#pragma once + +#include "assert-fundamental.h" + +/* A wrapper for 'func' to return void. + * Only useful when a void-returning function is required by some API. */ +#define DEFINE_TRIVIAL_DESTRUCTOR(name, type, func) \ + static inline void name(type *p) { \ + func(p); \ + } + +/* When func() returns the void value (NULL, -1, …) of the appropriate type */ +#define DEFINE_TRIVIAL_CLEANUP_FUNC(type, func) \ + static inline void func##p(type *p) { \ + if (*p) \ + *p = func(*p); \ + } + +/* When func() doesn't return the appropriate type, set variable to empty afterwards. + * The func() may be provided by a dynamically loaded shared library, hence add an assertion. */ +#define DEFINE_TRIVIAL_CLEANUP_FUNC_FULL(type, func, empty) \ + static inline void func##p(type *p) { \ + if (*p != (empty)) { \ + DISABLE_WARNING_ADDRESS; \ + assert(func); \ + REENABLE_WARNING; \ + func(*p); \ + *p = (empty); \ + } \ + } + +/* When func() doesn't return the appropriate type, and is also a macro, set variable to empty afterwards. */ +#define DEFINE_TRIVIAL_CLEANUP_FUNC_FULL_MACRO(type, func, empty) \ + static inline void func##p(type *p) { \ + if (*p != (empty)) { \ + func(*p); \ + *p = (empty); \ + } \ + } + +typedef void (*free_array_func_t)(void *p, size_t n); + +/* An automatic _cleanup_-like logic for destroy arrays (i.e. pointers + size) when leaving scope */ +typedef struct ArrayCleanup { + void **parray; + size_t *pn; + free_array_func_t pfunc; +} ArrayCleanup; + +static inline void array_cleanup(const ArrayCleanup *c) { + assert(c); + assert(!c->parray == !c->pn); + + if (!c->parray) + return; + + if (*c->parray) { + assert(c->pfunc); + c->pfunc(*c->parray, *c->pn); + *c->parray = NULL; + } + + *c->pn = 0; +} + +#define CLEANUP_ARRAY(array, n, func) \ + _cleanup_(array_cleanup) _unused_ const ArrayCleanup CONCATENATE(_cleanup_array_, UNIQ) = { \ + .parray = (void**) &(array), \ + .pn = &(n), \ + .pfunc = (free_array_func_t) ({ \ + void (*_f)(typeof(array[0]) *a, size_t b) = func; \ + _f; \ + }), \ + } diff --git a/src/fundamental/macro-fundamental.h b/src/fundamental/macro-fundamental.h index 54b3e6a6510..01af1e29772 100644 --- a/src/fundamental/macro-fundamental.h +++ b/src/fundamental/macro-fundamental.h @@ -465,3 +465,10 @@ assert_cc(sizeof(dummy_t) == 0); assert_cc(STRLEN(__FILE__) > STRLEN(RELATIVE_SOURCE_PATH) + 1); #define PROJECT_FILE (&__FILE__[STRLEN(RELATIVE_SOURCE_PATH) + 1]) + +/* In GCC 14 (C23) we can force enums to have the right types, and not solely rely on language extensions anymore */ +#if __GNUC__ >= 14 || __STDC_VERSION__ >= 202311L +# define ENUM_TYPE_S64(id) id : int64_t +#else +# define ENUM_TYPE_S64(id) id +#endif diff --git a/src/fundamental/memory-util-fundamental.h b/src/fundamental/memory-util-fundamental.h index 4b50714f5e1..c2a99a20397 100644 --- a/src/fundamental/memory-util-fundamental.h +++ b/src/fundamental/memory-util-fundamental.h @@ -10,6 +10,7 @@ #endif #include "assert-fundamental.h" +#include "cleanup-fundamental.h" #include "macro-fundamental.h" #define memzero(x, l) \ @@ -72,78 +73,6 @@ static inline void erase_varp(struct VarEraser *e) { .size = (sz), \ } -typedef void (*free_array_func_t)(void *p, size_t n); - -/* An automatic _cleanup_-like logic for destroy arrays (i.e. pointers + size) when leaving scope */ -typedef struct ArrayCleanup { - void **parray; - size_t *pn; - free_array_func_t pfunc; -} ArrayCleanup; - -static inline void array_cleanup(const ArrayCleanup *c) { - assert(c); - - assert(!c->parray == !c->pn); - - if (!c->parray) - return; - - if (*c->parray) { - assert(c->pfunc); - c->pfunc(*c->parray, *c->pn); - *c->parray = NULL; - } - - *c->pn = 0; -} - -#define CLEANUP_ARRAY(array, n, func) \ - _cleanup_(array_cleanup) _unused_ const ArrayCleanup CONCATENATE(_cleanup_array_, UNIQ) = { \ - .parray = (void**) &(array), \ - .pn = &(n), \ - .pfunc = (free_array_func_t) ({ \ - void (*_f)(typeof(array[0]) *a, size_t b) = func; \ - _f; \ - }), \ - } - -/* A wrapper for 'func' to return void. - * Only useful when a void-returning function is required by some API. */ -#define DEFINE_TRIVIAL_DESTRUCTOR(name, type, func) \ - static inline void name(type *p) { \ - func(p); \ - } - -/* When func() returns the void value (NULL, -1, …) of the appropriate type */ -#define DEFINE_TRIVIAL_CLEANUP_FUNC(type, func) \ - static inline void func##p(type *p) { \ - if (*p) \ - *p = func(*p); \ - } - -/* When func() doesn't return the appropriate type, set variable to empty afterwards. - * The func() may be provided by a dynamically loaded shared library, hence add an assertion. */ -#define DEFINE_TRIVIAL_CLEANUP_FUNC_FULL(type, func, empty) \ - static inline void func##p(type *p) { \ - if (*p != (empty)) { \ - DISABLE_WARNING_ADDRESS; \ - assert(func); \ - REENABLE_WARNING; \ - func(*p); \ - *p = (empty); \ - } \ - } - -/* When func() doesn't return the appropriate type, and is also a macro, set variable to empty afterwards. */ -#define DEFINE_TRIVIAL_CLEANUP_FUNC_FULL_MACRO(type, func, empty) \ - static inline void func##p(type *p) { \ - if (*p != (empty)) { \ - func(*p); \ - *p = (empty); \ - } \ - } - static inline size_t ALIGN_TO(size_t l, size_t ali) { assert(ISPOWEROF2(ali)); -- 2.47.3