Commit Graph

20 Commits

Author SHA1 Message Date
Ken Brown 73e3ff9328 Cygwin: timerfd: avoid a deadlock
Add a function timerfd_tracker::enter_critical_section_cancelable,
which is like enter_critical_section but honors a cancel event.  Call
this when a timer expires while the timerfd thread is in its inner
loop.  This avoids a deadlock if timerfd_tracker::dtor has entered its
critical section and is trying to cancel the thread.  See
https://cygwin.com/ml/cygwin/2019-06/msg00096.html.
2020-10-14 10:53:55 -04:00
Corinna Vinschen 639645a2fd Cygwin: timerfd: add a sleep when being debugged
A sleep is required on Windows 10 64 bit only before calling
RegisterClassW in the timerfd thread, and only when running
under strace.  One of the child processes inheriting the timerfd
descriptor will get a STATUS_FLOAT_INEXACT_RESULT exception inside
of msvcrt.dll.  It's apparently some timing problem.  It occurs
in 4 out of 5 runs under strace only.  WOW64 and Windows 7 64 bit
don't have this problem.

Signed-off-by: Corinna Vinschen <corinna@vinschen.de>
2019-02-26 10:46:05 +01:00
Corinna Vinschen 5a483b6bca Cygwin: timerfd: reduce size of shared mem region to a single page
The share section was created using the PAGE_SIZE constant,
but PAGE_SIZE is 64K.  Fix that by using wincap.page_size()
instead, which returns the desired actual page size of 4K.

Signed-off-by: Corinna Vinschen <corinna@vinschen.de>
2019-02-26 10:19:08 +01:00
Corinna Vinschen 98afd02be3 Cygwin: timerfd: rework implementation
timerfd_tracker and timerfd_shared classes:

- Just because handles are shared, we don't have to store them in
  shared memory.  Move share handles into timerfd_tracker class.

- Drop shared instance counter since it's not required anymore.
  timerfd_shared only stores the actual timer data.

- Drop timerfd_shared::create, just set clock id.

- Drop timerfd_shared::dtor, it's not required anymore.

- Drop timerfd_tracker::close, just call dtor where required.

- Rename timerfd_tracker::increment_instances to timerfd_tracker::dup.
  It's the only reason it exists...

- timerfd_tracker::dtor now checks the non-shared pointers for NULL
  before attempting to close them.

- timerfd_tracker::dtor handles decrementing the local instance count
  by itself.

- Add a method timerfd_tracker::init_fixup_after_fork_exec to set
  non-shared pointers to NULL.  Together with the dtor patches it
  fixes a problem with close_on_exec timerfd descriptors.

- Fix a bug in handling the thread synchronization event.  It's
  actually nice to create it before using it...

- Drop using sec_none{_nih} in InitializeObjectAttributes.  It's
  an unnecessary roundabout route just to get a NULL pointer.

- Slightly rework timechange window handling.

- Add more comments to explain what happens.

fhandler_timerfd:

- Drop cnew macro, it just hides what happens.

- fhandler_timerfd::fixup_after_exec now calls
  timerfd_tracker::init_fixup_after_fork_exec first, so a subsequent
  call to timerfd_tracker::dtor only works on valid handles.

- fhandler_timerfd::close directly calls timerfd_tracker::dtor now.

- Drop dtor call in fhandler_timerfd destructor.

Signed-off-by: Corinna Vinschen <corinna@vinschen.de>
2019-02-25 21:01:32 +01:00
Corinna Vinschen a4e2eb6ba3 Cygwin: timerfd: fix shared memory allocation in fork/exec
timerfd_tracker::fixup_after_fork_exec always tries to restore
the shared timer region at the same address as in the parent.
This is entirely unnecessary and wasn't intended, rather some
kind of copy/paste thinko.  Fix that.  Print NtMapViewOfSection
status code in api_fatal on failure for debugging.

Signed-off-by: Corinna Vinschen <corinna@vinschen.de>
2019-02-24 20:23:34 +01:00
Corinna Vinschen 99cd3df6ec Cygwin: timerfd: drop outdated TODO comment
Signed-off-by: Corinna Vinschen <corinna@vinschen.de>
2019-02-04 21:08:03 +01:00
Corinna Vinschen 6c44af8179 Cygwin: timerfd: Add support for CLOCK_REALTIME_ALARM/CLOCK_BOOTTIME_ALARM
Signed-off-by: Corinna Vinschen <corinna@vinschen.de>
2019-01-22 15:46:17 +01:00
Corinna Vinschen 4c50dc94c3 Cygwin: timerfd: another overrun computation fix and drop useless variable
- When correcting the next expiration timestamp, the number of
  expirations gets computed correctly, just the expiration timestamp
  itself is then only incremented by a single interval, rather than
  the just computed expired intervals.  Fix that.

- drop the local clock variable in timerfd_tracker::create.  It doesn't
  serve any purpose.

Signed-off-by: Corinna Vinschen <corinna@vinschen.de>
2019-01-22 15:06:51 +01:00
Corinna Vinschen a75bd958b4 Cygwin: timerfd: reset expiry counter in settime
As on Linux, reset the expiry counter when the timer gets rearmed.

