There is no reason for the DPDK libraries to all have 'librte_' prefix on the directory names. This prefix makes the directory names longer and also makes it awkward to add features referring to individual libraries in the build - should the lib names be specified with or without the prefix. Therefore, we can just remove the library prefix and use the library's unique name as the directory name, i.e. 'eal' rather than 'librte_eal' Signed-off-by: Bruce Richardson <bruce.richardson@intel.com>
206 lines
4.6 KiB
C
206 lines
4.6 KiB
C
/* SPDX-License-Identifier: BSD-3-Clause
|
|
* Copyright(c) 2021 Microsoft Corp.
|
|
* All rights reserved.
|
|
*
|
|
* Derived from Concurrency Kit
|
|
* Copyright 2011-2015 Samy Al Bahra.
|
|
*/
|
|
|
|
#ifndef _RTE_PFLOCK_H_
|
|
#define _RTE_PFLOCK_H_
|
|
|
|
/**
|
|
* @file
|
|
*
|
|
* Phase-fair locks
|
|
*
|
|
* This file defines an API for phase-fair reader writer locks,
|
|
* which is a variant of typical reader-writer locks that prevent
|
|
* starvation. In this type of lock, readers and writers alternate.
|
|
* This significantly reduces the worst-case blocking for readers and writers.
|
|
*
|
|
* This is an implementation derived from FreeBSD
|
|
* based on the work described in:
|
|
* Brandenburg, B. and Anderson, J. 2010. Spin-Based
|
|
* Reader-Writer Synchronization for Multiprocessor Real-Time Systems
|
|
*
|
|
* All locks must be initialised before use, and only initialised once.
|
|
*/
|
|
|
|
#ifdef __cplusplus
|
|
extern "C" {
|
|
#endif
|
|
|
|
#include <rte_common.h>
|
|
#include <rte_pause.h>
|
|
|
|
/**
|
|
* The rte_pflock_t type.
|
|
*/
|
|
struct rte_pflock {
|
|
struct {
|
|
uint16_t in;
|
|
uint16_t out;
|
|
} rd, wr;
|
|
};
|
|
typedef struct rte_pflock rte_pflock_t;
|
|
|
|
/*
|
|
* Allocation of bits to reader
|
|
*
|
|
* 15 4 3 2 1 0
|
|
* +-------------------+---+-+-+
|
|
* | rin: reads issued |x|x| | |
|
|
* +-------------------+---+-+-+
|
|
* ^ ^
|
|
* | |
|
|
* PRES: writer present ----/ |
|
|
* PHID: writer phase id -----/
|
|
*
|
|
* 15 4 3 2 1 0
|
|
* +------------------+------+
|
|
* |rout:read complete|unused|
|
|
* +------------------+------+
|
|
*
|
|
* The maximum number of readers is 4095
|
|
*/
|
|
|
|
/* Constants used to map the bits in reader counter */
|
|
#define RTE_PFLOCK_WBITS 0x3 /* Writer bits in reader. */
|
|
#define RTE_PFLOCK_PRES 0x2 /* Writer present bit. */
|
|
#define RTE_PFLOCK_PHID 0x1 /* Phase ID bit. */
|
|
#define RTE_PFLOCK_LSB 0xFFF0 /* reader bits. */
|
|
#define RTE_PFLOCK_RINC 0x10 /* Reader increment. */
|
|
|
|
/**
|
|
* A static pflock initializer.
|
|
*/
|
|
#define RTE_PFLOCK_INITIALIZER { }
|
|
|
|
/**
|
|
* @warning
|
|
* @b EXPERIMENTAL: this API may change without prior notice.
|
|
*
|
|
* Initialize the pflock to an unlocked state.
|
|
*
|
|
* @param pf
|
|
* A pointer to the pflock.
|
|
*/
|
|
__rte_experimental
|
|
static inline void
|
|
rte_pflock_init(struct rte_pflock *pf)
|
|
{
|
|
pf->rd.in = 0;
|
|
pf->rd.out = 0;
|
|
pf->wr.in = 0;
|
|
pf->wr.out = 0;
|
|
}
|
|
|
|
/**
|
|
* @warning
|
|
* @b EXPERIMENTAL: this API may change without prior notice.
|
|
*
|
|
* Take a pflock for read.
|
|
*
|
|
* @param pf
|
|
* A pointer to a pflock structure.
|
|
*/
|
|
__rte_experimental
|
|
static inline void
|
|
rte_pflock_read_lock(rte_pflock_t *pf)
|
|
{
|
|
uint16_t w;
|
|
|
|
/*
|
|
* If no writer is present, then the operation has completed
|
|
* successfully.
|
|
*/
|
|
w = __atomic_fetch_add(&pf->rd.in, RTE_PFLOCK_RINC, __ATOMIC_ACQUIRE)
|
|
& RTE_PFLOCK_WBITS;
|
|
if (w == 0)
|
|
return;
|
|
|
|
/* Wait for current write phase to complete. */
|
|
while ((__atomic_load_n(&pf->rd.in, __ATOMIC_ACQUIRE)
|
|
& RTE_PFLOCK_WBITS) == w)
|
|
rte_pause();
|
|
}
|
|
|
|
/**
|
|
* @warning
|
|
* @b EXPERIMENTAL: this API may change without prior notice.
|
|
*
|
|
* Release a pflock locked for reading.
|
|
*
|
|
* @param pf
|
|
* A pointer to the pflock structure.
|
|
*/
|
|
__rte_experimental
|
|
static inline void
|
|
rte_pflock_read_unlock(rte_pflock_t *pf)
|
|
{
|
|
__atomic_fetch_add(&pf->rd.out, RTE_PFLOCK_RINC, __ATOMIC_RELEASE);
|
|
}
|
|
|
|
/**
|
|
* @warning
|
|
* @b EXPERIMENTAL: this API may change without prior notice.
|
|
*
|
|
* Take the pflock for write.
|
|
*
|
|
* @param pf
|
|
* A pointer to the pflock structure.
|
|
*/
|
|
__rte_experimental
|
|
static inline void
|
|
rte_pflock_write_lock(rte_pflock_t *pf)
|
|
{
|
|
uint16_t ticket, w;
|
|
|
|
/* Acquire ownership of write-phase.
|
|
* This is same as rte_tickelock_lock().
|
|
*/
|
|
ticket = __atomic_fetch_add(&pf->wr.in, 1, __ATOMIC_RELAXED);
|
|
rte_wait_until_equal_16(&pf->wr.out, ticket, __ATOMIC_ACQUIRE);
|
|
|
|
/*
|
|
* Acquire ticket on read-side in order to allow them
|
|
* to flush. Indicates to any incoming reader that a
|
|
* write-phase is pending.
|
|
*
|
|
* The load of rd.out in wait loop could be executed
|
|
* speculatively.
|
|
*/
|
|
w = RTE_PFLOCK_PRES | (ticket & RTE_PFLOCK_PHID);
|
|
ticket = __atomic_fetch_add(&pf->rd.in, w, __ATOMIC_RELAXED);
|
|
|
|
/* Wait for any pending readers to flush. */
|
|
rte_wait_until_equal_16(&pf->rd.out, ticket, __ATOMIC_ACQUIRE);
|
|
}
|
|
|
|
/**
|
|
* @warning
|
|
* @b EXPERIMENTAL: this API may change without prior notice.
|
|
*
|
|
* Release a pflock held for writing.
|
|
*
|
|
* @param pf
|
|
* A pointer to a pflock structure.
|
|
*/
|
|
__rte_experimental
|
|
static inline void
|
|
rte_pflock_write_unlock(rte_pflock_t *pf)
|
|
{
|
|
/* Migrate from write phase to read phase. */
|
|
__atomic_fetch_and(&pf->rd.in, RTE_PFLOCK_LSB, __ATOMIC_RELEASE);
|
|
|
|
/* Allow other writers to continue. */
|
|
__atomic_fetch_add(&pf->wr.out, 1, __ATOMIC_RELEASE);
|
|
}
|
|
|
|
#ifdef __cplusplus
|
|
}
|
|
#endif
|
|
|
|
#endif /* RTE_PFLOCK_H */
|