]> Projects (at) Tadryanom (dot) Me - AdrOS.git/commitdiff
fix select() timeout conversion — was passing raw pointer as kernel timeout
authorTulio A M Mendes <[email protected]>
Sun, 19 Apr 2026 21:30:12 +0000 (18:30 -0300)
committerTulio A M Mendes <[email protected]>
Sun, 19 Apr 2026 21:30:12 +0000 (18:30 -0300)
The select() wrapper in both newlib/posix_stubs.c and ulibc/unistd.c
was casting the struct timeval* pointer directly to int and passing it
as the 5th syscall argument. The kernel expects an int32_t timeout:
  -1 = infinite wait, 0 = poll (return immediately), >0 = ticks.

When bash calls select() with timeout=NULL (infinite wait), the raw
pointer value was interpreted as a large positive number (poll with
timeout), not as -1 (infinite). Worse, on some code paths the pointer
could be 0 (NULL), which the kernel treats as timeout=0 (poll only),
causing select() to return 0 immediately with no fds ready — which
bash interprets as EOF on stdin, causing it to exit immediately.

Fix: convert struct timeval to int32_t ticks before passing to the
kernel. NULL timeout → -1 (infinite). tv_sec=0, tv_usec=0 → 0 (poll).
Otherwise convert ms → ticks (TIMER_HZ=100, 10ms/tick).

newlib/libgloss/adros/posix_stubs.c
user/ulibc/src/unistd.c

index db32cadd33f0e054dffc06f0f5b28b9d4ef59f16..108e8260648afb66fd8a9ab35640a7be497a1823 100644 (file)
@@ -451,8 +451,21 @@ int ioctl(int fd, unsigned long request, ...) {
 
 int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds,
            struct timeval *timeout) {
+    /* Kernel expects int32_t timeout: -1 = infinite, 0 = poll, >0 = ticks.
+     * TIMER_HZ = 100, so 1 tick = 10 ms. */
+    int32_t tmo = -1;  /* default: infinite wait */
+    if (timeout) {
+        if (timeout->tv_sec == 0 && timeout->tv_usec == 0) {
+            tmo = 0;  /* poll only */
+        } else {
+            uint32_t ms = (uint32_t)timeout->tv_sec * 1000
+                        + (uint32_t)timeout->tv_usec / 1000;
+            tmo = (int32_t)(ms / 10);  /* ms → ticks (10 ms/tick) */
+            if (tmo < 1) tmo = 1;
+        }
+    }
     return _check(_sc5(SYS_SELECT, nfds, (int)readfds, (int)writefds,
-                       (int)exceptfds, (int)timeout));
+                       (int)exceptfds, (int)tmo));
 }
 
 int pselect(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds,
index 748b78a48a77649baa62a3f92593f88d1b315a22..5993e2c8fe89b013b6e1bb9d17029c9d5156d8f9 100644 (file)
@@ -335,8 +335,21 @@ void* sbrk(int increment) {
 
 int select(int nfds, fd_set* readfds, fd_set* writefds, fd_set* exceptfds,
            struct timeval* timeout) {
+    /* Kernel expects int32_t timeout: -1 = infinite, 0 = poll, >0 = ticks.
+     * TIMER_HZ = 100, so 1 tick = 10 ms. */
+    int32_t tmo = -1;
+    if (timeout) {
+        if (timeout->tv_sec == 0 && timeout->tv_usec == 0) {
+            tmo = 0;
+        } else {
+            uint32_t ms = (uint32_t)timeout->tv_sec * 1000
+                        + (uint32_t)timeout->tv_usec / 1000;
+            tmo = (int32_t)(ms / 10);
+            if (tmo < 1) tmo = 1;
+        }
+    }
     return __syscall_ret(_syscall5(SYS_SELECT, nfds, (int)readfds, (int)writefds,
-                                   (int)exceptfds, (int)timeout));
+                                   (int)exceptfds, (int)tmo));
 }
 
 int fcntl(int fd, int cmd, ...) {