2023-03-21 14:26:01 +08:00
|
|
|
#ifndef WRAPPER_H
|
|
|
|
#define WRAPPER_H
|
|
|
|
|
2023-07-06 01:09:20 +08:00
|
|
|
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);
|
|
|
|
|
2023-03-21 14:26:01 +08:00
|
|
|
/* 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);
|
|
|
|
|
2023-07-06 01:09:20 +08:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2023-03-21 14:26:01 +08:00
|
|
|
#endif /* WRAPPER_H */
|