diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-11 08:17:27 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-11 08:17:27 +0000 |
commit | f215e02bf85f68d3a6106c2a1f4f7f063f819064 (patch) | |
tree | 6bb5b92c046312c4e95ac2620b10ddf482d3fa8b /src/VBox/Devices/Network/lwip-new/vbox/sys_arch.c | |
parent | Initial commit. (diff) | |
download | virtualbox-f215e02bf85f68d3a6106c2a1f4f7f063f819064.tar.xz virtualbox-f215e02bf85f68d3a6106c2a1f4f7f063f819064.zip |
Adding upstream version 7.0.14-dfsg.upstream/7.0.14-dfsg
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to '')
-rw-r--r-- | src/VBox/Devices/Network/lwip-new/vbox/sys_arch.c | 583 |
1 files changed, 583 insertions, 0 deletions
diff --git a/src/VBox/Devices/Network/lwip-new/vbox/sys_arch.c b/src/VBox/Devices/Network/lwip-new/vbox/sys_arch.c new file mode 100644 index 00000000..d04c03ab --- /dev/null +++ b/src/VBox/Devices/Network/lwip-new/vbox/sys_arch.c @@ -0,0 +1,583 @@ +/** $Id: sys_arch.c $ */ +/** @file + * System dependent parts of lwIP, implemented with IPRT. + */ + +/* + * Copyright (C) 2007-2023 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program 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 + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * SPDX-License-Identifier: GPL-3.0-only + */ + + +#include <lwip/sys.h> + +#include <iprt/assert.h> +#include <iprt/errcore.h> +#include <iprt/mem.h> +#include <iprt/string.h> +#include <iprt/critsect.h> +#include <iprt/thread.h> +#include <iprt/time.h> + +/** @todo during my tests on Debian Lenny 64 bit I ran into trouble using + * mutex semaphores (crash deep down in the pthreads lib). Using the write + * case of rw semaphores also gives mutual exclusion, and didn't show those + * crashes. Should be investigated, because this "fix" might be just covering + * the symptoms of a bug elsewhere. */ +#if HC_ARCH_BITS == 64 && defined RT_ARCH_LINUX +#define LWIPMUTEXTYPE RTSEMRW +#define LWIPMutexCreate RTSemRWCreate +#define LWIPMutexDestroy RTSemRWDestroy +#define LWIPMutexRequest(m) RTSemRWRequestWrite((m), RT_INDEFINITE_WAIT) +#define LWIPMutexRelease RTSemRWReleaseWrite +#else +#define LWIPMUTEXTYPE RTSEMMUTEX +#define LWIPMutexCreate RTSemMutexCreate +#define LWIPMutexDestroy RTSemMutexDestroy +#define LWIPMutexRequest(m) RTSemMutexRequest((m), RT_INDEFINITE_WAIT) +#define LWIPMutexRelease RTSemMutexRelease +#endif + +/** Maximum number of threads lwIP is allowed to create. */ +#define THREADS_MAX 5 + +/** Maximum number of mbox entries needed for reasonable performance. */ +#define MBOX_ENTRIES_MAX 128 + +/** Data type for slots in TLS. */ +typedef struct +{ + RTTHREAD tid; + void (* thread)(void *arg); + void *arg; +#if 0 + struct sys_timeouts timeouts; +#endif +} THREADLOCALSTORAGE; + +/** Actual declaration of the mbox type. */ +/** @todo magic - ??? */ +struct sys_mbox +{ + LWIPMUTEXTYPE mutex; + RTSEMEVENTMULTI nonempty, nonfull; + void *apvEntries[MBOX_ENTRIES_MAX]; + u32_t head, tail; + int valid; +}; + +#if SYS_LIGHTWEIGHT_PROT +/** Critical section variable for short term synchronization. */ +static RTCRITSECT g_ProtCritSect; +#else +/** Synchronization for thread creation handling. */ +static RTSEMEVENT g_ThreadSem; +#endif + +/** Number of threads currently created by lwIP. */ +static u32_t g_cThreads = 2; + +/** The simulated thread local storage for lwIP things. */ +static THREADLOCALSTORAGE g_aTLS[THREADS_MAX]; + +/** + * Initialize the port to IPRT. + */ +void sys_init(void) +{ + int rc; + unsigned i; +#if SYS_LIGHTWEIGHT_PROT + rc = RTCritSectInit(&g_ProtCritSect); + AssertRC(rc); +#else + rc = RTSemEventCreate(&g_ThreadSem); + AssertRC(rc); + rc = RTSemEventSignal(g_ThreadSem); + AssertRC(rc); +#endif + for (i = 0; i < THREADS_MAX; i++) + g_aTLS[i].tid = NIL_RTTHREAD; +} + +/** + * Create a new (binary) semaphore. + */ +err_t sys_sem_new(sys_sem_t *pSem, u8_t count) +{ + int rc; + err_t rcLwip = ERR_ARG; + + if (!pSem) + return ERR_ARG; + Assert(count <= 1); + rc = RTSemEventCreate(pSem); + AssertRCReturn(rc, ERR_ARG); + rcLwip = ERR_OK; + if (count == 1) + { + rc = RTSemEventSignal(*pSem); + AssertRCReturn(rc, ERR_VAL); + } + return rcLwip; +} + +/** + * Destroy a (binary) semaphore. + */ +void sys_sem_free(sys_sem_t *sem) +{ + int rc; + rc = RTSemEventDestroy(*sem); + AssertRC(rc); +} + +/** + * Signal a (binary) semaphore. + */ +void sys_sem_signal(sys_sem_t *sem) +{ + int rc; + rc = RTSemEventSignal(*sem); + AssertRC(rc); +} + +/** + * Wait for a (binary) semaphore. + */ +u32_t sys_arch_sem_wait(sys_sem_t *sem, u32_t timeout) +{ + int rc; + RTMSINTERVAL cMillies; + uint64_t tsStart, tsEnd; + + tsStart = RTTimeMilliTS(); + if (timeout == 0) + cMillies = RT_INDEFINITE_WAIT; + else + cMillies = timeout; + rc = RTSemEventWait(*sem, cMillies); + if (rc == VERR_TIMEOUT) + return SYS_ARCH_TIMEOUT; + AssertRC(rc); + tsEnd = RTTimeMilliTS(); + return tsEnd - tsStart; +} + +/** + * Create new mbox. + */ +err_t sys_mbox_new(sys_mbox_t *pvMbox, int size) +{ + int rc; + struct sys_mbox *mbox = NULL; + RT_NOREF(size); /** @todo safe to ignore this? */ + + if (pvMbox == NULL) + return ERR_ARG; + mbox = RTMemAllocZ(sizeof(struct sys_mbox)); + Assert(mbox != NULL); + if (!mbox) + return ERR_MEM; + rc = LWIPMutexCreate(&mbox->mutex); + AssertRC(rc); + if (RT_FAILURE(rc)) + { + RTMemFree(mbox); + return ERR_VAL; + } + rc = RTSemEventMultiCreate(&mbox->nonempty); + AssertRC(rc); + if (RT_FAILURE(rc)) + { + rc = LWIPMutexDestroy(mbox->mutex); + AssertRC(rc); + RTMemFree(mbox); + return ERR_VAL; + } + rc = RTSemEventMultiCreate(&mbox->nonfull); + AssertRC(rc); + if (RT_FAILURE(rc)) + { + rc = RTSemEventMultiDestroy(mbox->nonempty); + AssertRC(rc); + rc = LWIPMutexDestroy(mbox->mutex); + AssertRC(rc); + RTMemFree(mbox); + return ERR_VAL; + } + mbox->valid = 1; + *pvMbox = mbox; + return ERR_OK; +} + +/** + * Free an mbox. + */ +void sys_mbox_free(sys_mbox_t *pvMbox) +{ + struct sys_mbox *mbox = NULL; + Assert(pvMbox && *pvMbox); + mbox = (struct sys_mbox*)*pvMbox; + LWIPMutexDestroy((mbox)->mutex); + RTSemEventMultiDestroy((mbox)->nonempty); + RTSemEventMultiDestroy((mbox)->nonfull); + RTMemFree(mbox); + *pvMbox = NULL; +} + +/** + * Place an entry in an mbox, waiting for a free slot if necessary. + */ +void sys_mbox_post(sys_mbox_t *pvMbox, void *msg) +{ + int rc; + struct sys_mbox *mbox = NULL; + Assert(pvMbox && *pvMbox); + mbox = (struct sys_mbox*)*pvMbox; + + rc = LWIPMutexRequest((mbox)->mutex); + AssertRC(rc); + + while (((mbox)->head + 1) % MBOX_ENTRIES_MAX == (mbox)->tail) + { + /* (mbox) is full, have to wait until a slot becomes available. */ + rc = LWIPMutexRelease((mbox)->mutex); + AssertRC(rc); + + rc = RTSemEventMultiWait((mbox)->nonfull, RT_INDEFINITE_WAIT); + AssertRC(rc); + + rc = LWIPMutexRequest((mbox)->mutex); + AssertRC(rc); + } + + if ((mbox)->head == (mbox)->tail) + { + rc = RTSemEventMultiSignal((mbox)->nonempty); + AssertRC(rc); + } + (mbox)->apvEntries[(mbox)->head] = msg; + (mbox)->head++; + (mbox)->head %= MBOX_ENTRIES_MAX; + if (((mbox)->head + 1) % MBOX_ENTRIES_MAX == (mbox)->tail) + { + rc = RTSemEventMultiReset((mbox)->nonfull); + AssertRC(rc); + } + rc = LWIPMutexRelease((mbox)->mutex); + AssertRC(rc); +} + + +/** + * Try to place an entry in an mbox if there is a free slot. + */ +err_t sys_mbox_trypost(sys_mbox_t *pvMbox, void *msg) +{ + int rc; + struct sys_mbox *mbox = NULL; + AssertReturn(pvMbox && *pvMbox, ERR_ARG); + mbox = (struct sys_mbox*)*pvMbox; + + rc = LWIPMutexRequest((mbox)->mutex); + AssertRC(rc); + + if (((mbox)->head + 1) % MBOX_ENTRIES_MAX == (mbox)->tail) + { + /* (mbox) is full */ + rc = LWIPMutexRelease((mbox)->mutex); + AssertRC(rc); + return ERR_MEM; + } + + if ((mbox)->head == (mbox)->tail) + { + rc = RTSemEventMultiSignal((mbox)->nonempty); + AssertRC(rc); + } + (mbox)->apvEntries[(mbox)->head] = msg; + (mbox)->head++; + (mbox)->head %= MBOX_ENTRIES_MAX; + if (((mbox)->head + 1) % MBOX_ENTRIES_MAX == (mbox)->tail) + { + rc = RTSemEventMultiReset((mbox)->nonfull); + AssertRC(rc); + } + rc = LWIPMutexRelease((mbox)->mutex); + AssertRC(rc); + return ERR_OK; +} + + +/** + * Get an entry from an mbox. + */ +u32_t sys_arch_mbox_fetch(sys_mbox_t *pvMbox, void **msg, u32_t timeout) +{ + int rc; + RTMSINTERVAL cMillies; + uint64_t tsStart, tsEnd; + struct sys_mbox *mbox = NULL; + + if (!pvMbox || !*pvMbox) return 0; + mbox = (struct sys_mbox*)*pvMbox; + + tsStart = RTTimeMilliTS(); + if (timeout == 0) + cMillies = RT_INDEFINITE_WAIT; + else + cMillies = timeout; + + rc = LWIPMutexRequest((mbox)->mutex); + AssertRC(rc); + while ((mbox)->head == (mbox)->tail) + { + /* (mbox) is empty, have to wait until a slot is filled. */ + rc = LWIPMutexRelease((mbox)->mutex); + AssertRC(rc); + if (timeout != 0) + { + tsEnd = RTTimeMilliTS(); + if (tsEnd - tsStart >= cMillies) + return SYS_ARCH_TIMEOUT; + cMillies -= tsEnd - tsStart; + } + rc = RTSemEventMultiWait((mbox)->nonempty, cMillies); + if (rc == VERR_TIMEOUT) + return SYS_ARCH_TIMEOUT; + AssertRC(rc); + if (timeout != 0) + { + tsEnd = RTTimeMilliTS(); + if (tsEnd - tsStart >= cMillies) + return SYS_ARCH_TIMEOUT; + cMillies -= tsEnd - tsStart; + } + rc = LWIPMutexRequest((mbox)->mutex); + AssertRC(rc); + } + if (((mbox)->head + 1) % MBOX_ENTRIES_MAX == (mbox)->tail) + { + rc = RTSemEventMultiSignal((mbox)->nonfull); + AssertRC(rc); + } + if (msg != NULL) + *msg = (mbox)->apvEntries[(mbox)->tail]; + (mbox)->tail++; + (mbox)->tail %= MBOX_ENTRIES_MAX; + rc = RTSemEventMultiSignal((mbox)->nonfull); + if ((mbox)->head == (mbox)->tail) + { + rc = RTSemEventMultiReset((mbox)->nonempty); + AssertRC(rc); + } + rc = LWIPMutexRelease((mbox)->mutex); + AssertRC(rc); + tsEnd = RTTimeMilliTS(); + return tsEnd - tsStart; +} + +/** + * Try to get an entry from an mbox. + */ +u32_t sys_arch_mbox_tryfetch(sys_mbox_t *pvMbox, void **msg) +{ + int rc; + struct sys_mbox *mbox = NULL; + if (!pvMbox || !*pvMbox) return SYS_MBOX_EMPTY; + mbox = (struct sys_mbox*)*pvMbox; + + rc = LWIPMutexRequest((mbox)->mutex); + AssertRC(rc); + if ((mbox)->head == (mbox)->tail) + { + /* (mbox) is empty, don't wait */ + rc = LWIPMutexRelease((mbox)->mutex); + AssertRC(rc); + return SYS_MBOX_EMPTY; + } + if (((mbox)->head + 1) % MBOX_ENTRIES_MAX == (mbox)->tail) + { + rc = RTSemEventMultiSignal((mbox)->nonfull); + AssertRC(rc); + } + if (msg != NULL) + *msg = (mbox)->apvEntries[(mbox)->tail]; + (mbox)->tail++; + (mbox)->tail %= MBOX_ENTRIES_MAX; + rc = RTSemEventMultiSignal((mbox)->nonfull); + if ((mbox)->head == (mbox)->tail) + { + rc = RTSemEventMultiReset((mbox)->nonempty); + AssertRC(rc); + } + rc = LWIPMutexRelease((mbox)->mutex); + AssertRC(rc); + return 0; +} + +/** Check if an mbox is valid/allocated: return 1 for valid, 0 for invalid */ +int sys_mbox_valid(sys_mbox_t *pvMbox) +{ + struct sys_mbox *mbox = NULL; + if (!pvMbox || !*pvMbox) return 0; + mbox = (struct sys_mbox*)*pvMbox; + return (mbox)->valid; +} + +/** Set an mbox invalid so that sys_mbox_valid returns 0 */ +void sys_mbox_set_invalid(sys_mbox_t *pvMbox) +{ + struct sys_mbox *mbox = NULL; + if (!pvMbox || !*pvMbox) + return; + mbox = (struct sys_mbox *)*pvMbox; + mbox->valid = 0; +} + +#if 0 +/** + * Grab the pointer to this thread's timeouts from TLS. + */ +struct sys_timeouts *sys_arch_timeouts(void) +{ + unsigned i; +#if SYS_LIGHTWEIGHT_PROT + SYS_ARCH_DECL_PROTECT(old_level); +#endif + RTTHREAD myself; + struct sys_timeouts *to = NULL; + + myself = RTThreadSelf(); +#if SYS_LIGHTWEIGHT_PROT + SYS_ARCH_PROTECT(old_level); +#else + RTSemEventWait(g_ThreadSem, RT_INDEFINITE_WAIT); +#endif + for (i = 0; i < g_cThreads; i++) + { + if (g_aTLS[i].tid == myself) + { + to = &g_aTLS[i].timeouts; + break; + } + } + /* Auto-adopt new threads which use lwIP as they pop up. */ + if (!to) + { + unsigned id; + id = g_cThreads; + g_cThreads++; + Assert(g_cThreads <= THREADS_MAX); + g_aTLS[id].tid = myself; + to = &g_aTLS[id].timeouts; + } +#if SYS_LIGHTWEIGHT_PROT + SYS_ARCH_UNPROTECT(old_level); +#else + RTSemEventSignal(g_ThreadSem); +#endif + return to; +} +#endif + +/** + * Internal: thread main function adapter, dropping the first parameter. Needed + * to make lwip thread main function compatible with IPRT thread main function. + */ +static DECLCALLBACK(int) sys_thread_adapter(RTTHREAD hThreadSelf, void *pvUser) +{ + THREADLOCALSTORAGE *tls = (THREADLOCALSTORAGE *)pvUser; + RT_NOREF(hThreadSelf); + + tls->thread(tls->arg); + + return VINF_SUCCESS; +} + +/** + * Create new thread. + */ +sys_thread_t sys_thread_new(const char*name, lwip_thread_fn thread, void *arg, int stacksize, int prio) +{ + int rc; +#if SYS_LIGHTWEIGHT_PROT + SYS_ARCH_DECL_PROTECT(old_level); +#endif + unsigned id; + RTTHREAD tid; + + RT_NOREF(prio, stacksize, name); + +#if SYS_LIGHTWEIGHT_PROT + SYS_ARCH_PROTECT(old_level); +#else + RTSemEventWait(g_ThreadSem, RT_INDEFINITE_WAIT); +#endif + id = g_cThreads; + g_cThreads++; + Assert(g_cThreads <= THREADS_MAX); + g_aTLS[id].thread = thread; + g_aTLS[id].arg = arg; + rc = RTThreadCreateF(&tid, sys_thread_adapter, &g_aTLS[id], 0, + RTTHREADTYPE_IO, 0, "lwIP%u", id); + if (RT_FAILURE(rc)) + { + g_cThreads--; + tid = NIL_RTTHREAD; + } + else + g_aTLS[id].tid = tid; +#if SYS_LIGHTWEIGHT_PROT + SYS_ARCH_UNPROTECT(old_level); +#else + RTSemEventSignal(g_ThreadSem); +#endif + AssertRC(rc); + return tid; +} + +#if SYS_LIGHTWEIGHT_PROT +/** + * Start a short critical section. + */ +sys_prot_t sys_arch_protect(void) +{ + int rc; + rc = RTCritSectEnter(&g_ProtCritSect); + AssertRC(rc); + return NULL; +} +#endif + +#if SYS_LIGHTWEIGHT_PROT +/** + * End a short critical section. + */ +void sys_arch_unprotect(sys_prot_t pval) +{ + int rc; + (void)pval; + rc = RTCritSectLeave(&g_ProtCritSect); + AssertRC(rc); +} +#endif + |