Add os_usleep with bounded sleep loop returning on signal interruption and use it in bandwidth limiter

This commit is contained in:
Andrea Mazzoleni 2026-08-14 09:25:14 +02:00
parent 2bf74bc66f
commit daf713820e
5 changed files with 66 additions and 20 deletions

View file

@ -42,7 +42,7 @@ void bw_limit(struct snapraid_bw* bw, uint64_t bytes)
bw->total += bytes;
done = bw->total;
eta = done * 1000 / bw->limit;
eta = (done / bw->limit) * 1000 + (done % bw->limit) * 1000 / bw->limit;
/*
* To prevent accumulating unlimited credit during long pauses
@ -61,10 +61,7 @@ void bw_limit(struct snapraid_bw* bw, uint64_t bytes)
#endif
if (eta > elapsed) {
eta -= elapsed;
if (eta > 1000)
eta = 1000;
usleep((unsigned)eta * 1000);
os_usleep((eta - elapsed) * 1000);
}
}

View file

@ -469,10 +469,10 @@ static int windows_info2stat(const BY_HANDLE_FILE_INFORMATION* info, const FILE_
* the nFileIndexHigh and nFileIndexLow members. This API is an extended version
* that includes 128-bit file identifiers. If GetFileInformationByHandle returns
* FILE_INVALID_FILE_ID, the identifier may only be described in 128 bit form.
*
*
* From Microsoft "[MS-FSCC]: File System Control Codes - 11/21/2025 v60.0 - 6 Appendix B: Product Behavior"
* https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-fscc/d4bc551b-7aaf-4b4f-ba0e-3a75e7c528f0
*
*
* 64bitFileID Generate Stable Unique
* FAT Yes No No
* EXFAT Yes No No
@ -492,7 +492,7 @@ static int windows_info2stat(const BY_HANDLE_FILE_INFORMATION* info, const FILE_
*
* From Microsoft "[MS-FSCC]: File System Control Codes - 11/21/2025 v60.0 - 2.1.9 64-bit file ID"
* https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-fscc/2d3333fe-fc98-4a6f-98a2-4bb805aff407?utm_source=chatgpt.com
*
*
* A 64-bit file ID value uniquely identifies a file within a given volume. This
* identifier is generated and stored by the file system. The identifier SHOULD
* be unique to the volume and stable until the file is deleted.
@ -1600,11 +1600,6 @@ unsigned windows_sleep(unsigned seconds)
return seconds;
}
void windows_usleep(uint64_t useconds)
{
Sleep(useconds / 1000);
}
int windows_link(const char* existing, const char* file)
{
wchar_t conv_buf_file[CONV_MAX];
@ -3458,6 +3453,27 @@ uint64_t os_tick_ms(void)
return GetTickCount64();
}
int os_usleep(uint64_t usec)
{
while (usec > 0) {
unsigned chunk = 1000000;
if (usec < chunk)
chunk = (unsigned)usec;
if (os_signal_interrupt()) {
errno = EINTR;
return -1;
}
Sleep(chunk / 1000);
usec -= chunk;
}
return 0;
}
void os_privileges_acquire(void)
{
}

View file

@ -156,8 +156,6 @@ wchar_t* u8tou16_mayfail(wchar_t* conv_buf, size_t number_of_wchar, const char*
#define stat_desc windows_stat_desc
#undef sleep
#define sleep windows_sleep
#undef usleep
#define usleep windows_usleep
/* 4==DIR, 5,6,7=free, 8==REG */
#define S_IFLNK 0x5000 /* Symbolic link to file */
#define S_ISLNK(m) (((m) & _S_IFMT) == S_IFLNK)
@ -434,16 +432,12 @@ const char* windows_stat_desc(struct stat* st);
*/
unsigned windows_sleep(unsigned seconds);
/**
* Like usleep().
*/
void windows_usleep(uint64_t useconds);
/**
* Like readlink().
*/
int windows_readlink(const char* file, char* buffer, size_t size);
/**
* Like symlink().
* Return ENOSYS if symlinks are not supported.

11
os/os.h
View file

@ -307,6 +307,16 @@ uint64_t os_tick_ms(void);
*/
uint64_t os_tick_sec(void);
/**
* Sleep for the specified number of microseconds.
*
* Loops in bounded intervals and returns on the first error or signal interruption.
* \param usec Number of microseconds to sleep.
* \return 0 on success, -1 on error.
*/
int os_usleep(uint64_t usec);
/**
* Abort the process with a stacktrace.
*/
@ -343,3 +353,4 @@ int os_randomize(void* ptr, size_t size);
int os_get_optimal_cpu(void);
#endif

View file

@ -1694,6 +1694,34 @@ uint64_t os_tick_sec(void)
return ts.tv_sec;
}
int os_usleep(uint64_t usec)
{
while (usec > 0) {
unsigned chunk = 999999;
if (usec < chunk)
chunk = (unsigned)usec;
if (os_signal_interrupt()) {
errno = EINTR;
return -1;
}
/*
* Sleep in intervals of at most 999999 microseconds because POSIX usleep()
* only accepts values less than 1,000,000 microseconds (< 1 second)
* and may fail with EINVAL for larger values.
*/
if (usleep(chunk) != 0)
return -1;
usec -= chunk;
}
return 0;
}
int os_randomize(void* ptr, size_t size)
{
int f;