123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406 |
- /****************************************************************************
- * net/utils/net_lock.c
- *
- * Copyright (C) 2011-2012, 2014-2018 Gregory Nutt. All rights reserved.
- * Author: Gregory Nutt <gnutt@nuttx.org>
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- * 3. Neither the name NuttX nor the names of its contributors may be
- * used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
- * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
- * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
- * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
- * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
- * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
- * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
- *
- ****************************************************************************/
- /****************************************************************************
- * Included Files
- ****************************************************************************/
- #include <nuttx/config.h>
- #include <unistd.h>
- #include <semaphore.h>
- #include <assert.h>
- #include <errno.h>
- #include <debug.h>
- #include <nuttx/irq.h>
- #include <nuttx/arch.h>
- #include <nuttx/semaphore.h>
- #include <nuttx/mm/iob.h>
- #include <nuttx/net/net.h>
- #include "utils/utils.h"
- /****************************************************************************
- * Pre-processor Definitions
- ****************************************************************************/
- #define NO_HOLDER (pid_t)-1
- /****************************************************************************
- * Private Data
- ****************************************************************************/
- static sem_t g_netlock;
- static pid_t g_holder = NO_HOLDER;
- static unsigned int g_count = 0;
- /****************************************************************************
- * Private Functions
- ****************************************************************************/
- /****************************************************************************
- * Name: _net_takesem
- *
- * Description:
- * Take the semaphore, waiting indefinitely.
- * REVISIT: Should this return if -EINTR?
- *
- ****************************************************************************/
- static void _net_takesem(void)
- {
- int ret;
- do
- {
- /* Take the semaphore (perhaps waiting) */
- ret = nxsem_wait(&g_netlock);
- /* The only case that an error should occur here is if the wait was
- * awakened by a signal.
- */
- DEBUGASSERT(ret == OK || ret == -EINTR);
- }
- while (ret == -EINTR);
- }
- /****************************************************************************
- * Public Functions
- ****************************************************************************/
- /****************************************************************************
- * Name: net_lockinitialize
- *
- * Description:
- * Initialize the locking facility
- *
- ****************************************************************************/
- void net_lockinitialize(void)
- {
- nxsem_init(&g_netlock, 0, 1);
- }
- /****************************************************************************
- * Name: net_lock
- *
- * Description:
- * Take the network lock
- *
- * Input Parameters:
- * None
- *
- * Returned Value:
- * None
- *
- ****************************************************************************/
- void net_lock(void)
- {
- #ifdef CONFIG_SMP
- irqstate_t flags = enter_critical_section();
- #endif
- pid_t me = getpid();
- /* Does this thread already hold the semaphore? */
- if (g_holder == me)
- {
- /* Yes.. just increment the reference count */
- g_count++;
- }
- else
- {
- /* No.. take the semaphore (perhaps waiting) */
- _net_takesem();
- /* Now this thread holds the semaphore */
- g_holder = me;
- g_count = 1;
- }
- #ifdef CONFIG_SMP
- leave_critical_section(flags);
- #endif
- }
- /****************************************************************************
- * Name: net_unlock
- *
- * Description:
- * Release the network lock.
- *
- * Input Parameters:
- * None
- *
- * Returned Value:
- * None
- *
- ****************************************************************************/
- void net_unlock(void)
- {
- #ifdef CONFIG_SMP
- irqstate_t flags = enter_critical_section();
- #endif
- DEBUGASSERT(g_holder == getpid() && g_count > 0);
- /* If the count would go to zero, then release the semaphore */
- if (g_count == 1)
- {
- /* We no longer hold the semaphore */
- g_holder = NO_HOLDER;
- g_count = 0;
- nxsem_post(&g_netlock);
- }
- else
- {
- /* We still hold the semaphore. Just decrement the count */
- g_count--;
- }
- #ifdef CONFIG_SMP
- leave_critical_section(flags);
- #endif
- }
- /****************************************************************************
- * Name: net_breaklock
- *
- * Description:
- * Break the lock, return information needed to restore re-entrant lock
- * state.
- *
- ****************************************************************************/
- int net_breaklock(FAR unsigned int *count)
- {
- irqstate_t flags;
- pid_t me = getpid();
- int ret = -EPERM;
- DEBUGASSERT(count != NULL);
- flags = enter_critical_section(); /* No interrupts */
- if (g_holder == me)
- {
- /* Return the lock setting */
- *count = g_count;
- /* Release the network lock */
- g_holder = NO_HOLDER;
- g_count = 0;
- (void)nxsem_post(&g_netlock);
- ret = OK;
- }
- leave_critical_section(flags);
- return ret;
- }
- /****************************************************************************
- * Name: net_breaklock
- *
- * Description:
- * Restore the locked state
- *
- ****************************************************************************/
- void net_restorelock(unsigned int count)
- {
- pid_t me = getpid();
- DEBUGASSERT(g_holder != me);
- /* Recover the network lock at the proper count */
- _net_takesem();
- g_holder = me;
- g_count = count;
- }
- /****************************************************************************
- * Name: net_timedwait
- *
- * Description:
- * Atomically wait for sem (or a timeout( while temporarily releasing
- * the lock on the network.
- *
- * Caution should be utilized. Because the network lock is relinquished
- * during the wait, there could changes in the network state that occur
- * before the lock is recovered. Your design should account for this
- * possibility.
- *
- * Input Parameters:
- * sem - A reference to the semaphore to be taken.
- * abstime - The absolute time to wait until a timeout is declared.
- *
- * Returned Value:
- * Zero (OK) is returned on success; a negated errno value is returned on
- * any failure.
- *
- ****************************************************************************/
- int net_timedwait(sem_t *sem, FAR const struct timespec *abstime)
- {
- unsigned int count;
- irqstate_t flags;
- int blresult;
- int ret;
- flags = enter_critical_section(); /* No interrupts */
- sched_lock(); /* No context switches */
- /* Release the network lock, remembering my count. net_breaklock will
- * return a negated value if the caller does not hold the network lock.
- */
- blresult = net_breaklock(&count);
- /* Now take the semaphore, waiting if so requested. */
- if (abstime != NULL)
- {
- /* Wait until we get the lock or until the timeout expires */
- ret = nxsem_timedwait(sem, abstime);
- }
- else
- {
- /* Wait as long as necessary to get the lock */
- ret = nxsem_wait(sem);
- }
- /* Recover the network lock at the proper count (if we held it before) */
- if (blresult >= 0)
- {
- net_restorelock(count);
- }
- sched_unlock();
- leave_critical_section(flags);
- return ret;
- }
- /****************************************************************************
- * Name: net_lockedwait
- *
- * Description:
- * Atomically wait for sem while temporarily releasing the network lock.
- *
- * Caution should be utilized. Because the network lock is relinquished
- * during the wait, there could changes in the network state that occur
- * before the lock is recovered. Your design should account for this
- * possibility.
- *
- * Input Parameters:
- * sem - A reference to the semaphore to be taken.
- *
- * Returned Value:
- * Zero (OK) is returned on success; a negated errno value is returned on
- * any failure.
- *
- ****************************************************************************/
- int net_lockedwait(sem_t *sem)
- {
- return net_timedwait(sem, NULL);
- }
- /****************************************************************************
- * Name: net_ioballoc
- *
- * Description:
- * Allocate an IOB. If no IOBs are available, then atomically wait for
- * for the IOB while temporarily releasing the lock on the network.
- *
- * Caution should be utilized. Because the network lock is relinquished
- * during the wait, there could changes in the network state that occur
- * before the lock is recovered. Your design should account for this
- * possibility.
- *
- * Input Parameters:
- * throttled - An indication of the IOB allocation is "throttled"
- *
- * Returned Value:
- * A pointer to the newly allocated IOB is returned on success. NULL is
- * returned on any allocation failure.
- *
- ****************************************************************************/
- #ifdef CONFIG_MM_IOB
- FAR struct iob_s *net_ioballoc(bool throttled)
- {
- FAR struct iob_s *iob;
- iob = iob_tryalloc(throttled);
- if (iob == NULL)
- {
- irqstate_t flags;
- unsigned int count;
- int blresult;
- /* There are no buffers available now. We will have to wait for one to
- * become available. But let's not do that with the network locked.
- */
- flags = enter_critical_section();
- blresult = net_breaklock(&count);
- iob = iob_alloc(throttled);
- if (blresult >= 0)
- {
- net_restorelock(count);
- }
- leave_critical_section(flags);
- }
- return iob;
- }
- #endif
|