History log of /haiku/src/libs/compat/freebsd_network/callout.cpp
Revision Date Author Comments
# c4737dcb 17-Apr-2023 Augustin Cavalier <waddlesplash@gmail.com>

freebsd_network: Be lenient, do not assert if the callout mutex is &Giant.

Same as FreeBSD. Should fix #18356.


# 70b4d59f 31-Mar-2023 Augustin Cavalier <waddlesplash@gmail.com>

freebsd_network: Refactor callout_stop and functions which invoke it.

* Create an internal variant which accepts a "bool locked" parameter.
Use this from callout_reset instead of invoking it before locking,
and then relocking afterwards. Eliminates some possible (though,
so far as I know, benign) races.

* mtx_assert always, even if the callout is not active. (Requirement
notated in the comment.)

* In callout_reset, do not invoke callout_stop at all unless we are
cancelling; in cases of mere reschedules, simply change c_due
and notify the callout thread.

* While at it, use list_init_etc in init_callout; no-op change,
but keeps things clean.

This should fix #18338 (specifically the change to never invoke
callout_stop when merely rescheduling, not cancelling.)


# f863f473 31-Mar-2023 Augustin Cavalier <waddlesplash@gmail.com>

freebsd_network: Check for c_due > 0 in the callout invocation.

Here is the scenario in which this matters:

1. A callout comes due, it is removed from the list, and c_due is set
to 0. We then wind up in the mtx_lock here inside invoke_callout;
while some other thread holds the lock.

2. The other thread, holding the lock, decides to *re*schedule the callout
for a later time than the present. callout_reset sees the callout has
a c_due of 0, thus indicating it is not in the sTimers list, adds it,
and sets a (future) c_due.

3. The other thread unlocks c_mtx, thus the callout thread acquires it
and proceeds.

Under the code I wrote in hrev56875, before this commit, the following
would occur (at least with the ipro1000 driver on some hardware):

4. c_due would be set to -1, thus signaling the callout was no longer
scheduled, and thus not in the sTimers list (despite being in it!).
The callout's own method would decide to reschedule itself, and
invoke callout_reset as such.

5. callout_reset would, seeing c_due of <= 0, try to add the callout to
the sTimers list. However it is already in the list, and in many
circumstances the only item in the list, so it would get silently
linked to itself.

6. An infinite loop due to the looped linked-list and/or double-remove
resulting in NULL dereferences would result.

Steps 1-2 coinciding in just the right way was apparently very rare, hence
why this problem only appeared very infrequently. The code I wrote to force
their coinciding made the problem happen extremely frequently.

This fixes #18334.

(Figuring out that the problem was an item being linked to itself, and
most critically a double-*reschedule* not a double-*removal*, took
far too long to figure out. I will be refactoring this code more
in subsequent commits, but also introducing new assertions to our
linked-list systems which enabled me to finally track down this problem
at all. Who knows; perhaps they will shake loose other bugs.)


# 1110e6fc 30-Mar-2023 Augustin Cavalier <waddlesplash@gmail.com>

freebsd_network: Migrate callout invocation to another function.

Avoids "goto" and reduces indentation.


# 673bc108 30-Mar-2023 Augustin Cavalier <waddlesplash@gmail.com>

freebsd_network: Always unset c_due after removing the callout from the list.

Use 0 as the magic value instead of a positive one. This way, <= 0
consistently signals that the callout is not in the list, whereas > 0
signals that it is.


# e6d3d777 30-Mar-2023 Augustin Cavalier <waddlesplash@gmail.com>

freebsd_network: Cleanup callout_thread.

* Reorganize inner loop for clarity and to reduce indentation.
* Handle callouts that are due at this exact system_time.
* "break" instead of "continue" if lock fails.


# d2670b49 29-Mar-2023 Augustin Cavalier <waddlesplash@gmail.com>

freebsd_network: Handle an edge-case race of callout_stop.

If callout_stop() runs at the same time the callout_thread is
about to process the callout, we can wind up with a situation where
the callout is "active" but has not yet run due to waiting on the mutex.

FreeBSD's documentation confirms that callout_stop must be called
(when "safe" is 0, i.e. not callout_drain) with the callout's lock
held, if it has one, and so we can prevent the callout from being
invoked at this point, too.

Additionally, fix return values of callout_reset.

May further help with #18315.


# 90d34dca 24-Mar-2023 Augustin Cavalier <waddlesplash@gmail.com>

freebsd_network: Rework callout_stop implementation.

From the FreeBSD manual pages:
> If the callout is currently being serviced and cannot be stopped,
> and at the same time a next invocation of the same callout is also
> scheduled, then callout_stop() unschedules the next run and returns
> zero.

Previously we would return zero but not unschedule the next run.
This may fix #18315.


# d51cccd9 07-Jul-2022 Augustin Cavalier <waddlesplash@gmail.com>

Revert "freebsd_network: Adjust callout_reset to drain not stop callouts."

This reverts commit 259f9a76d8eb1c6156b544f3f91158e684b23d00.

This does not work with callouts that reschedule themselves, which is
something certain drivers indeed do.


# 259f9a76 07-Jul-2022 Augustin Cavalier <waddlesplash@gmail.com>

freebsd_network: Adjust callout_reset to drain not stop callouts.

As we are going to modify func/arg, we need to be sure they are not
even executing.


# a73773b2 07-Jul-2022 Augustin Cavalier <waddlesplash@gmail.com>

freebsd_network: Clean up struct callout.

* Remove unused flags field.
* Rename internal members to have c_ at the beginning, like FreeBSD.


