blob: 86bc1101b806469ec4b16cb1360c01cf1cd9e1ed [file] [log] [blame]
Ingo Molnar45753c52017-05-02 10:31:18 +02001/*
Paul E. McKenney98059b92017-05-02 06:30:12 -07002 * RCU segmented callback lists, internal-to-rcu header file
Ingo Molnar45753c52017-05-02 10:31:18 +02003 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, you can access it online at
16 * http://www.gnu.org/licenses/gpl-2.0.html.
17 *
18 * Copyright IBM Corporation, 2017
19 *
20 * Authors: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
21 */
22
23#include <linux/rcu_segcblist.h>
24
Ingo Molnar45753c52017-05-02 10:31:18 +020025/* Is simple callback list empty? */
26static inline bool rcu_cblist_empty(struct rcu_cblist *rclp)
27{
28 return !rclp->head;
29}
30
31/* Return number of callbacks in simple callback list. */
32static inline long rcu_cblist_n_cbs(struct rcu_cblist *rclp)
33{
34 return rclp->len;
35}
36
37/* Return number of lazy callbacks in simple callback list. */
38static inline long rcu_cblist_n_lazy_cbs(struct rcu_cblist *rclp)
39{
40 return rclp->len_lazy;
41}
42
43/*
Ingo Molnar45753c52017-05-02 10:31:18 +020044 * Account for the fact that a previously dequeued callback turned out
45 * to be marked as lazy.
46 */
47static inline void rcu_cblist_dequeued_lazy(struct rcu_cblist *rclp)
48{
49 rclp->len_lazy--;
50}
51
52/*
53 * Interim function to return rcu_cblist head pointer. Longer term, the
54 * rcu_cblist will be used more pervasively, removing the need for this
55 * function.
56 */
57static inline struct rcu_head *rcu_cblist_head(struct rcu_cblist *rclp)
58{
59 return rclp->head;
60}
61
62/*
63 * Interim function to return rcu_cblist head pointer. Longer term, the
64 * rcu_cblist will be used more pervasively, removing the need for this
65 * function.
66 */
67static inline struct rcu_head **rcu_cblist_tail(struct rcu_cblist *rclp)
68{
69 WARN_ON_ONCE(rcu_cblist_empty(rclp));
70 return rclp->tail;
71}
72
Paul E. McKenney98059b92017-05-02 06:30:12 -070073void rcu_cblist_init(struct rcu_cblist *rclp);
74long rcu_cblist_count_cbs(struct rcu_cblist *rclp, long lim);
75struct rcu_head *rcu_cblist_dequeue(struct rcu_cblist *rclp);
Ingo Molnar45753c52017-05-02 10:31:18 +020076
77/*
78 * Is the specified rcu_segcblist structure empty?
79 *
80 * But careful! The fact that the ->head field is NULL does not
81 * necessarily imply that there are no callbacks associated with
82 * this structure. When callbacks are being invoked, they are
83 * removed as a group. If callback invocation must be preempted,
84 * the remaining callbacks will be added back to the list. Either
85 * way, the counts are updated later.
86 *
87 * So it is often the case that rcu_segcblist_n_cbs() should be used
88 * instead.
89 */
90static inline bool rcu_segcblist_empty(struct rcu_segcblist *rsclp)
91{
92 return !rsclp->head;
93}
94
95/* Return number of callbacks in segmented callback list. */
96static inline long rcu_segcblist_n_cbs(struct rcu_segcblist *rsclp)
97{
98 return READ_ONCE(rsclp->len);
99}
100
101/* Return number of lazy callbacks in segmented callback list. */
102static inline long rcu_segcblist_n_lazy_cbs(struct rcu_segcblist *rsclp)
103{
104 return rsclp->len_lazy;
105}
106
107/* Return number of lazy callbacks in segmented callback list. */
108static inline long rcu_segcblist_n_nonlazy_cbs(struct rcu_segcblist *rsclp)
109{
110 return rsclp->len - rsclp->len_lazy;
111}
112
113/*
114 * Is the specified rcu_segcblist enabled, for example, not corresponding
115 * to an offline or callback-offloaded CPU?
116 */
117static inline bool rcu_segcblist_is_enabled(struct rcu_segcblist *rsclp)
118{
119 return !!rsclp->tails[RCU_NEXT_TAIL];
120}
121
122/*
Ingo Molnar45753c52017-05-02 10:31:18 +0200123 * Are all segments following the specified segment of the specified
124 * rcu_segcblist structure empty of callbacks? (The specified
125 * segment might well contain callbacks.)
126 */
127static inline bool rcu_segcblist_restempty(struct rcu_segcblist *rsclp, int seg)
128{
129 return !*rsclp->tails[seg];
130}
131
132/*
Ingo Molnar45753c52017-05-02 10:31:18 +0200133 * Interim function to return rcu_segcblist head pointer. Longer term, the
134 * rcu_segcblist will be used more pervasively, removing the need for this
135 * function.
136 */
137static inline struct rcu_head *rcu_segcblist_head(struct rcu_segcblist *rsclp)
138{
139 return rsclp->head;
140}
141
142/*
143 * Interim function to return rcu_segcblist head pointer. Longer term, the
144 * rcu_segcblist will be used more pervasively, removing the need for this
145 * function.
146 */
147static inline struct rcu_head **rcu_segcblist_tail(struct rcu_segcblist *rsclp)
148{
149 WARN_ON_ONCE(rcu_segcblist_empty(rsclp));
150 return rsclp->tails[RCU_NEXT_TAIL];
151}
Paul E. McKenney98059b92017-05-02 06:30:12 -0700152
153void rcu_segcblist_init(struct rcu_segcblist *rsclp);
154void rcu_segcblist_disable(struct rcu_segcblist *rsclp);
155bool rcu_segcblist_segempty(struct rcu_segcblist *rsclp, int seg);
156bool rcu_segcblist_ready_cbs(struct rcu_segcblist *rsclp);
157bool rcu_segcblist_pend_cbs(struct rcu_segcblist *rsclp);
158struct rcu_head *rcu_segcblist_dequeue(struct rcu_segcblist *rsclp);
159void rcu_segcblist_dequeued_lazy(struct rcu_segcblist *rsclp);
160struct rcu_head *rcu_segcblist_first_cb(struct rcu_segcblist *rsclp);
161struct rcu_head *rcu_segcblist_first_pend_cb(struct rcu_segcblist *rsclp);
162bool rcu_segcblist_new_cbs(struct rcu_segcblist *rsclp);
163void rcu_segcblist_enqueue(struct rcu_segcblist *rsclp,
164 struct rcu_head *rhp, bool lazy);
165bool rcu_segcblist_entrain(struct rcu_segcblist *rsclp,
166 struct rcu_head *rhp, bool lazy);
167void rcu_segcblist_extract_count(struct rcu_segcblist *rsclp,
168 struct rcu_cblist *rclp);
169void rcu_segcblist_extract_done_cbs(struct rcu_segcblist *rsclp,
170 struct rcu_cblist *rclp);
171void rcu_segcblist_extract_pend_cbs(struct rcu_segcblist *rsclp,
172 struct rcu_cblist *rclp);
173void rcu_segcblist_insert_count(struct rcu_segcblist *rsclp,
174 struct rcu_cblist *rclp);
175void rcu_segcblist_insert_done_cbs(struct rcu_segcblist *rsclp,
176 struct rcu_cblist *rclp);
177void rcu_segcblist_insert_pend_cbs(struct rcu_segcblist *rsclp,
178 struct rcu_cblist *rclp);
179void rcu_segcblist_advance(struct rcu_segcblist *rsclp, unsigned long seq);
180bool rcu_segcblist_accelerate(struct rcu_segcblist *rsclp, unsigned long seq);
181bool rcu_segcblist_future_gp_needed(struct rcu_segcblist *rsclp,
182 unsigned long seq);