Skip to content

Commit

Permalink
Use async context lock support
Browse files Browse the repository at this point in the history
  • Loading branch information
earlephilhower committed Sep 11, 2023
1 parent 4636b50 commit 8d98a9d
Show file tree
Hide file tree
Showing 2 changed files with 33 additions and 22 deletions.
54 changes: 33 additions & 21 deletions libraries/lwIP_Ethernet/src/LwipEthernet.cpp
Original file line number Diff line number Diff line change
@@ -1,55 +1,67 @@
/*
LwipEthernet.cpp
Handles the async context for wired Ethernet
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/

#include <LwipEthernet.h>
#include <lwip/timeouts.h>
#include <pico/mutex.h>
#include <pico/async_context_threadsafe_background.h>
#include <functional>
#include <list>


bool __lwipInitted = false;

// Protection against LWIP re-entrancy for non-PicoW case
auto_init_recursive_mutex(__ethernetMutex);
// Async context that pumps the ethernet controllers
static async_context_threadsafe_background_t lwip_ethernet_async_context_threadsafe_background;
static async_when_pending_worker_t always_pending_update_timeout_worker;
static async_at_time_worker_t ethernet_timeout_worker;

// Theoretically support multiple interfaces
static std::list<std::function<void(void)>> _handlePacketList;

void ethernet_arch_lwip_begin() {
recursive_mutex_enter_blocking(&__ethernetMutex);
async_context_acquire_lock_blocking(&lwip_ethernet_async_context_threadsafe_background.core);
}

void ethernet_arch_lwip_end() {
recursive_mutex_exit(&__ethernetMutex);
}
bool ethernet_arch_lwip_try() {
uint32_t unused;
return recursive_mutex_try_enter(&__ethernetMutex, &unused);
async_context_release_lock(&lwip_ethernet_async_context_threadsafe_background.core);
}

// Theoretically support multiple interfaces
static std::list<std::function<void(void)>> _handlePacketList;
void __addEthernetInterface(std::function<void(void)> _packet) {
_handlePacketList.push_back(_packet);
}

// Async context that pumps the ethernet controllers
static async_context_threadsafe_background_t lwip_ethernet_async_context_threadsafe_background;
static async_when_pending_worker_t always_pending_update_timeout_worker;
static async_at_time_worker_t ethernet_timeout_worker;

async_context_t *lwip_ethernet_init_default_async_context(void) {
static async_context_t *lwip_ethernet_init_default_async_context(void) {
async_context_threadsafe_background_config_t config = async_context_threadsafe_background_default_config();
if (async_context_threadsafe_background_init(&lwip_ethernet_async_context_threadsafe_background, &config)) {
return &lwip_ethernet_async_context_threadsafe_background.core;
}
return NULL;
}

// This will only be called under the protection of the async context mutex, so no re-entrancy checks needed
static void ethernet_timeout_reached(__unused async_context_t *context, __unused async_at_time_worker_t *worker) {
assert(worker == &ethernet_timeout_worker);
for (auto handlePacket : _handlePacketList) {
handlePacket();
}
if (ethernet_arch_lwip_try()) {
sys_check_timeouts();
ethernet_arch_lwip_end();
}
sys_check_timeouts();
}

static void update_next_timeout(async_context_t *context, async_when_pending_worker_t *worker) {
Expand Down
1 change: 0 additions & 1 deletion libraries/lwIP_Ethernet/src/LwipEthernet.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@

void ethernet_arch_lwip_begin() __attribute__((weak));
void ethernet_arch_lwip_end() __attribute__((weak));
bool ethernet_arch_lwip_try() __attribute__((weak));

// Internal Ethernet helper functions
void __addEthernetInterface(std::function<void(void)> _packetHandler);
Expand Down

0 comments on commit 8d98a9d

Please sign in to comment.