xref: /linux/kernel/rcu/rcu_segcblist.h (revision d0034a7a4ac7fae708146ac0059b9c47a1543f0d)
1eb7935e4SPaul E. McKenney /* SPDX-License-Identifier: GPL-2.0+ */
245753c5fSIngo Molnar /*
398059b98SPaul E. McKenney  * RCU segmented callback lists, internal-to-rcu header file
445753c5fSIngo Molnar  *
545753c5fSIngo Molnar  * Copyright IBM Corporation, 2017
645753c5fSIngo Molnar  *
7eb7935e4SPaul E. McKenney  * Authors: Paul E. McKenney <paulmck@linux.ibm.com>
845753c5fSIngo Molnar  */
945753c5fSIngo Molnar 
1045753c5fSIngo Molnar #include <linux/rcu_segcblist.h>
1145753c5fSIngo Molnar 
12eda669a6SPaul E. McKenney /* Return number of callbacks in the specified callback list. */
13eda669a6SPaul E. McKenney static inline long rcu_cblist_n_cbs(struct rcu_cblist *rclp)
14eda669a6SPaul E. McKenney {
15eda669a6SPaul E. McKenney 	return READ_ONCE(rclp->len);
16eda669a6SPaul E. McKenney }
17eda669a6SPaul E. McKenney 
18b4e6039eSJoel Fernandes (Google) /* Return number of callbacks in segmented callback list by summing seglen. */
19b4e6039eSJoel Fernandes (Google) long rcu_segcblist_n_segment_cbs(struct rcu_segcblist *rsclp);
20b4e6039eSJoel Fernandes (Google) 
2198059b98SPaul E. McKenney void rcu_cblist_init(struct rcu_cblist *rclp);
22d1b222c6SPaul E. McKenney void rcu_cblist_enqueue(struct rcu_cblist *rclp, struct rcu_head *rhp);
23d1b222c6SPaul E. McKenney void rcu_cblist_flush_enqueue(struct rcu_cblist *drclp,
24d1b222c6SPaul E. McKenney 			      struct rcu_cblist *srclp,
25d1b222c6SPaul E. McKenney 			      struct rcu_head *rhp);
2698059b98SPaul E. McKenney struct rcu_head *rcu_cblist_dequeue(struct rcu_cblist *rclp);
2745753c5fSIngo Molnar 
2845753c5fSIngo Molnar /*
2945753c5fSIngo Molnar  * Is the specified rcu_segcblist structure empty?
3045753c5fSIngo Molnar  *
3145753c5fSIngo Molnar  * But careful!  The fact that the ->head field is NULL does not
3245753c5fSIngo Molnar  * necessarily imply that there are no callbacks associated with
3345753c5fSIngo Molnar  * this structure.  When callbacks are being invoked, they are
3445753c5fSIngo Molnar  * removed as a group.  If callback invocation must be preempted,
3545753c5fSIngo Molnar  * the remaining callbacks will be added back to the list.  Either
3645753c5fSIngo Molnar  * way, the counts are updated later.
3745753c5fSIngo Molnar  *
3845753c5fSIngo Molnar  * So it is often the case that rcu_segcblist_n_cbs() should be used
3945753c5fSIngo Molnar  * instead.
4045753c5fSIngo Molnar  */
4145753c5fSIngo Molnar static inline bool rcu_segcblist_empty(struct rcu_segcblist *rsclp)
4245753c5fSIngo Molnar {
43e6060b41SPaul E. McKenney 	return !READ_ONCE(rsclp->head);
4445753c5fSIngo Molnar }
4545753c5fSIngo Molnar 
4645753c5fSIngo Molnar /* Return number of callbacks in segmented callback list. */
4745753c5fSIngo Molnar static inline long rcu_segcblist_n_cbs(struct rcu_segcblist *rsclp)
4845753c5fSIngo Molnar {
49eda669a6SPaul E. McKenney #ifdef CONFIG_RCU_NOCB_CPU
50eda669a6SPaul E. McKenney 	return atomic_long_read(&rsclp->len);
51eda669a6SPaul E. McKenney #else
5245753c5fSIngo Molnar 	return READ_ONCE(rsclp->len);
53eda669a6SPaul E. McKenney #endif
5445753c5fSIngo Molnar }
5545753c5fSIngo Molnar 
5665e56032SFrederic Weisbecker static inline void rcu_segcblist_set_flags(struct rcu_segcblist *rsclp,
5765e56032SFrederic Weisbecker 					   int flags)
5865e56032SFrederic Weisbecker {
5965e56032SFrederic Weisbecker 	rsclp->flags |= flags;
6065e56032SFrederic Weisbecker }
6165e56032SFrederic Weisbecker 
6265e56032SFrederic Weisbecker static inline void rcu_segcblist_clear_flags(struct rcu_segcblist *rsclp,
6365e56032SFrederic Weisbecker 					     int flags)
6465e56032SFrederic Weisbecker {
6565e56032SFrederic Weisbecker 	rsclp->flags &= ~flags;
6665e56032SFrederic Weisbecker }
6765e56032SFrederic Weisbecker 
6865e56032SFrederic Weisbecker static inline bool rcu_segcblist_test_flags(struct rcu_segcblist *rsclp,
6965e56032SFrederic Weisbecker 					    int flags)
7065e56032SFrederic Weisbecker {
7165e56032SFrederic Weisbecker 	return READ_ONCE(rsclp->flags) & flags;
7265e56032SFrederic Weisbecker }
7365e56032SFrederic Weisbecker 
7445753c5fSIngo Molnar /*
7545753c5fSIngo Molnar  * Is the specified rcu_segcblist enabled, for example, not corresponding
76e83e73f5SPaul E. McKenney  * to an offline CPU?
7745753c5fSIngo Molnar  */
7845753c5fSIngo Molnar static inline bool rcu_segcblist_is_enabled(struct rcu_segcblist *rsclp)
7945753c5fSIngo Molnar {
8065e56032SFrederic Weisbecker 	return rcu_segcblist_test_flags(rsclp, SEGCBLIST_ENABLED);
8145753c5fSIngo Molnar }
8245753c5fSIngo Molnar 
83*f759081eSPaul E. McKenney /* Is the specified rcu_segcblist offloaded, or is SEGCBLIST_SOFTIRQ_ONLY set? */
84ce5215c1SPaul E. McKenney static inline bool rcu_segcblist_is_offloaded(struct rcu_segcblist *rsclp)
85ce5215c1SPaul E. McKenney {
86*f759081eSPaul E. McKenney 	if (IS_ENABLED(CONFIG_RCU_NOCB_CPU) &&
87*f759081eSPaul E. McKenney 	    !rcu_segcblist_test_flags(rsclp, SEGCBLIST_SOFTIRQ_ONLY))
888d346d43SFrederic Weisbecker 		return true;
898d346d43SFrederic Weisbecker 
908d346d43SFrederic Weisbecker 	return false;
91ce5215c1SPaul E. McKenney }
92ce5215c1SPaul E. McKenney 
9332aa2f41SFrederic Weisbecker static inline bool rcu_segcblist_completely_offloaded(struct rcu_segcblist *rsclp)
9432aa2f41SFrederic Weisbecker {
9532aa2f41SFrederic Weisbecker 	int flags = SEGCBLIST_KTHREAD_CB | SEGCBLIST_KTHREAD_GP | SEGCBLIST_OFFLOADED;
9632aa2f41SFrederic Weisbecker 
97*f759081eSPaul E. McKenney 	if (IS_ENABLED(CONFIG_RCU_NOCB_CPU) && (rsclp->flags & flags) == flags)
9832aa2f41SFrederic Weisbecker 		return true;
9932aa2f41SFrederic Weisbecker 
10032aa2f41SFrederic Weisbecker 	return false;
10132aa2f41SFrederic Weisbecker }
10232aa2f41SFrederic Weisbecker 
10345753c5fSIngo Molnar /*
10445753c5fSIngo Molnar  * Are all segments following the specified segment of the specified
10545753c5fSIngo Molnar  * rcu_segcblist structure empty of callbacks?  (The specified
10645753c5fSIngo Molnar  * segment might well contain callbacks.)
10745753c5fSIngo Molnar  */
10845753c5fSIngo Molnar static inline bool rcu_segcblist_restempty(struct rcu_segcblist *rsclp, int seg)
10945753c5fSIngo Molnar {
11076c6927cSPaul E. McKenney 	return !READ_ONCE(*READ_ONCE(rsclp->tails[seg]));
11145753c5fSIngo Molnar }
11245753c5fSIngo Molnar 
11334169061SPaul E. McKenney /*
11434169061SPaul E. McKenney  * Is the specified segment of the specified rcu_segcblist structure
11534169061SPaul E. McKenney  * empty of callbacks?
11634169061SPaul E. McKenney  */
11734169061SPaul E. McKenney static inline bool rcu_segcblist_segempty(struct rcu_segcblist *rsclp, int seg)
11834169061SPaul E. McKenney {
11934169061SPaul E. McKenney 	if (seg == RCU_DONE_TAIL)
12034169061SPaul E. McKenney 		return &rsclp->head == rsclp->tails[RCU_DONE_TAIL];
12134169061SPaul E. McKenney 	return rsclp->tails[seg - 1] == rsclp->tails[seg];
12234169061SPaul E. McKenney }
12334169061SPaul E. McKenney 
124d1b222c6SPaul E. McKenney void rcu_segcblist_inc_len(struct rcu_segcblist *rsclp);
1256bc33582SJoel Fernandes (Google) void rcu_segcblist_add_len(struct rcu_segcblist *rsclp, long v);
12698059b98SPaul E. McKenney void rcu_segcblist_init(struct rcu_segcblist *rsclp);
12798059b98SPaul E. McKenney void rcu_segcblist_disable(struct rcu_segcblist *rsclp);
128d97b0781SFrederic Weisbecker void rcu_segcblist_offload(struct rcu_segcblist *rsclp, bool offload);
12998059b98SPaul E. McKenney bool rcu_segcblist_ready_cbs(struct rcu_segcblist *rsclp);
13098059b98SPaul E. McKenney bool rcu_segcblist_pend_cbs(struct rcu_segcblist *rsclp);
13198059b98SPaul E. McKenney struct rcu_head *rcu_segcblist_first_cb(struct rcu_segcblist *rsclp);
13298059b98SPaul E. McKenney struct rcu_head *rcu_segcblist_first_pend_cb(struct rcu_segcblist *rsclp);
1335d6742b3SPaul E. McKenney bool rcu_segcblist_nextgp(struct rcu_segcblist *rsclp, unsigned long *lp);
13498059b98SPaul E. McKenney void rcu_segcblist_enqueue(struct rcu_segcblist *rsclp,
13577a40f97SJoel Fernandes (Google) 			   struct rcu_head *rhp);
13698059b98SPaul E. McKenney bool rcu_segcblist_entrain(struct rcu_segcblist *rsclp,
13777a40f97SJoel Fernandes (Google) 			   struct rcu_head *rhp);
13898059b98SPaul E. McKenney void rcu_segcblist_extract_done_cbs(struct rcu_segcblist *rsclp,
13998059b98SPaul E. McKenney 				    struct rcu_cblist *rclp);
14098059b98SPaul E. McKenney void rcu_segcblist_extract_pend_cbs(struct rcu_segcblist *rsclp,
14198059b98SPaul E. McKenney 				    struct rcu_cblist *rclp);
14298059b98SPaul E. McKenney void rcu_segcblist_insert_count(struct rcu_segcblist *rsclp,
14398059b98SPaul E. McKenney 				struct rcu_cblist *rclp);
14498059b98SPaul E. McKenney void rcu_segcblist_insert_done_cbs(struct rcu_segcblist *rsclp,
14598059b98SPaul E. McKenney 				   struct rcu_cblist *rclp);
14698059b98SPaul E. McKenney void rcu_segcblist_insert_pend_cbs(struct rcu_segcblist *rsclp,
14798059b98SPaul E. McKenney 				   struct rcu_cblist *rclp);
14898059b98SPaul E. McKenney void rcu_segcblist_advance(struct rcu_segcblist *rsclp, unsigned long seq);
14998059b98SPaul E. McKenney bool rcu_segcblist_accelerate(struct rcu_segcblist *rsclp, unsigned long seq);
150f2dbe4a5SPaul E. McKenney void rcu_segcblist_merge(struct rcu_segcblist *dst_rsclp,
151f2dbe4a5SPaul E. McKenney 			 struct rcu_segcblist *src_rsclp);
152