Signed-off-by: Corinna Vinschen <corinna@vinschen.de>
2019-01-21 22:54:26 +01:00
Corinna Vinschen 5b23a8e831 Cygwin: timerfd: fix gettime
- split into to __try/__except blocks to make sure
  leave_critical_section is always called when required.

- Actually fill time_spec in settime so it_interval is returned
  correctly.

- Return all 0 if timer is disarmed.

Signed-off-by: Corinna Vinschen <corinna@vinschen.de>
2019-01-21 22:52:39 +01:00
Corinna Vinschen 289b7c09c8 Cygwin: timerfd: move ioctl error handling into timerfd_tracker
Signed-off-by: Corinna Vinschen <corinna@vinschen.de>
2019-01-21 12:41:00 +01:00
Corinna Vinschen 528f4d4938 Cygwin: timerfd: rename overrun_count to expiration_count
The value returned by reading from a timerfd is not an overrun
count in the same sense as for posix timers, it's an expiry counter.
Reflect that in the name.

Signed-off-by: Corinna Vinschen <corinna@vinschen.de>
2019-01-21 12:26:51 +01:00
Corinna Vinschen ea99e9fdda Cygwin: timerfd: fix overrun computation
- Drop erroneous initial computation of overrun count in settime
  for absolute non-realtime clocks.  It's repeated in thread_func
  and thus counted twice.

- Fix overrun computation for timestamp offsets being a multiple of
  the timer interval.  The timestamp has to be corrected after the
  first offset, otherwise the correction loop counts the intervals
  again.

Signed-off-by: Corinna Vinschen <corinna@vinschen.de>
2019-01-21 11:14:16 +01:00
Corinna Vinschen 6ed50a68a1 Cygwin: timerfd: settime: fix computing DueTime on non-realtime clocks
Non-CLOCK_REALTIME counters always use a relative DueTime in NtSetTimer.
However, relative DueTime has to be negative, but the code

Signed-off-by: Corinna Vinschen <corinna@vinschen.de>
2019-01-21 10:05:16 +01:00
Corinna Vinschen a3268ac392 Cygwin: timerfd: Handle gettime error in settime
Signed-off-by: Corinna Vinschen <corinna@vinschen.de>
2019-01-21 00:14:51 +01:00
Corinna Vinschen 02de9ac61e Cygwin: timerfd: fill out it_interval on timerfd_gettime
Might not be such a bad idea, after all...

Signed-off-by: Corinna Vinschen <corinna@vinschen.de>
2019-01-21 00:14:09 +01:00
Corinna Vinschen 2993057a94 Cygwin: timerfd: implement TFD_TIMER_CANCEL_ON_SET
Signed-off-by: Corinna Vinschen <corinna@vinschen.de>
2019-01-20 22:47:52 +01:00
Corinna Vinschen 597285ca58 Cygwin: timerfd: fix read(2) running wild
- On systems with inexact realtime clock, the current timestamp may
  be fractionally smaller than the desired timestamp.  This breaks the
  computation for incrementing overrun_count so overrun_count may end
  up as 0.  Expiring the timer with an overrun_count of 0 is a no-go.
  Make sure we always increment overrun_count by at least one after
  timer expiry.

- Do not expire the timer when another process deletes its timer_tracker.
  This, too, may result in a 0 overrun_count.

Signed-off-by: Corinna Vinschen <corinna@vinschen.de>
2019-01-20 22:18:17 +01:00
Corinna Vinschen e32d1510da Cygwin: timerfd: prepare for TFD_TIMER_CANCEL_ON_SET
Also drop debugging sleep and make sure overrun count is positive.

Signed-off-by: Corinna Vinschen <corinna@vinschen.de>
2019-01-19 20:53:38 +01:00
Corinna Vinschen 40481dbabb Cygwin: timerfd: reimplement from scratch
Using posix timers "timer_tracker" as base class for timerfd was flawed.
Posix timers are not inherited by child processes and don't survive
execve.  The method used by posix timers didn't allow to share timers
between processes. The timers were still per-process timers and worked
entirely separate from each other.  Reading from these timers via
different descriptors was only synchronized within the same process.

This does not reflect the timerfd semantics in Linux: The per-file
timers can be dup'ed and survive fork and execve.  They are still just
descriptors pointing to the same timer object originally created by
timerfd_create.  Synchronization is performed between all descriptor
instances of the same timer, system-wide.

Thus, reimplement timerfd using a timer instance in shared memory,
a kernel timer, and a handful of sync objects.

Every process maintains a per-process timerfd struct on the cygheap
maintaining a per-process thread.  Every process sharing the same
timerfd will run this thread checking the state of the timer, similar
to the posix timer thread, just working on the shared objects and
synchronizing its job with each other thread.

Drop the timerfd implementation in the posix timer code and move the
public API to fhandler_timerfd.c.  Keep the ttstart timer_tracker
anchor out of "NO_COPY" since the fixup_after_fork code should run to
avoid memory leakage.

Signed-off-by: Corinna Vinschen <corinna@vinschen.de>
2019-01-19 20:00:06 +01:00