diff --git a/docs/CODING_STYLE.md b/docs/CODING_STYLE.md index efc9d2ae3e..82b3302953 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 7cf10ef4f3..ec5b1059a8 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 0000000000..2d58b6654a --- /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 0000000000..dda17ffcde --- /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 7a86cac5bc..523486db1f 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 0000000000..244699105a --- /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 54b3e6a651..01af1e2977 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 4b50714f5e..c2a99a2039 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));