Cache struct lwip_sock* pointers at socket registration time instead of
looking them up by fd on every iteration. The previous code stored file
descriptors and called lwip_socket_dbg_get_socket(fd) on every loop
iteration to convert each fd back to a pointer — only to read a single
field from it.
- register_socket(lwip_sock*) returns bool and hooks the callback
internally — replaces the separate register_socket_fd + hook dance
- Hot loop iterates struct lwip_sock* directly instead of converting
fds each iteration
- Socket::ready() uses the cached pointer instead of fd lookup
- esphome_lwip_hook_socket() takes struct lwip_sock* directly
- esphome_lwip_socket_has_data() moved to header as static inline
for inlining — uses offset-based access verified by _Static_assert
- Null cached_sock_ on close to prevent post-close dereference
- socket_ready() tolerant of null pointer for safety
Cache struct lwip_sock* pointers at socket registration time instead of
looking them up by fd on every iteration. The previous code stored file
descriptors and called lwip_socket_dbg_get_socket(fd) on every loop
iteration to convert each fd back to a pointer — only to read a single
field from it.
- register_socket(lwip_sock*) returns bool and hooks the callback
internally — replaces the separate register_socket_fd + hook dance
- Hot loop iterates struct lwip_sock* directly instead of converting
fds each iteration
- Socket::ready() uses the cached pointer instead of fd lookup
- esphome_lwip_hook_socket() takes struct lwip_sock* directly
- esphome_lwip_socket_has_data() moved to header as static inline
for inlining — uses offset-based access verified by _Static_assert
- Null cached_sock_ on close to prevent post-close dereference
- socket_ready() tolerant of null pointer for safety
Cache struct lwip_sock* pointers at socket registration time instead of
looking them up by fd on every iteration. The previous code stored file
descriptors and called lwip_socket_dbg_get_socket(fd) on every loop
iteration to convert each fd back to a pointer — only to read a single
field from it.
- register_socket(lwip_sock*) returns bool and hooks the callback
internally — replaces the separate register_socket_fd + hook dance
- Hot loop iterates struct lwip_sock* directly instead of converting
fds each iteration
- Socket::ready() uses the cached pointer instead of fd lookup
- esphome_lwip_hook_socket() takes struct lwip_sock* directly
- esphome_lwip_socket_has_data() moved to header as static inline
for inlining — uses offset-based access verified by _Static_assert
- Null cached_sock_ on close to prevent post-close dereference
- socket_ready() tolerant of null pointer for safety
Cache struct lwip_sock* pointers at socket registration time instead of
looking them up by fd on every iteration. The previous code stored file
descriptors and called lwip_socket_dbg_get_socket(fd) on every loop
iteration to convert each fd back to a pointer — only to read a single
field from it.
- register_socket(lwip_sock*) returns bool and hooks the callback
internally — replaces the separate register_socket_fd + hook dance
- Hot loop iterates struct lwip_sock* directly instead of converting
fds each iteration
- Socket::ready() uses the cached pointer instead of fd lookup
- esphome_lwip_hook_socket() takes struct lwip_sock* directly
- esphome_lwip_socket_has_data() moved to header as static inline
for inlining — uses offset-based access verified by _Static_assert
- Null cached_sock_ on close to prevent post-close dereference
- socket_ready() tolerant of null pointer for safety
Cache struct lwip_sock* pointers at socket registration time instead of
looking them up by fd on every iteration. The previous code stored file
descriptors and called lwip_socket_dbg_get_socket(fd) on every loop
iteration to convert each fd back to a pointer — only to read a single
field from it.
- register_socket(lwip_sock*) returns bool and hooks the callback
internally — replaces the separate register_socket_fd + hook dance
- Hot loop iterates struct lwip_sock* directly instead of converting
fds each iteration
- Socket::ready() uses the cached pointer instead of fd lookup
- esphome_lwip_hook_socket() takes struct lwip_sock* directly
- esphome_lwip_socket_has_data() moved to header as static inline
for inlining — uses offset-based access verified by _Static_assert
- Null cached_sock_ on close to prevent post-close dereference
- socket_ready() tolerant of null pointer for safety
Cache struct lwip_sock* pointers at socket registration time instead of
looking them up by fd on every iteration. The previous code stored file
descriptors and called lwip_socket_dbg_get_socket(fd) on every loop
iteration to convert each fd back to a pointer — only to read a single
field from it.
- register_socket(lwip_sock*) returns bool and hooks the callback
internally — replaces the separate register_socket_fd + hook dance
- Hot loop iterates struct lwip_sock* directly instead of converting
fds each iteration
- Socket::ready() uses the cached pointer instead of fd lookup
- esphome_lwip_hook_socket() takes struct lwip_sock* directly
- esphome_lwip_socket_has_data() moved to header as static inline
for inlining — uses offset-based access verified by _Static_assert
- Null cached_sock_ on close to prevent post-close dereference
- socket_ready() tolerant of null pointer for safety
Cache struct lwip_sock* pointers at socket registration time instead of
looking them up by fd on every iteration. The previous code stored file
descriptors and called lwip_socket_dbg_get_socket(fd) on every loop
iteration to convert each fd back to a pointer — only to read a single
field from it.
- register_socket(lwip_sock*) returns bool and hooks the callback
internally — replaces the separate register_socket_fd + hook dance
- Hot loop iterates struct lwip_sock* directly instead of converting
fds each iteration
- Socket::ready() uses the cached pointer instead of fd lookup
- esphome_lwip_hook_socket() takes struct lwip_sock* directly
- esphome_lwip_socket_has_data() moved to header as static inline
for inlining — uses offset-based access verified by _Static_assert
- Null cached_sock_ on close to prevent post-close dereference
- socket_ready() tolerant of null pointer for safety
Cache struct lwip_sock* pointers at socket registration time instead of
looking them up by fd on every iteration. The previous code stored file
descriptors and called lwip_socket_dbg_get_socket(fd) on every loop
iteration to convert each fd back to a pointer — only to read a single
field from it.
- register_socket(lwip_sock*) returns bool and hooks the callback
internally — replaces the separate register_socket_fd + hook dance
- Hot loop iterates struct lwip_sock* directly instead of converting
fds each iteration
- Socket::ready() uses the cached pointer instead of fd lookup
- esphome_lwip_hook_socket() takes struct lwip_sock* directly
- esphome_lwip_socket_has_data() moved to header as static inline
for inlining — uses offset-based access verified by _Static_assert
- Null cached_sock_ on close to prevent post-close dereference
- socket_ready() tolerant of null pointer for safety
Cache struct lwip_sock* pointers at socket registration time instead of
looking them up by fd on every iteration. The previous code stored file
descriptors and called lwip_socket_dbg_get_socket(fd) on every loop
iteration to convert each fd back to a pointer — only to read a single
field from it.
- register_socket(lwip_sock*) returns bool and hooks the callback
internally — replaces the separate register_socket_fd + hook dance
- Hot loop iterates struct lwip_sock* directly instead of converting
fds each iteration
- Socket::ready() uses the cached pointer instead of fd lookup
- esphome_lwip_hook_socket() takes struct lwip_sock* directly
- esphome_lwip_socket_has_data() moved to header as static inline
for inlining — uses offset-based access verified by _Static_assert
- Null cached_sock_ on close to prevent post-close dereference
- socket_ready() tolerant of null pointer for safety
Cache struct lwip_sock* pointers at socket registration time instead of
looking them up by fd on every iteration. The previous code stored file
descriptors and called lwip_socket_dbg_get_socket(fd) on every loop
iteration to convert each fd back to a pointer — only to read a single
field from it.
- register_socket(lwip_sock*) returns bool and hooks the callback
internally — replaces the separate register_socket_fd + hook dance
- Hot loop iterates struct lwip_sock* directly instead of converting
fds each iteration
- Socket::ready() uses the cached pointer instead of fd lookup
- esphome_lwip_hook_socket() takes struct lwip_sock* directly
- esphome_lwip_socket_has_data() moved to header as static inline
for inlining — uses offset-based access verified by _Static_assert
- Null cached_sock_ on close to prevent post-close dereference
- socket_ready() tolerant of null pointer for safety
Cache struct lwip_sock* pointers at socket registration time instead of
looking them up by fd on every iteration. The previous code stored file
descriptors and called lwip_socket_dbg_get_socket(fd) on every loop
iteration to convert each fd back to a pointer — only to read a single
field from it.
- register_socket(lwip_sock*) returns bool and hooks the callback
internally — replaces the separate register_socket_fd + hook dance
- Hot loop iterates struct lwip_sock* directly instead of converting
fds each iteration
- Socket::ready() uses the cached pointer instead of fd lookup
- esphome_lwip_hook_socket() takes struct lwip_sock* directly
- Null cached_sock_ on close to prevent post-close dereference
- socket_ready() tolerant of null pointer for safety
In yield_with_select_(), the fast select path iterated all monitored
sockets and called esphome_lwip_socket_has_data(fd) for each one.
That C function called lwip_socket_dbg_get_socket(fd) — a cross-
compilation-unit call that can't be inlined because sockets[] is
static in lwip's sockets.c. The actual rcvevent check is ~4
instructions, but the lookup adds entry/retw window overhead on
Xtensa (~8-12 cycles per socket per loop iteration).
Now lwip_sock* pointers are cached at socket registration time and
stored directly in monitored_sockets_. The hot path iterates pointers
and reads rcvevent with no fd lookup. esphome_lwip_hook_socket() also
takes lwip_sock* directly, avoiding a redundant get_sock() call.
API split for fast select vs fallback select:
- register_socket(lwip_sock*) / unregister_socket(lwip_sock*)
- register_socket_fd(int fd) / unregister_socket_fd(int fd)
Chained on top of socket-devirtualize (#14398).