26typedef enum : uint8_t {
30typedef enum : uint16_t {
56 if ((ctx ==
nullptr) || (out_written ==
nullptr)) {
59 const int fd = *(
const int*)ctx;
61 const ssize_t result =
write(fd, data, length);
63 *out_written = (size_t)result;
76 static int s_output_fd = STDOUT_FILENO;
77 static int s_error_fd = STDERR_FILENO;
78 if (output !=
nullptr) {
81 if (error !=
nullptr) {
111 if ((source ==
nullptr) || (dst ==
nullptr) || (out_read ==
nullptr) || (offset > source->
size)) {
114 struct stat info = {};
115 if ((fstat(source->
fd, &info) != 0) || (info.st_size < 0) ||
116 ((uint64_t)info.st_size != source->
size)) {
120 const ssize_t result = pread(source->
fd, dst, capacity, (off_t)offset);
122 *out_read = (size_t)result;
125 if (errno != EINTR) {
135 if ((path ==
nullptr) || (binding ==
nullptr) || (source ==
nullptr)) {
143 struct stat info = {};
144 if ((fstat(fd, &info) != 0) || !S_ISREG(info.st_mode) || (info.st_size < 0)) {
155 if ((binding ==
nullptr) || (binding->
fd < 0)) {
158 const int result = close(binding->
fd);
185 const char* slash =
strrchr(path,
'/');
186 *base = (slash ==
nullptr) ? path : slash + 1;
187 const size_t parent_length = (slash ==
nullptr) ? 1U : (size_t)(slash - path);
188 if ((**base ==
'\0') || (parent_length >= parent_capacity)) {
191 size_t output_length = parent_length;
192 if (slash ==
nullptr) {
194 }
else if (parent_length == 0U) {
198 memcpy(parent, path, parent_length);
200 parent[output_length] =
'\0';
230 const int length = snprintf(binding->
temporary,
232 "%s/.%s.cache-bench.%ld.%u",
236 (
unsigned int)attempt);
237 if ((length < 0) || ((
size_t)length >=
sizeof(binding->
temporary))) {
243 if (binding->
fd >= 0) {
247 if (errno != EEXIST) {
256 if ((binding ==
nullptr) || (sink ==
nullptr)) {
260 if (path ==
nullptr) {
261 binding->
fd = STDOUT_FILENO;
265 const size_t path_length =
strlen(path);
271 const char* base =
nullptr;
277 if (binding->
dir_fd < 0) {
291 if ((binding ==
nullptr) || (binding->
fd < 0)) {
297 bool ok = fsync(binding->
fd) == 0;
298 ok = (close(binding->
fd) == 0) && ok;
304 ok = fsync(binding->
dir_fd) == 0;
306 const bool dir_ok = close(binding->
dir_fd) == 0;
317 if (binding ==
nullptr) {
320 if (binding->
fd >= 0) {
321 (void)close(binding->
fd);
327 if (binding->
dir_fd >= 0) {
328 (void)close(binding->
dir_fd);
357 size_t complete = 0U;
358 uint32_t attempts = 0U;
359 while (complete < length) {
360 const ssize_t result =
363 &((
const uint8_t*)data)[complete],
365 (off_t)(offset + complete))
366 : pread(fd, &((uint8_t*)data)[complete], length - complete, (off_t)(offset + complete));
368 complete += (size_t)result;
429 if ((binding ==
nullptr) || (scratch ==
nullptr)) {
432 char path[] =
"/tmp/ra8-cache-bench.XXXXXX";
433 binding->
fd = mkstemp(path);
434 if (binding->
fd < 0) {
437 if (unlink(path) != 0) {
438 (void)close(binding->
fd);
449 if ((binding ==
nullptr) || (binding->
fd < 0)) {
452 const int result = close(binding->
fd);
cb_io_status_t cb_host_source_open(const char *path, cb_host_source_t *binding, cb_source_t *source)
Open a captured-trace path and publish its source seam.
static cb_io_status_t internal_split_path(const char *path, char *parent, size_t parent_capacity, const char **base)
Split an output path into parent bytes and a borrowed leaf pointer.
@ k_cb_host_retry_limit
Bounded EINTR/temp-name retry count.
@ k_cb_host_create_mode
Owner-only scratch/output permissions.
cb_io_status_t cb_host_scratch_close(cb_host_scratch_t *binding)
Close the scratch transaction.
cb_io_status_t cb_host_scratch_open(cb_host_scratch_t *binding, cb_scratch_t *scratch)
Create an unlinked raw-descriptor scratch transaction.
void cb_host_output_abort(cb_host_output_t *binding)
Abandon a temporary sibling while preserving the destination.
static cb_io_status_t internal_scratch_write(void *ctx, uint64_t offset, void *data, size_t length)
Write an exact region through a bound host scratch transaction.
void cb_host_standard_sinks(cb_sink_t *output, cb_sink_t *error)
Bind the process standard-output and standard-error descriptor sinks.
cb_io_status_t cb_host_output_open(const char *path, cb_host_output_t *binding, cb_sink_t *sink)
Open a sibling output transaction, or bind descriptor one for NULL.
static cb_io_status_t internal_sink_write(void *ctx, const uint8_t *data, size_t length, size_t *out_written)
Write one bounded fragment to a borrowed host descriptor.
cb_io_status_t cb_host_output_commit(cb_host_output_t *binding)
Flush and atomically publish a transactional output.
cb_io_status_t cb_host_source_close(cb_host_source_t *binding)
Close a source binding.
static cb_io_status_t internal_scratch_read(void *ctx, uint64_t offset, void *data, size_t length)
Read an exact region through a bound host scratch transaction.
static cb_io_status_t internal_source_read(void *ctx, uint64_t offset, uint8_t *dst, size_t capacity, size_t *out_read)
Read a bounded fragment from a snapshotted host source.
static cb_io_status_t internal_create_temp_exclusive(cb_host_output_t *binding, const char *parent, const char *base)
Create a uniquely-named exclusive temp file beside the destination.
static cb_io_status_t internal_scratch_transfer(int fd, bool write_mode, uint64_t offset, void *data, size_t length)
Complete one positional scratch transfer with bounded interruption retries.
POSIX raw-descriptor composition bindings for cache_bench.
@ k_cb_host_path_capacity
Bounded host path copy.
cb_io_status_t
Status returned by tool-local injected I/O callbacks.
@ k_cb_io_ok
Operation completed.
@ k_cb_io_fault
Backing device or sink failed.
@ k_cb_io_mutated
A replay source changed between passes.
@ k_cb_io_capacity
Caller-owned storage was too small.
#define O_DIRECTORY
No-op directory-open fallback for hosts lacking the flag.
#define O_NOFOLLOW
Zero fallback paired with explicit no-follow metadata validation.
#define O_CLOEXEC
Zero fallback when the host lacks close-on-exec open flags.
Annotation-attribute framework macros for ra8-firmware.
#define RA8_INTERNAL
Marker that a function is intended to be static (file-local).
size_t strlen(const char *s)
Calculate string length.
void * memcpy(void *dst, const void *src, size_t n)
Copy memory area between non-overlapping regions.
char * strrchr(const char *s, int c)
Locate last occurrence of character in string.
Output transaction or borrowed standard descriptor.
bool transactional
True when temporary sibling is live.
int dir_fd
Parent descriptor for durable rename.
char temporary[k_cb_host_path_capacity]
Sibling temporary path.
int fd
Writable descriptor.
char destination[k_cb_host_path_capacity]
Final path.
Unlinked raw-descriptor scratch binding.
int fd
Open temporary descriptor.
Borrowed raw descriptor source binding.
int fd
Open read-only descriptor.
uint64_t size
Size snapshot.
Injected bounded random-access scratch transaction.
Immutable injected byte source with a snapshotted length.