]>
Commit | Line | Data |
---|---|---|
dad81a20 PM |
1 | /* |
2 | * Sleepable Read-Copy Update mechanism for mutual exclusion, | |
3 | * classic v4.11 variant. | |
4 | * | |
5 | * This program is free software; you can redistribute it and/or modify | |
6 | * it under the terms of the GNU General Public License as published by | |
7 | * the Free Software Foundation; either version 2 of the License, or | |
8 | * (at your option) any later version. | |
9 | * | |
10 | * This program is distributed in the hope that it will be useful, | |
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
13 | * GNU General Public License for more details. | |
14 | * | |
15 | * You should have received a copy of the GNU General Public License | |
16 | * along with this program; if not, you can access it online at | |
17 | * http://www.gnu.org/licenses/gpl-2.0.html. | |
18 | * | |
19 | * Copyright (C) IBM Corporation, 2017 | |
20 | * | |
21 | * Author: Paul McKenney <paulmck@us.ibm.com> | |
22 | */ | |
23 | ||
24 | #ifndef _LINUX_SRCU_CLASSIC_H | |
25 | #define _LINUX_SRCU_CLASSIC_H | |
26 | ||
27 | struct srcu_array { | |
28 | unsigned long lock_count[2]; | |
29 | unsigned long unlock_count[2]; | |
30 | }; | |
31 | ||
32 | struct rcu_batch { | |
33 | struct rcu_head *head, **tail; | |
34 | }; | |
35 | ||
36 | #define RCU_BATCH_INIT(name) { NULL, &(name.head) } | |
37 | ||
38 | struct srcu_struct { | |
39 | unsigned long completed; | |
40 | struct srcu_array __percpu *per_cpu_ref; | |
41 | spinlock_t queue_lock; /* protect ->batch_queue, ->running */ | |
42 | bool running; | |
43 | /* callbacks just queued */ | |
44 | struct rcu_batch batch_queue; | |
45 | /* callbacks try to do the first check_zero */ | |
46 | struct rcu_batch batch_check0; | |
47 | /* callbacks done with the first check_zero and the flip */ | |
48 | struct rcu_batch batch_check1; | |
49 | struct rcu_batch batch_done; | |
50 | struct delayed_work work; | |
51 | #ifdef CONFIG_DEBUG_LOCK_ALLOC | |
52 | struct lockdep_map dep_map; | |
53 | #endif /* #ifdef CONFIG_DEBUG_LOCK_ALLOC */ | |
54 | }; | |
55 | ||
56 | void process_srcu(struct work_struct *work); | |
57 | ||
58 | #define __SRCU_STRUCT_INIT(name) \ | |
59 | { \ | |
60 | .completed = -300, \ | |
61 | .per_cpu_ref = &name##_srcu_array, \ | |
62 | .queue_lock = __SPIN_LOCK_UNLOCKED(name.queue_lock), \ | |
63 | .running = false, \ | |
64 | .batch_queue = RCU_BATCH_INIT(name.batch_queue), \ | |
65 | .batch_check0 = RCU_BATCH_INIT(name.batch_check0), \ | |
66 | .batch_check1 = RCU_BATCH_INIT(name.batch_check1), \ | |
67 | .batch_done = RCU_BATCH_INIT(name.batch_done), \ | |
68 | .work = __DELAYED_WORK_INITIALIZER(name.work, process_srcu, 0),\ | |
69 | __SRCU_DEP_MAP_INIT(name) \ | |
70 | } | |
71 | ||
72 | /* | |
73 | * Define and initialize a srcu struct at build time. | |
74 | * Do -not- call init_srcu_struct() nor cleanup_srcu_struct() on it. | |
75 | * | |
76 | * Note that although DEFINE_STATIC_SRCU() hides the name from other | |
77 | * files, the per-CPU variable rules nevertheless require that the | |
78 | * chosen name be globally unique. These rules also prohibit use of | |
79 | * DEFINE_STATIC_SRCU() within a function. If these rules are too | |
80 | * restrictive, declare the srcu_struct manually. For example, in | |
81 | * each file: | |
82 | * | |
83 | * static struct srcu_struct my_srcu; | |
84 | * | |
85 | * Then, before the first use of each my_srcu, manually initialize it: | |
86 | * | |
87 | * init_srcu_struct(&my_srcu); | |
88 | * | |
89 | * See include/linux/percpu-defs.h for the rules on per-CPU variables. | |
90 | */ | |
91 | #define __DEFINE_SRCU(name, is_static) \ | |
92 | static DEFINE_PER_CPU(struct srcu_array, name##_srcu_array);\ | |
93 | is_static struct srcu_struct name = __SRCU_STRUCT_INIT(name) | |
94 | #define DEFINE_SRCU(name) __DEFINE_SRCU(name, /* not static */) | |
95 | #define DEFINE_STATIC_SRCU(name) __DEFINE_SRCU(name, static) | |
96 | ||
97 | void synchronize_srcu_expedited(struct srcu_struct *sp); | |
98 | void srcu_barrier(struct srcu_struct *sp); | |
99 | unsigned long srcu_batches_completed(struct srcu_struct *sp); | |
100 | ||
7f6733c3 PM |
101 | static inline void srcutorture_get_gp_data(enum rcutorture_type test_type, |
102 | struct srcu_struct *sp, int *flags, | |
103 | unsigned long *gpnum, | |
104 | unsigned long *completed) | |
105 | { | |
106 | if (test_type != SRCU_FLAVOR) | |
107 | return; | |
108 | *flags = 0; | |
109 | *completed = sp->completed; | |
110 | *gpnum = *completed; | |
111 | if (sp->batch_queue.head || sp->batch_check0.head || sp->batch_check0.head) | |
112 | (*gpnum)++; | |
113 | } | |
114 | ||
dad81a20 | 115 | #endif |