For a long time, I had assumed that the iteration variables of a .for
loop are just normal global variables. This assumption was wrong but
didn't have any consequences.
The iteration variables of a .for loop can just be accessed like global
variables, therefore it is not obvious that they are implemented in a
completely different way.
There are some edge cases in conditions used inside .for loops, in which
the iteration variables cannot be used like normal variables. An
example is brought up in https://gnats.netbsd.org/47888, which observes
that the defined() and empty() functions in conditions only work with
variables but ignore the iteration "variables", simply because these are
not variables but only expressions.
When the struct stat was used for both calling the actual stat and for
returning the result, no copying was needed. This also had the side
effect that for the first call of cached_stat, the returned struct stat
included all the fields properly filled in, and on later calls, these
fields were all zeroed out.
These two variables are separate now, thus the fields need to be copied
explicitly. There are no existing unit tests for this, but ./build.sh
failed reliably.
Only st_mtime and st_mode are actually filled, the remaining fields had
been set to zero. To prevent these from ever being accessed, a custom
struct make_stat replaces the previously used struct stat.
The fields in struct make_stat are intentionally named different from
the fields in struct stat because NetBSD and some other operating
systems define st_mtime as a macro, and that would not work in a field
declaration.
Back in the 1980s it made sense to have the type information encoded in
the variable names. At the time when make was imported into the NetBSD
tree (1993-03-21), the functions did indeed not have prototypes, they
only had return types. The void type was already invented at that time.
Since the compiler could not verify the types of function parameters, it
made perfect sense to have each variable tell whether it was a pointer
or not.
Since ISO C90 this is no longer necessary since the compiler checks
this. The variable names can now focus on the application level and
their high-level meaning, expressing the relationship to other
variables instead of encoding redundant type information.
The name HTSIZE didn't provide any explanation for the value 191, and it
is obvious that this is a hash table size. Therefore giving the
constant a name didn't explain anything or make it less magic.
exceptions on QNaNs.
- alpha_fp_interpret(): Instructions are 32-bits wide, so don't use a
uint64_t to contain them.
- alpha_fp_complete(): Operations on NaNs trap on Alpha, but the exception
summary reports INV (invalid operation) rather than SWC (software
completion) in this case. So also interpret the instruction if INV
is set in the exception summary. This will emulate operations on
NaN and correctly suppress FP traps for QNaNs.
This fixes bin/55633, which was caused by:
-> Input string "nanotime" is passed to awk's internal is_number().
-> strtod() interprets as "nan" and returns QNaN as the result.
-> Result compared against HUGE_VAL, blows up because cmptle is called
with a NaN operand, and the hardware doesn't care that it's quiet.
The recovery mode timer is first issued by the callout and it schedule
the workqueue. The workqueue then reschedule the callout. It's hard to
stop both of them without race only with callout_stop() and workqueue_wait.
To solve this problem. add new "detaching" flag and use it.
The situation is almost the same as schedule_wqs_ok for the local_timer's
callout and workqueue, but the difference is that the local_timer isn't
required to run if the interface is not up. If it's not important to prevent
running timer while !IFF_UP, the flag can be integrated into one.
Summary: Access to a stable established session is still allowed via
psref; all other access to peer and session state is now serialized
by struct wg_peer::wgp_lock, with no dancing around a per-session
lock. This way, the handshake paths are locked, while the data
transmission paths are pserialized.
- Eliminate struct wg_session::wgs_lock.
- Eliminate wg_get_unstable_session -- access to the unstable session
is allowed only with struct wgp_peer::wgp_lock held.
- Push INIT_PASSIVE->ESTABLISHED transition down into a thread task.
- Push rekey down into a thread task.
- Allocate session indices only on transition from UNKNOWN and free
them only on transition back to UNKNOWN.
- Be a little more explicit about allowed state transitions, and
reject some nonsensical ones.
- Sprinkle assertions and comments.
- Reduce atomic r/m/w swap operations that can just as well be
store-release.
- Ensure all access to struct wg_peer::wgp_endpoint happens while
holding a psref.
- Simplify internalize/externalize logic and be more careful about
verifying it before printing anything.
Can't release the lock here, and can't sleep waiting for the callout
while we hold it without risking deadlock. But not waiting is fine;
after we transition out of WGS_STATE_UNKNOWN the timer has no effect.