3 # Modify SRCU for formal verification. The first argument should be srcu.h and
4 # the second should be srcu.c. Outputs modified srcu.h and srcu.c into the
9 print "Usange: input.h input.c output.h output.c" > "/dev/stderr";
16 # Tokenize using FS and not RS as FS supports regular expressions. Each
17 # record is one line of source, except that backslashed lines are
18 # combined. Comments are treated as field separators, as are quotes.
19 quote_regexp="\"([^\\\\\"]|\\\\.)*\"";
20 comment_regexp="\\/\\*([^*]|\\*+[^*/])*\\*\\/|\\/\\/.*(\n|$)";
21 FS="([ \\\\\t\n\v\f;,.=(){}+*/<>&|^-]|\\[|\\]|" comment_regexp "|" quote_regexp ")+";
23 inside_srcu_struct = 0;
24 inside_srcu_init_def = 0;
25 srcu_init_param_name = "";
30 # Allow the manipulation of the last field separator after has been
33 # Whether the last field separator was intended to be output.
36 # rcu_batches stores the initialization for each instance of struct
45 prev_outputfile = outputfile;
46 if (FILENAME ~ /\.h$/) {
47 outputfile = h_output;
49 print "Incorrect file order" > "/dev/stderr";
54 outputfile = c_output;
56 if (prev_outputfile && outputfile != prev_outputfile) {
57 new_outputfile = outputfile;
58 outputfile = prev_outputfile;
59 update_fieldsep("", 0);
60 outputfile = new_outputfile;
64 # Combine the next line into $0.
65 function combine_line() {
66 ret = getline next_line;
68 # Don't allow two consecutive getlines at the end of the file
70 print "Error: expected more input." > "/dev/stderr";
75 } else if (ret == -1) {
76 print "Error reading next line of file" FILENAME > "/dev/stderr";
79 $0 = $0 "\n" next_line;
82 # Combine backslashed lines and multiline comments.
83 function combine_backslashes() {
84 while (/\\$|\/\*([^*]|\*+[^*\/])*\**$/) {
89 function read_line() {
91 combine_backslashes();
94 # Print out field separators and update variables that depend on them. Only
95 # print if p is true. Call with sep="" and p=0 to print out the last field
97 function update_fieldsep(sep, p) {
100 gsub(quote_regexp "|" comment_regexp, "", sep_tmp);
103 if (sub("[^{}()]*\\{", "", sep_tmp)) {
107 if (sub("[^{}()]*\\}", "", sep_tmp)) {
109 if (brace_nesting < 0) {
110 print "Unbalanced braces!" > "/dev/stderr";
115 if (sub("[^{}()]*\\(", "", sep_tmp)) {
119 if (sub("[^{}()]*\\)", "", sep_tmp)) {
121 if (paren_nesting < 0) {
122 print "Unbalanced parenthesis!" > "/dev/stderr";
132 printf("%s", last_fs) > outputfile;
137 # Shifts the fields down by n positions. Calls next if there are no more. If p
138 # is true then print out field separators.
139 function shift_fields(n, p) {
141 if (match($0, FS) > 0) {
142 update_fieldsep(substr($0, RSTART, RLENGTH), p);
143 if (RSTART + RLENGTH <= length())
144 $0 = substr($0, RSTART + RLENGTH);
148 update_fieldsep("", 0);
149 print "" > outputfile;
155 # Shifts and prints the first n fields.
156 function print_fields(n) {
158 update_fieldsep("", 0);
159 printf("%s", $1) > outputfile;
165 combine_backslashes();
170 if (match($0, "^(" FS ")+") > 0) {
171 update_fieldsep(substr($0, RSTART, RLENGTH), 1);
172 if (RSTART + RLENGTH <= length())
173 $0 = substr($0, RSTART + RLENGTH);
182 if ($1 == "struct" && NF < 3) {
187 if (FILENAME ~ /\.h$/ && !inside_srcu_struct &&
188 brace_nesting == 0 && paren_nesting == 0 &&
189 $1 == "struct" && $2 == "srcu_struct" &&
190 $0 ~ "^struct(" FS ")+srcu_struct(" FS ")+\\{") {
191 inside_srcu_struct = 1;
195 if (inside_srcu_struct && brace_nesting == 0 &&
196 paren_nesting == 0) {
197 inside_srcu_struct = 0;
198 update_fieldsep("", 0);
199 for (name in rcu_batches)
200 print "extern struct rcu_batch " name ";" > outputfile;
203 if (inside_srcu_struct && $1 == "struct" && $2 == "rcu_batch") {
204 # Move rcu_batches outside of the struct.
205 rcu_batches[$3] = "";
207 sub(/;[[:space:]]*$/, "", last_fs);
211 if (FILENAME ~ /\.h$/ && !inside_srcu_init_def &&
212 $1 == "#define" && $2 == "__SRCU_STRUCT_INIT") {
213 inside_srcu_init_def = 1;
214 srcu_init_param_name = $3;
219 if (inside_srcu_init_def && brace_nesting == 0 &&
220 paren_nesting == 0) {
221 inside_srcu_init_def = 0;
226 if (inside_srcu_init_def && brace_nesting == 1 &&
227 paren_nesting == 0 && last_fs ~ /\.[[:space:]]*$/ &&
228 $1 ~ /^[[:alnum:]_]+$/) {
230 if (name in rcu_batches) {
232 sub(/\.[[:space:]]*$/, "", last_fs);
237 while (last_fs !~ /,/ || paren_nesting > 0);
238 end_loc = length(old_record) - length($0);
239 end_loc += index(last_fs, ",") - length(last_fs);
241 last_fs = substr(last_fs, index(last_fs, ",") + 1);
244 match(old_record, "^"name"("FS")+=");
245 start_loc = RSTART + RLENGTH;
247 len = end_loc - start_loc;
248 initializer = substr(old_record, start_loc, len);
249 gsub(srcu_init_param_name "\\.", "", initializer);
250 rcu_batches[name] = initializer;
255 # Don't include a nonexistent file
256 if (!in_macro && $1 == "#include" && /^#include[[:space:]]+"rcu\.h"/) {
257 update_fieldsep("", 0);
261 # Ignore most preprocessor stuff.
262 if (!in_macro && $1 ~ /#/) {
266 if (brace_nesting > 0 && $1 ~ "^[[:alnum:]_]+$" && NF < 2) {
270 if (brace_nesting > 0 &&
271 $0 ~ "^[[:alnum:]_]+[[:space:]]*(\\.|->)[[:space:]]*[[:alnum:]_]+" &&
273 # Make uses of rcu_batches global. Somewhat unreliable.
279 if ($1 == "static" && NF < 3) {
283 if ($1 == "static" && ($2 == "bool" && $3 == "try_check_zero" ||
284 $2 == "void" && $3 == "srcu_flip")) {
290 # Distinguish between read-side and write-side memory barriers.
291 if ($1 == "smp_mb" && NF < 2) {
295 if (match($0, /^smp_mb[[:space:]();\/*]*[[:alnum:]]/)) {
296 barrier_letter = substr($0, RLENGTH, 1);
297 if (barrier_letter ~ /A|D/)
298 new_barrier_name = "sync_smp_mb";
299 else if (barrier_letter ~ /B|C/)
300 new_barrier_name = "rs_smp_mb";
302 print "Unrecognized memory barrier." > "/dev/null";
307 printf("%s", new_barrier_name) > outputfile;
311 # Skip definition of rcu_synchronize, since it is already
312 # defined in misc.h. Only present in old versions of srcu.
313 if (brace_nesting == 0 && paren_nesting == 0 &&
314 $1 == "struct" && $2 == "rcu_synchronize" &&
315 $0 ~ "^struct(" FS ")+rcu_synchronize(" FS ")+\\{") {
317 while (brace_nesting) {
324 # Skip definition of wakeme_after_rcu for the same reason
325 if (brace_nesting == 0 && $1 == "static" && $2 == "void" &&
326 $3 == "wakeme_after_rcu") {
334 } while (paren_nesting || brace_nesting);
337 if ($1 ~ /^(unsigned|long)$/ && NF < 3) {
342 # Give srcu_batches_completed the correct type for old SRCU.
343 if (brace_nesting == 0 && $1 == "long" &&
344 $2 == "srcu_batches_completed") {
345 update_fieldsep("", 0);
346 printf("unsigned ") > outputfile;
350 if (brace_nesting == 0 && $1 == "unsigned" && $2 == "long" &&
351 $3 == "srcu_batches_completed") {
356 # Just print out the input code by default.
359 update_fieldsep("", 0);
365 update_fieldsep("", 0);
367 if (brace_nesting != 0) {
368 print "Unbalanced braces!" > "/dev/stderr";
372 # Define the rcu_batches
373 for (name in rcu_batches)
374 print "struct rcu_batch " name " = " rcu_batches[name] ";" > c_output;