I learned how to use tcp_callback to use thread-unsafe function in a safe way from multiple context. Here is an example.
Thread-safe version of etharp_find_addr function (etharp_find_addrTSW) that uses tcp_callback to pass it to tcpip_thread, callback version of etharp_find_addr that actually calls etharp_find_addr and structure used to store function's arguments, return value and semaphore
/* etharp_find_addr */
typedef struct {
//arguments
struct netif *netif;
const ip4_addr_t *ipaddr;
struct eth_addr **eth_ret;
const ip4_addr_t **ip_ret;
ssize_t etharpRet; //result
osSemaphoreId_t sem; //to signal completion
} etharp_find_addrTSW_Struct;
static void etharp_find_addrTWS_Callback(void *argument) {
etharp_find_addrTSW_Struct *fStr=(etharp_find_addrTSW_Struct *)argument;
fStr->etharpRet=etharp_find_addr(fStr->netif, fStr->ipaddr, fStr->eth_ret, fStr->ip_ret);
osSemaphoreRelease(fStr->sem); // wake up the waiting task
}
ssize_t etharp_find_addrTSW(struct netif *netif, const ip4_addr_t *ipaddr, struct eth_addr **eth_ret, const ip4_addr_t **ip_ret, uint32_t timeoutMs) {
osStatus_t semReturn;
ssize_t result;
osSemaphoreAttr_t attr={
.name="etharp_find_addrTSW"
};
etharp_find_addrTSW_Struct fStr={
.netif=netif,
.ipaddr=ipaddr,
.eth_ret=eth_ret,
.ip_ret=ip_ret,
.sem=osSemaphoreNew(1, 0, &attr)
};
if (fStr.sem==NULL) {
return -1; //out of resources
}
if (tcpip_callback(etharp_find_addrTWS_Callback, &fStr) != ERR_OK) {
osSemaphoreDelete(fStr.sem);
return -1;
}
//wait for the callback to run (or timeout)
semReturn=osSemaphoreAcquire(fStr.sem, timeoutMs);
osSemaphoreDelete(fStr.sem);
if (semReturn != osOK) { // timed out before TCPIP thread could process
return -1;
}
result=fStr.etharpRet;
return result;
}
How to use:
ssize_t arpRet=etharp_find_addrTSW(NULL, &gnetif.gw, NULL, NULL, 5000);
I still don't know how to use LOCK_TCPIP_CORE() and UNLOCK_TCPIP_CORE() though.