diff --git a/cmdline/bw.c b/cmdline/bw.c index 7d857745..3d407545 100644 --- a/cmdline/bw.c +++ b/cmdline/bw.c @@ -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); } } diff --git a/os/mingw.c b/os/mingw.c index 3b1611de..d837474f 100644 --- a/os/mingw.c +++ b/os/mingw.c @@ -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) { } diff --git a/os/mingw.h b/os/mingw.h index 3d263517..990adc2f 100644 --- a/os/mingw.h +++ b/os/mingw.h @@ -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. diff --git a/os/os.h b/os/os.h index 5495c180..2ba71c12 100644 --- a/os/os.h +++ b/os/os.h @@ -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 + diff --git a/os/unix.c b/os/unix.c index a9fb2842..23f6cc4b 100644 --- a/os/unix.c +++ b/os/unix.c @@ -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;