mirror of
https://github.com/morgan9e/systemd
synced 2026-04-16 01:16:10 +09:00
We recently started making more use of malloc_usable_size() and rely on it (see the string_erase() story). Given that we don't really support sytems where malloc_usable_size() cannot be trusted beyond statistics anyway, let's go fully in and rework GREEDY_REALLOC() on top of it: instead of passing around and maintaining the currenly allocated size everywhere, let's just derive it automatically from malloc_usable_size(). I am mostly after this for the simplicity this brings. It also brings minor efficiency improvements I guess, but things become so much nicer to look at if we can avoid these allocation size variables everywhere. Note that the malloc_usable_size() man page says relying on it wasn't "good programming practice", but I think it does this for reasons that don't apply here: the greedy realloc logic specifically doesn't rely on the returned extra size, beyond the fact that it is equal or larger than what was requested. (This commit was supposed to be a quick patch btw, but apparently we use the greedy realloc stuff quite a bit across the codebase, so this ends up touching *a*lot* of code.)
99 lines
3.4 KiB
C
99 lines
3.4 KiB
C
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
|
#pragma once
|
|
|
|
#include <poll.h>
|
|
#include <stdbool.h>
|
|
#include <stddef.h>
|
|
#include <stdint.h>
|
|
#include <sys/types.h>
|
|
#include <sys/uio.h>
|
|
|
|
#include "macro.h"
|
|
#include "time-util.h"
|
|
|
|
int flush_fd(int fd);
|
|
|
|
ssize_t loop_read(int fd, void *buf, size_t nbytes, bool do_poll);
|
|
int loop_read_exact(int fd, void *buf, size_t nbytes, bool do_poll);
|
|
int loop_write(int fd, const void *buf, size_t nbytes, bool do_poll);
|
|
|
|
int pipe_eof(int fd);
|
|
|
|
int ppoll_usec(struct pollfd *fds, size_t nfds, usec_t timeout);
|
|
int fd_wait_for_event(int fd, int event, usec_t timeout);
|
|
|
|
ssize_t sparse_write(int fd, const void *p, size_t sz, size_t run_length);
|
|
|
|
static inline size_t IOVEC_TOTAL_SIZE(const struct iovec *i, size_t n) {
|
|
size_t r = 0;
|
|
|
|
for (size_t j = 0; j < n; j++)
|
|
r += i[j].iov_len;
|
|
|
|
return r;
|
|
}
|
|
|
|
static inline bool IOVEC_INCREMENT(struct iovec *i, size_t n, size_t k) {
|
|
/* Returns true if there is nothing else to send (bytes written cover all of the iovec),
|
|
* false if there's still work to do. */
|
|
|
|
for (size_t j = 0; j < n; j++) {
|
|
size_t sub;
|
|
|
|
if (i[j].iov_len == 0)
|
|
continue;
|
|
if (k == 0)
|
|
return false;
|
|
|
|
sub = MIN(i[j].iov_len, k);
|
|
i[j].iov_len -= sub;
|
|
i[j].iov_base = (uint8_t*) i[j].iov_base + sub;
|
|
k -= sub;
|
|
}
|
|
|
|
assert(k == 0); /* Anything else would mean that we wrote more bytes than available,
|
|
* or the kernel reported writing more bytes than sent. */
|
|
return true;
|
|
}
|
|
|
|
static inline bool FILE_SIZE_VALID(uint64_t l) {
|
|
/* ftruncate() and friends take an unsigned file size, but actually cannot deal with file sizes larger than
|
|
* 2^63 since the kernel internally handles it as signed value. This call allows checking for this early. */
|
|
|
|
return (l >> 63) == 0;
|
|
}
|
|
|
|
static inline bool FILE_SIZE_VALID_OR_INFINITY(uint64_t l) {
|
|
|
|
/* Same as above, but allows one extra value: -1 as indication for infinity. */
|
|
|
|
if (l == UINT64_MAX)
|
|
return true;
|
|
|
|
return FILE_SIZE_VALID(l);
|
|
|
|
}
|
|
|
|
#define IOVEC_INIT(base, len) { .iov_base = (base), .iov_len = (len) }
|
|
#define IOVEC_MAKE(base, len) (struct iovec) IOVEC_INIT(base, len)
|
|
#define IOVEC_INIT_STRING(string) IOVEC_INIT((char*) string, strlen(string))
|
|
#define IOVEC_MAKE_STRING(string) (struct iovec) IOVEC_INIT_STRING(string)
|
|
|
|
char* set_iovec_string_field(struct iovec *iovec, size_t *n_iovec, const char *field, const char *value);
|
|
char* set_iovec_string_field_free(struct iovec *iovec, size_t *n_iovec, const char *field, char *value);
|
|
|
|
struct iovec_wrapper {
|
|
struct iovec *iovec;
|
|
size_t count;
|
|
};
|
|
|
|
struct iovec_wrapper *iovw_new(void);
|
|
struct iovec_wrapper *iovw_free(struct iovec_wrapper *iovw);
|
|
struct iovec_wrapper *iovw_free_free(struct iovec_wrapper *iovw);
|
|
void iovw_free_contents(struct iovec_wrapper *iovw, bool free_vectors);
|
|
int iovw_put(struct iovec_wrapper *iovw, void *data, size_t len);
|
|
int iovw_put_string_field(struct iovec_wrapper *iovw, const char *field, const char *value);
|
|
int iovw_put_string_field_free(struct iovec_wrapper *iovw, const char *field, char *value);
|
|
void iovw_rebase(struct iovec_wrapper *iovw, char *old, char *new);
|
|
size_t iovw_size(struct iovec_wrapper *iovw);
|