# 631f505f 07-Jul-2022 Augustin Cavalier <waddlesplash@gmail.com>

freebsd_network: Fix callout_active checking in callout_stop.

We have to perform the "due" check after checking callout_active,
because due is set to -1 while the callout is actually active.


# 1cef8ebf 07-Jun-2022 Augustin Cavalier <waddlesplash@gmail.com>

freebsd_network: Fix ticks check in callout_reset.

"ticks" is the name of the global variable indicating time since
system start; "_ticks" is the local variable. The confusion between
the two caused every callout to be invoked as soon as it was instantiated.

I am pretty surprised this was not noticed before. I only discovered
it just now while working on the OpenBSD WiFi driver ports. Seems
it has been broken like this for multiple years...


# 385fce1c 09-Mar-2022 Augustin Cavalier <waddlesplash@gmail.com>

freebsd_network: Properly implement callout_drain().

Also cleanup code a bit.

May help with #17634.


# c70ec71d 05-Jul-2020 Augustin Cavalier <waddlesplash@gmail.com>

freebsd_network: Move ticks/seconds conversions to sys/time.h and
rename.

They now match the names they have in FreeBSD.
No functional change intended.


# dba28784 24-Dec-2018 Augustin Cavalier <waddlesplash@gmail.com>

freebsd11_network -> freebsd_network.

FreeBSD 12 has no major changes to the ifnet KPIs that constitute a
source compatibility break, save a single one related to locking
which doesn't really apply to us, and so we don't need to create
a "freebsd12_network" directory to work through the upgrades.


# 15ed6a1e 11-Aug-2012 Alex Smith <alex@alex-smith.me.uk>

CID 609387: Uninitialized pointer access.

Fixes a crash I just ran into on x86_64, only appeared when I built
with optimization disabled.


# a2e7d8df 18-Jul-2012 Fredrik Holmqvist <fredrik.holmqvist@gmail.com>

callout_schedule uses ticks as timeunit, not usecs.

As suggested by Rene Gollent, we used ticks as usecs.


# 73fc635b 16-Jul-2012 Fredrik Holmqvist <fredrik.holmqvist@gmail.com>

Tick at 1000Hz not 1MHz.

Our FreeBSD networking code defined hz to 1MHz and 1 tick = 1 / hz,
but the clock code ticked 1 tick at 1000Hz.

This caused all calculations that are done on ticks, autonegotiation
and wlan scanning to be done very often as FreeBSD uses 1000 Hz
(100Hz for ARM). Defaults for autonegotiation is 5 and 17 ticks.

(Another interesting thing is that callouts are using 8% cpu...)


# e7c3a8ff 19-Jul-2010 Axel Dörfler <axeld@pinc-software.de>

Fixed a few regressions that were introduced during the last months:
* device_attach() must not load the network stack. Besides being completely
unbalanced, this was also one reason why the stack could not be unloaded
anymore. Instead, it's now done in compat_open(), as before.
* This also fixes network booting from FreeBSD drivers - the stack apparently
could not be initialized that early.
* Replaced the previous network stack based callout implementation with one
that mostly copies its functionality, but has no dependencies. Furthermore,
it runs at a higher priority (the one of the network timer should also be
revisited, though).
* Fixed mtx_owned() to work without KDEBUG as well. It's not a good idea to
introduce code that behaves completely different based on debug settings.
* Minor cleanup.


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@37580 a95241bf-73f2-0310-859d-f6bbb57e9c96


# 15ed6a1e56f3c1a61c8aff7b310a0665f97e1c95 11-Aug-2012 Alex Smith <alex@alex-smith.me.uk>

CID 609387: Uninitialized pointer access.

Fixes a crash I just ran into on x86_64, only appeared when I built
with optimization disabled.


# a2e7d8df7bf39721a597b0473831f25813d71b0e 18-Jul-2012 Fredrik Holmqvist <fredrik.holmqvist@gmail.com>

callout_schedule uses ticks as timeunit, not usecs.

As suggested by Rene Gollent, we used ticks as usecs.


# 73fc635b3d87970ed7843eacd0ac7a5ffcac0e9b 16-Jul-2012 Fredrik Holmqvist <fredrik.holmqvist@gmail.com>

Tick at 1000Hz not 1MHz.

Our FreeBSD networking code defined hz to 1MHz and 1 tick = 1 / hz,
but the clock code ticked 1 tick at 1000Hz.

This caused all calculations that are done on ticks, autonegotiation
and wlan scanning to be done very often as FreeBSD uses 1000 Hz
(100Hz for ARM). Defaults for autonegotiation is 5 and 17 ticks.

(Another interesting thing is that callouts are using 8% cpu...)


# e7c3a8ffd7434cff9662772e1fd12d336b2073ec 19-Jul-2010 Axel Dörfler <axeld@pinc-software.de>

Fixed a few regressions that were introduced during the last months:
* device_attach() must not load the network stack. Besides being completely
unbalanced, this was also one reason why the stack could not be unloaded
anymore. Instead, it's now done in compat_open(), as before.
* This also fixes network booting from FreeBSD drivers - the stack apparently
could not be initialized that early.
* Replaced the previous network stack based callout implementation with one
that mostly copies its functionality, but has no dependencies. Furthermore,
it runs at a higher priority (the one of the network timer should also be
revisited, though).
* Fixed mtx_owned() to work without KDEBUG as well. It's not a good idea to
introduce code that behaves completely different based on debug settings.
* Minor cleanup.


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@37580 a95241bf-73f2-0310-859d-f6bbb57e9c96