DPDK 25.03.0-rc0
rte_pflock.h
Go to the documentation of this file.
1/* SPDX-License-Identifier: BSD-3-Clause
2 * Copyright(c) 2021 Microsoft Corp.
3 * All rights reserved.
4 *
5 * Derived from Concurrency Kit
6 * Copyright 2011-2015 Samy Al Bahra.
7 */
8
9#ifndef _RTE_PFLOCK_H_
10#define _RTE_PFLOCK_H_
11
30#include <rte_common.h>
31#include <rte_pause.h>
32#include <rte_stdatomic.h>
33
34#ifdef __cplusplus
35extern "C" {
36#endif
37
41struct rte_pflock {
42 struct {
43 RTE_ATOMIC(uint16_t) in;
44 RTE_ATOMIC(uint16_t) out;
45 } rd, wr;
46};
47typedef struct rte_pflock rte_pflock_t;
48
49/*
50 * Allocation of bits to reader
51 *
52 * 15 4 3 2 1 0
53 * +-------------------+---+-+-+
54 * | rin: reads issued |x|x| | |
55 * +-------------------+---+-+-+
56 * ^ ^
57 * | |
58 * PRES: writer present ----/ |
59 * PHID: writer phase id -----/
60 *
61 * 15 4 3 2 1 0
62 * +------------------+------+
63 * |rout:read complete|unused|
64 * +------------------+------+
65 *
66 * The maximum number of readers is 4095
67 */
68
69/* Constants used to map the bits in reader counter */
70#define RTE_PFLOCK_WBITS 0x3 /* Writer bits in reader. */
71#define RTE_PFLOCK_PRES 0x2 /* Writer present bit. */
72#define RTE_PFLOCK_PHID 0x1 /* Phase ID bit. */
73#define RTE_PFLOCK_LSB 0xFFF0 /* reader bits. */
74#define RTE_PFLOCK_RINC 0x10 /* Reader increment. */
75
79#define RTE_PFLOCK_INITIALIZER { }
80
87static inline void
89{
90 pf->rd.in = 0;
91 pf->rd.out = 0;
92 pf->wr.in = 0;
93 pf->wr.out = 0;
94}
95
102static inline void
104{
105 uint16_t w;
106
107 /*
108 * If no writer is present, then the operation has completed
109 * successfully.
110 */
111 w = rte_atomic_fetch_add_explicit(&pf->rd.in, RTE_PFLOCK_RINC, rte_memory_order_acquire)
112 & RTE_PFLOCK_WBITS;
113 if (w == 0)
114 return;
115
116 /* Wait for current write phase to complete. */
117 RTE_WAIT_UNTIL_MASKED(&pf->rd.in, RTE_PFLOCK_WBITS, !=, w, rte_memory_order_acquire);
118}
119
126static inline void
128{
129 rte_atomic_fetch_add_explicit(&pf->rd.out, RTE_PFLOCK_RINC, rte_memory_order_release);
130}
131
138static inline void
140{
141 uint16_t ticket, w;
142
143 /* Acquire ownership of write-phase.
144 * This is same as rte_ticketlock_lock().
145 */
146 ticket = rte_atomic_fetch_add_explicit(&pf->wr.in, 1, rte_memory_order_relaxed);
147 rte_wait_until_equal_16((uint16_t *)(uintptr_t)&pf->wr.out, ticket,
148 rte_memory_order_acquire);
149
150 /*
151 * Acquire ticket on read-side in order to allow them
152 * to flush. Indicates to any incoming reader that a
153 * write-phase is pending.
154 *
155 * The load of rd.out in wait loop could be executed
156 * speculatively.
157 */
158 w = RTE_PFLOCK_PRES | (ticket & RTE_PFLOCK_PHID);
159 ticket = rte_atomic_fetch_add_explicit(&pf->rd.in, w, rte_memory_order_relaxed);
160
161 /* Wait for any pending readers to flush. */
162 rte_wait_until_equal_16((uint16_t *)(uintptr_t)&pf->rd.out, ticket,
163 rte_memory_order_acquire);
164}
165
172static inline void
174{
175 /* Migrate from write phase to read phase. */
176 rte_atomic_fetch_and_explicit(&pf->rd.in, RTE_PFLOCK_LSB, rte_memory_order_release);
177
178 /* Allow other writers to continue. */
179 rte_atomic_fetch_add_explicit(&pf->wr.out, 1, rte_memory_order_release);
180}
181
182#ifdef __cplusplus
183}
184#endif
185
186#endif /* RTE_PFLOCK_H */
static __rte_always_inline void rte_wait_until_equal_16(volatile uint16_t *addr, uint16_t expected, rte_memory_order memorder)
Definition: rte_pause.h:84
static void rte_pflock_write_unlock(rte_pflock_t *pf)
Definition: rte_pflock.h:173
static void rte_pflock_read_lock(rte_pflock_t *pf)
Definition: rte_pflock.h:103
static void rte_pflock_read_unlock(rte_pflock_t *pf)
Definition: rte_pflock.h:127
static void rte_pflock_write_lock(rte_pflock_t *pf)
Definition: rte_pflock.h:139
static void rte_pflock_init(struct rte_pflock *pf)
Definition: rte_pflock.h:88