/* * * Copyright (c) 2023 Project CHIP Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include #include #include namespace chip { namespace Inet { err_t EndPointStateLwIP::RunOnTCPIPRet(std::function fn) { assertChipStackLockedByCurrentThread(); #if LWIP_TCPIP_CORE_LOCKING err_t err; LOCK_TCPIP_CORE(); err = fn(); UNLOCK_TCPIP_CORE(); return err; #else // Post a message to the TCPIP task and wait for it to run. static sys_sem_t sTCPIPSem; static bool sTCPIPSemInited = false; if (!sTCPIPSemInited) { err_t err = sys_sem_new(&sTCPIPSem, 0); if (err != ERR_OK) { return err; } sTCPIPSemInited = true; } // tcpip_callback takes a C function pointer, so we can't pass a capturing lambda to it. // Just store the state the function we pass to it needs in statics. // This should be safe, since that function will execute before we return and there is no // re-entry into this method. static std::function sTCPIPFunction; static err_t sTCPIPFunctionResult; VerifyOrDie(sTCPIPFunction == nullptr); sTCPIPFunction = fn; const err_t err = tcpip_callback( [](void * aCtx) { sTCPIPFunctionResult = sTCPIPFunction(); sys_sem_signal(&sTCPIPSem); }, nullptr); if (err != ERR_OK) { return err; } sys_arch_sem_wait(&sTCPIPSem, 0); sTCPIPFunction = nullptr; return sTCPIPFunctionResult; #endif } void EndPointStateLwIP::RunOnTCPIP(std::function fn) { VerifyOrDie(RunOnTCPIPRet([&fn]() { fn(); return ERR_OK; }) == ERR_OK); } } // namespace Inet } // namespace chip