Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 2 additions & 49 deletions examples/htool_console.c
Original file line number Diff line number Diff line change
Expand Up @@ -61,53 +61,6 @@ void restore_terminal(int fd, const struct termios* old_termios) {
tcsetattr(fd, TCSANOW, old_termios);
}

// Try to claim `dev`. If `dev` is already claimed, then try to claim later by
// waiting an exponentially backed off amount of time.
static int claim_device(struct libhoth_device* dev, uint32_t timeout_us) {
enum {
// The maximum time to sleep per attempt.
// Limited by `usleep()` to <1 second.
MAX_SINGLE_SLEEP_US = 1000 * 1000 - 1,
BACKOFF_FACTOR = 2,
INITIAL_WAIT_US = 10 * 1000,
};

uint32_t wait_us = INITIAL_WAIT_US;
uint32_t total_waiting_us = 0;

while (true) {
int status = dev->claim(dev);

if (status != LIBHOTH_ERR_INTERFACE_BUSY) {
// We either claimed the device or encountered an unexpected error. Let
// the caller know.
return status;
}

if (total_waiting_us >= timeout_us) {
// We've exhausted our waiting budget. We couldn't claim the device
// within the configured timeout.
return LIBHOTH_ERR_INTERFACE_BUSY;
}

usleep(wait_us);

if (total_waiting_us <= UINT32_MAX - wait_us) {
total_waiting_us += wait_us;
} else {
// Saturate at integer upper bound to prevent overflow.
total_waiting_us = UINT32_MAX;
}

if (wait_us <= MAX_SINGLE_SLEEP_US / BACKOFF_FACTOR) {
wait_us *= BACKOFF_FACTOR;
} else {
// Saturate at the `usleep()` max sleep bound.
wait_us = MAX_SINGLE_SLEEP_US;
}
}
}

int htool_console_run(struct libhoth_device* dev,
const struct libhoth_htool_console_opts* opts) {
printf("%sStarting Interactive Console\n", kAnsiRed);
Expand Down Expand Up @@ -164,12 +117,12 @@ int htool_console_run(struct libhoth_device* dev,
break;
}

dev->release(dev);
libhoth_release_device(dev);

// Give an opportunity for other clients to use the interface.
usleep(1000 * opts->yield_ms);

status = claim_device(dev, 1000 * 1000 * opts->claim_timeout_secs);
status = libhoth_claim_device(dev, 1000 * 1000 * opts->claim_timeout_secs);
if (status != LIBHOTH_OK) {
break;
}
Expand Down
54 changes: 54 additions & 0 deletions transports/libhoth_device.c
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,9 @@

#include "transports/libhoth_device.h"

#include <stdbool.h>
#include <stdlib.h>
#include <unistd.h>

#include "libhoth_device.h"

Expand Down Expand Up @@ -57,3 +59,55 @@ int libhoth_device_close(struct libhoth_device* dev) {
free(dev);
return status;
}

int libhoth_claim_device(struct libhoth_device* dev, uint32_t timeout_us) {
enum {
// The maximum time to sleep per attempt.
// Limited by `usleep()` to <1 second.
MAX_SINGLE_SLEEP_US = 1000 * 1000 - 1,
BACKOFF_FACTOR = 2,
INITIAL_WAIT_US = 10 * 1000,
};

uint32_t wait_us = INITIAL_WAIT_US;
uint32_t total_waiting_us = 0;

while (true) {
int status = dev->claim(dev);

if (status != LIBHOTH_ERR_INTERFACE_BUSY) {
// We either claimed the device or encountered an unexpected error. Let
// the caller know.
return status;
}

if (total_waiting_us >= timeout_us) {
// We've exhausted our waiting budget. We couldn't claim the device
// within the configured timeout.
return LIBHOTH_ERR_INTERFACE_BUSY;
}

usleep(wait_us);

if (total_waiting_us <= UINT32_MAX - wait_us) {
total_waiting_us += wait_us;
} else {
// Saturate at integer upper bound to prevent overflow.
total_waiting_us = UINT32_MAX;
}

if (wait_us <= MAX_SINGLE_SLEEP_US / BACKOFF_FACTOR) {
wait_us *= BACKOFF_FACTOR;
} else {
// Saturate at the `usleep()` max sleep bound.
wait_us = MAX_SINGLE_SLEEP_US;
}
}

// Unreachable
return LIBHOTH_ERR_FAIL;
}

int libhoth_release_device(struct libhoth_device* dev) {
return dev->release(dev);
}
7 changes: 7 additions & 0 deletions transports/libhoth_device.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
#define _LIBHOTH_TRANSPORTS_LIBHOTH_DEVICE_H_

#include <stddef.h>
#include <stdint.h>

#ifdef __cplusplus
extern "C" {
Expand Down Expand Up @@ -75,6 +76,12 @@ int libhoth_device_reconnect(struct libhoth_device* dev);

int libhoth_device_close(struct libhoth_device* dev);

// Try to claim `dev`. If `dev` is already claimed, then try to claim later by
// waiting an exponentially backed off amount of time.
int libhoth_claim_device(struct libhoth_device* dev, uint32_t timeout_us);

int libhoth_release_device(struct libhoth_device* dev);

#ifdef __cplusplus
}
#endif
Expand Down
Loading