|Age||Commit message (Collapse)||Author||Lines|
this practice came from very early, before internal/syscall.h defined
macros that could accept pointer arguments directly and handle them
correctly. aside from being ugly and unnecessary, it looks like it
will be problematic when we add support for 32-bit ABIs on archs where
registers (and syscall arguments) are 64-bit, e.g. x32 and mips n32.
1. the thread result field was reused for storing a kernel timer id,
but would be overwritten if the application code exited or cancelled
2. low pointer values were used as the indicator that the timer id is
a kernel timer id rather than a thread id. this is not portable, as
mmap may return low pointers on some conditions. instead, use the fact
that pointers must be aligned and kernel timer ids must be
non-negative to map pointers into the negative integer space.
3. signals were not blocked until after the timer thread started, so a
race condition could allow a signal handler to run in the timer thread
when it's not supposed to exist. this is mainly problematic if the
calling thread was the only thread where the signal was unblocked and
the signal handler assumes it runs in that thread.
calling pthread_exit from, or pthread_cancel on, the timer callback
thread will no longer destroy the timer.
since timer_create is no longer allocating a structure for the timer_t
and simply using the kernel timer id, it was impossible to specify the
timer_t as the argument to the signal handler. the solution is to pass
the null sigevent pointer on to the kernel, rather than filling it in
userspace, so that the kernel does the right thing. however, that
precludes the clever timerid-versus-threadid encoding we were doing.
instead, just assume timerids are below 1M and thread pointers are
above 1M. (in perspective: timerids are sequentially allocated and
seem limited to 32k, and thread pointers are at roughly 3G.)
this is necessary in order to avoid breaking timer_getoverrun in the
last run of the timer event handler, if it has not yet finished.
instead of allocating a userspace structure for signal-based timers,
simply use the kernel timer id. we use the fact that thread pointers
will always be zero in the low bit (actually more) to encode integer
timerid values as pointers.
also, this change ensures that the timer_destroy syscall has completed
before the library timer_destroy function returns, in case it matters.
this allows small programs which only create times, but never delete
them, to use simple_malloc instead of the full malloc.
this implementation is superior to the glibc/nptl implementation, in
that it gives true realtime behavior. there is no risk of timer
expiration events being lost due to failed thread creation or failed
malloc, because the thread is created as time creation time, and
reused until the timer is deleted.