git/wrapper.h

162 lines
5.1 KiB
C
Raw Normal View History

#ifndef WRAPPER_H
#define WRAPPER_H
char *xstrdup(const char *str);
void *xmalloc(size_t size);
void *xmallocz(size_t size);
void *xmallocz_gently(size_t size);
void *xmemdupz(const void *data, size_t len);
char *xstrndup(const char *str, size_t len);
void *xrealloc(void *ptr, size_t size);
void *xcalloc(size_t nmemb, size_t size);
void xsetenv(const char *name, const char *value, int overwrite);
void *xmmap(void *start, size_t length, int prot, int flags, int fd, off_t offset);
const char *mmap_os_err(void);
void *xmmap_gently(void *start, size_t length, int prot, int flags, int fd, off_t offset);
int xopen(const char *path, int flags, ...);
ssize_t xread(int fd, void *buf, size_t len);
ssize_t xwrite(int fd, const void *buf, size_t len);
ssize_t xpread(int fd, void *buf, size_t len, off_t offset);
int xdup(int fd);
FILE *xfopen(const char *path, const char *mode);
FILE *xfdopen(int fd, const char *mode);
int xmkstemp(char *temp_filename);
int xmkstemp_mode(char *temp_filename, int mode);
char *xgetcwd(void);
FILE *fopen_for_writing(const char *path);
FILE *fopen_or_warn(const char *path, const char *mode);
/*
* Like strncmp, but only return zero if s is NUL-terminated and exactly len
* characters long. If it is not, consider it greater than t.
*/
int xstrncmpz(const char *s, const char *t, size_t len);
__attribute__((format (printf, 3, 4)))
int xsnprintf(char *dst, size_t max, const char *fmt, ...);
int xgethostname(char *buf, size_t len);
/* set default permissions by passing mode arguments to open(2) */
int git_mkstemps_mode(char *pattern, int suffix_len, int mode);
int git_mkstemp_mode(char *pattern, int mode);
ssize_t read_in_full(int fd, void *buf, size_t count);
ssize_t write_in_full(int fd, const void *buf, size_t count);
ssize_t pread_in_full(int fd, void *buf, size_t count, off_t offset);
static inline ssize_t write_str_in_full(int fd, const char *str)
{
return write_in_full(fd, str, strlen(str));
}
/**
* Open (and truncate) the file at path, write the contents of buf to it,
* and close it. Dies if any errors are encountered.
*/
void write_file_buf(const char *path, const char *buf, size_t len);
/**
* Like write_file_buf(), but format the contents into a buffer first.
* Additionally, write_file() will append a newline if one is not already
* present, making it convenient to write text files:
*
* write_file(path, "counter: %d", ctr);
*/
__attribute__((format (printf, 2, 3)))
void write_file(const char *path, const char *fmt, ...);
/* Return 1 if the file is empty or does not exists, 0 otherwise. */
int is_empty_or_missing_file(const char *filename);
enum fsync_action {
FSYNC_WRITEOUT_ONLY,
FSYNC_HARDWARE_FLUSH
};
/*
* Issues an fsync against the specified file according to the specified mode.
*
* FSYNC_WRITEOUT_ONLY attempts to use interfaces available on some operating
* systems to flush the OS cache without issuing a flush command to the storage
* controller. If those interfaces are unavailable, the function fails with
* ENOSYS.
*
* FSYNC_HARDWARE_FLUSH does an OS writeout and hardware flush to ensure that
* changes are durable. It is not expected to fail.
*/
int git_fsync(int fd, enum fsync_action action);
/*
* Preserves errno, prints a message, but gives no warning for ENOENT.
* Returns 0 on success, which includes trying to unlink an object that does
* not exist.
*/
int unlink_or_warn(const char *path);
/*
* Tries to unlink file. Returns 0 if unlink succeeded
* or the file already didn't exist. Returns -1 and
* appends a message to err suitable for
* 'error("%s", err->buf)' on error.
*/
int unlink_or_msg(const char *file, struct strbuf *err);
/*
* Preserves errno, prints a message, but gives no warning for ENOENT.
* Returns 0 on success, which includes trying to remove a directory that does
* not exist.
*/
int rmdir_or_warn(const char *path);
/*
* Call access(2), but warn for any error except "missing file"
* (ENOENT or ENOTDIR).
*/
#define ACCESS_EACCES_OK (1U << 0)
int access_or_warn(const char *path, int mode, unsigned flag);
int access_or_die(const char *path, int mode, unsigned flag);
/* Warn on an inaccessible file if errno indicates this is an error */
int warn_on_fopen_errors(const char *path);
/*
* Open with O_NOFOLLOW, or equivalent. Note that the fallback equivalent
* may be racy. Do not use this as protection against an attacker who can
* simultaneously create paths.
*/
int open_nofollow(const char *path, int flags);
void sleep_millisec(int millisec);
/*
* Generate len bytes from the system cryptographically secure PRNG.
* Returns 0 on success and -1 on error, setting errno. The inability to
* satisfy the full request is an error.
*/
int csprng_bytes(void *buf, size_t len);
maintenance: add get_random_minute() When we initially created background maintenance -- with its hourly, daily, and weekly schedules -- we considered the effects of all clients launching fetches to the server every hour on the hour. The worry of DDoSing server hosts was noted, but left as something we would consider for a future update. As background maintenance has gained more adoption over the past three years, our worries about DDoSing the big Git hosts has been unfounded. Those systems, especially those serving public repositories, are already resilient to thundering herds of much smaller scale. However, sometimes organizations spin up specific custom server infrastructure either in addition to or on top of their Git host. Some of these technologies are built for a different range of scale, and can hit concurrency limits sooner. Organizations with such custom infrastructures are more likely to recommend tools like `scalar` which furthers their adoption of background maintenance. To help solve for this, create get_random_minute() as a method to help Git select a random minute when creating schedules in the future. The integrations with this method do not yet exist, but will follow in future changes. To avoid multiple sources of randomness in the Git codebase, create a new helper function, git_rand(), that returns a random uint32_t. This is similar to how rand() returns a random nonnegative value, except it is based on csprng_bytes() which is cryptographic and will return values larger than RAND_MAX. One thing that is important for testability is that we notice when we are under a test scenario and return a predictable result. The schedules themselves are not checked for this value, but at least one launchctl test checks that we do not unnecessarily reboot the schedule if it has not changed from a previous version. Signed-off-by: Derrick Stolee <derrickstolee@github.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2023-08-11 04:39:40 +08:00
/*
* Returns a random uint32_t, uniformly distributed across all possible
* values.
*/
uint32_t git_rand(void);
wrapper: introduce `log2u()` We have an implementation of a function that computes the log2 for an integer. While we could instead use log2(3P), that involves floating point numbers and is thus needlessly complex and inefficient. We're about to add a second caller that wants to compute log2 for a `size_t`. Let's thus move the function into "wrapper.h" such that it becomes generally available. While at it, tweak the implementation a bit: - The parameter is converted from `int` to `uintmax_t`. This conversion is safe to do in "bisect.c" because we already check that the argument is positive. - The return value is an `unsigned`. It cannot ever be negative, so it is pointless for it to be a signed integer. - Loop until `!n` instead of requiring that `n > 1` and then subtract 1 from the result and add a special case for `!sz`. This helps compilers to generate more efficient code. Compilers recognize the pattern of this function and optimize accordingly. On GCC 14.2 x86_64: log2u(unsigned long): test rdi, rdi je .L3 bsr rax, rdi ret .L3: mov eax, -1 ret Clang 18.1 does not yet recognize the pattern, but starts to do so on Clang trunk x86_64. The code isn't quite as efficient as the one generated by GCC, but still manages to optimize away the loop: log2u(unsigned long): test rdi, rdi je .LBB0_1 shr rdi bsr rcx, rdi mov eax, 127 cmovne rax, rcx xor eax, -64 add eax, 65 ret .LBB0_1: mov eax, -1 ret The pattern is also recognized on other platforms like ARM64 GCC 14.2.0, where we end up using `clz`: log2u(unsigned long): clz x2, x0 cmp x0, 0 mov w1, 63 sub w0, w1, w2 csinv w0, w0, wzr, ne ret Note that we have a similar function `fastlog2()` in the reftable code. As that codebase is separate from the Git codebase we do not adapt it to use the new function. Signed-off-by: Patrick Steinhardt <ps@pks.im> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2024-09-04 16:53:00 +08:00
/* Provide log2 of the given `size_t`. */
static inline unsigned log2u(uintmax_t sz)
{
unsigned l = 0;
/*
* Technically this isn't required, but it helps the compiler optimize
* this to a `bsr` instruction.
*/
if (!sz)
return 0;
for (; sz; sz >>= 1)
l++;
return l - 1;
}
#endif /* WRAPPER_H */