f-stack/dpdk/lib/librte_eal/common/include/generic/rte_ticketlock.h

225 lines
4.6 KiB
C
Raw Normal View History

2020-06-18 16:55:50 +00:00
/* SPDX-License-Identifier: BSD-3-Clause
* Copyright(c) 2019 Arm Limited
*/
#ifndef _RTE_TICKETLOCK_H_
#define _RTE_TICKETLOCK_H_
/**
* @file
*
* RTE ticket locks
*
* This file defines an API for ticket locks, which give each waiting
* thread a ticket and take the lock one by one, first come, first
* serviced.
*
* All locks must be initialised before use, and only initialised once.
*
*/
#ifdef __cplusplus
extern "C" {
#endif
#include <rte_common.h>
#include <rte_lcore.h>
#include <rte_pause.h>
/**
* The rte_ticketlock_t type.
*/
typedef union {
uint32_t tickets;
struct {
uint16_t current;
uint16_t next;
} s;
} rte_ticketlock_t;
/**
* A static ticketlock initializer.
*/
#define RTE_TICKETLOCK_INITIALIZER { 0 }
/**
* Initialize the ticketlock to an unlocked state.
*
* @param tl
* A pointer to the ticketlock.
*/
__rte_experimental
static inline void
rte_ticketlock_init(rte_ticketlock_t *tl)
{
__atomic_store_n(&tl->tickets, 0, __ATOMIC_RELAXED);
}
/**
* Take the ticketlock.
*
* @param tl
* A pointer to the ticketlock.
*/
__rte_experimental
static inline void
rte_ticketlock_lock(rte_ticketlock_t *tl)
{
uint16_t me = __atomic_fetch_add(&tl->s.next, 1, __ATOMIC_RELAXED);
while (__atomic_load_n(&tl->s.current, __ATOMIC_ACQUIRE) != me)
rte_pause();
}
/**
* Release the ticketlock.
*
* @param tl
* A pointer to the ticketlock.
*/
__rte_experimental
static inline void
rte_ticketlock_unlock(rte_ticketlock_t *tl)
{
uint16_t i = __atomic_load_n(&tl->s.current, __ATOMIC_RELAXED);
__atomic_store_n(&tl->s.current, i + 1, __ATOMIC_RELEASE);
}
/**
* Try to take the lock.
*
* @param tl
* A pointer to the ticketlock.
* @return
* 1 if the lock is successfully taken; 0 otherwise.
*/
__rte_experimental
static inline int
rte_ticketlock_trylock(rte_ticketlock_t *tl)
{
rte_ticketlock_t old, new;
old.tickets = __atomic_load_n(&tl->tickets, __ATOMIC_RELAXED);
new.tickets = old.tickets;
new.s.next++;
if (old.s.next == old.s.current) {
if (__atomic_compare_exchange_n(&tl->tickets, &old.tickets,
new.tickets, 0, __ATOMIC_ACQUIRE, __ATOMIC_RELAXED))
return 1;
}
return 0;
}
/**
* Test if the lock is taken.
*
* @param tl
* A pointer to the ticketlock.
* @return
* 1 if the lock is currently taken; 0 otherwise.
*/
__rte_experimental
static inline int
rte_ticketlock_is_locked(rte_ticketlock_t *tl)
{
rte_ticketlock_t tic;
tic.tickets = __atomic_load_n(&tl->tickets, __ATOMIC_ACQUIRE);
return (tic.s.current != tic.s.next);
}
/**
* The rte_ticketlock_recursive_t type.
*/
#define TICKET_LOCK_INVALID_ID -1
typedef struct {
rte_ticketlock_t tl; /**< the actual ticketlock */
int user; /**< core id using lock, TICKET_LOCK_INVALID_ID for unused */
unsigned int count; /**< count of time this lock has been called */
} rte_ticketlock_recursive_t;
/**
* A static recursive ticketlock initializer.
*/
#define RTE_TICKETLOCK_RECURSIVE_INITIALIZER {RTE_TICKETLOCK_INITIALIZER, \
TICKET_LOCK_INVALID_ID, 0}
/**
* Initialize the recursive ticketlock to an unlocked state.
*
* @param tlr
* A pointer to the recursive ticketlock.
*/
__rte_experimental
static inline void
rte_ticketlock_recursive_init(rte_ticketlock_recursive_t *tlr)
{
rte_ticketlock_init(&tlr->tl);
__atomic_store_n(&tlr->user, TICKET_LOCK_INVALID_ID, __ATOMIC_RELAXED);
tlr->count = 0;
}
/**
* Take the recursive ticketlock.
*
* @param tlr
* A pointer to the recursive ticketlock.
*/
__rte_experimental
static inline void
rte_ticketlock_recursive_lock(rte_ticketlock_recursive_t *tlr)
{
int id = rte_gettid();
if (__atomic_load_n(&tlr->user, __ATOMIC_RELAXED) != id) {
rte_ticketlock_lock(&tlr->tl);
__atomic_store_n(&tlr->user, id, __ATOMIC_RELAXED);
}
tlr->count++;
}
/**
* Release the recursive ticketlock.
*
* @param tlr
* A pointer to the recursive ticketlock.
*/
__rte_experimental
static inline void
rte_ticketlock_recursive_unlock(rte_ticketlock_recursive_t *tlr)
{
if (--(tlr->count) == 0) {
__atomic_store_n(&tlr->user, TICKET_LOCK_INVALID_ID,
__ATOMIC_RELAXED);
rte_ticketlock_unlock(&tlr->tl);
}
}
/**
* Try to take the recursive lock.
*
* @param tlr
* A pointer to the recursive ticketlock.
* @return
* 1 if the lock is successfully taken; 0 otherwise.
*/
__rte_experimental
static inline int
rte_ticketlock_recursive_trylock(rte_ticketlock_recursive_t *tlr)
{
int id = rte_gettid();
if (__atomic_load_n(&tlr->user, __ATOMIC_RELAXED) != id) {
if (rte_ticketlock_trylock(&tlr->tl) == 0)
return 0;
__atomic_store_n(&tlr->user, id, __ATOMIC_RELAXED);
}
tlr->count++;
return 1;
}
#ifdef __cplusplus
}
#endif
#endif /* _RTE_TICKETLOCK_H_ */