I believe I found out what's wrong with that.
/usr/src/linux-2.0.3x/fs/select.c:sys_select():
unsigned long timeout;
/* ... */
timeout = ~0UL;
if (tvp) {
error = verify_area(VERIFY_WRITE, tvp, sizeof(*tvp));
if (error)
goto out;
timeout = ROUND_UP(get_user(&tvp->tv_usec),(1000000/HZ));
timeout += get_user(&tvp->tv_sec) * (unsigned long) HZ;
if (timeout)
timeout += jiffies + 1;
}
zero_fd_set(n, &res_in);
zero_fd_set(n, &res_out);
zero_fd_set(n, &res_ex);
current->timeout = timeout;
error = do_select(n,
(fd_set *) &in,
(fd_set *) &out,
(fd_set *) &ex,
(fd_set *) &res_in,
(fd_set *) &res_out,
(fd_set *) &res_ex,
(fd_set *) &locked);
timeout = current->timeout - jiffies - 1;
current->timeout = 0;
if ((long) timeout < 0)
timeout = 0;
if (tvp && !(current->personality & STICKY_TIMEOUTS)) {
put_user(timeout/HZ, &tvp->tv_sec);
timeout %= HZ;
timeout *= (1000000/HZ);
put_user(timeout, &tvp->tv_usec);
}
Now, if the timeout is reached during do_select, current->timeout becomes zero.
The line
if ((long) timeout < 0)
timeout = 0;
is propably for that. However, if jiffies > 2**31, that wont work (since
timeout wraps around and actually becomes positive), and select returns
false values. I would suggest something like
timeout = current->timeout ? current->timeout - jiffies - 1 : 0;
instead of
timeout = current->timeout - jiffies - 1;
2.2 seems to do
if (tvp && !(current->personality & STICKY_TIMEOUTS)) {
time_t sec = 0, usec = 0;
if (timeout) {
sec = timeout / HZ;
usec = timeout % HZ;
usec *= (1000000/HZ);
}
put_user(sec, &tvp->tv_sec);
put_user(usec, &tvp->tv_usec);
}
So I think it has not got this bug. I'm not sure, however.
-- v --
v@iki.fi
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.rutgers.edu
Please read the FAQ at http://www.tux.org/lkml/