1 | /* Copyright 2016 Google Inc. |
2 | |
3 | Licensed under the Apache License, Version 2.0 (the "License"); |
4 | you may not use this file except in compliance with the License. |
5 | You may obtain a copy of the License at |
6 | |
7 | http://www.apache.org/licenses/LICENSE-2.0 |
8 | |
9 | Unless required by applicable law or agreed to in writing, software |
10 | distributed under the License is distributed on an "AS IS" BASIS, |
11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
12 | See the License for the specific language governing permissions and |
13 | limitations under the License. */ |
14 | |
15 | /* Routines for debugging. */ |
16 | |
17 | #include "nsync_cpp.h" |
18 | #include "platform.h" |
19 | #include "compiler.h" |
20 | #include "cputype.h" |
21 | #include "nsync.h" |
22 | #include "dll.h" |
23 | #include "sem.h" |
24 | #include "wait_internal.h" |
25 | #include "common.h" |
26 | #include "atomic.h" |
27 | |
28 | NSYNC_CPP_START_ |
29 | |
30 | /* ---------- */ |
31 | |
32 | /* An emit_buf represents a buffer into which debug information can |
33 | be written. */ |
34 | struct emit_buf { |
35 | char *start; /* start of buffer */ |
36 | int len; /* pength of buffer */ |
37 | int pos; /* position of next character to bve written */ |
38 | int overflow; /* non-zero iff buffer overflow has occurred */ |
39 | }; |
40 | |
41 | /* Initialize *b to point to start[0, .., len-1], and return b. |
42 | of to an internal static buffer if buf==NULL. */ |
43 | static struct emit_buf *emit_init (struct emit_buf *b, char *start, int len) { |
44 | b->start = start; |
45 | b->len = len; |
46 | b->pos = 0; |
47 | b->overflow = 0; |
48 | return (b); |
49 | } |
50 | |
51 | |
52 | /* Write character c to buffer *b. */ |
53 | static void emit_c (struct emit_buf *b, int c) { |
54 | if (b->pos < b->len) { |
55 | b->start[b->pos++] = c; |
56 | } else if (!b->overflow) { |
57 | static const char suffix[] = "..." ; |
58 | const char *s = &suffix[sizeof (suffix)]; /* past nul */ |
59 | char *p = &b->start[b->len]; /* past end */ |
60 | while (s > suffix && p > b->start) { |
61 | *--p = *--s; |
62 | } |
63 | b->overflow = 1; |
64 | } |
65 | } |
66 | |
67 | /* A printf-like function that writes to an emit_buf. |
68 | It understands only the format specifiers %s (const char *), and %i |
69 | (uintptr_t in hex), with no modifiers. */ |
70 | static void emit_print (struct emit_buf *b, const char *fmt, ...) { |
71 | va_list ap; |
72 | va_start (ap, fmt); |
73 | while (*fmt != 0) { |
74 | int c = *fmt++; |
75 | if (c != '%') { |
76 | emit_c (b, c); |
77 | } else { |
78 | c = *fmt++; |
79 | if (c == 's') { |
80 | const char *s = va_arg (ap, const char *); |
81 | while (*s != 0) { |
82 | emit_c (b, *s++); |
83 | } |
84 | } else if (c == 'i') { |
85 | uintptr_t n = va_arg (ap, uintptr_t); |
86 | int i; |
87 | for (i = 0; (n >> i) >= 0x10; i += 4) { |
88 | } |
89 | for (; i >= 0; i -= 4) { |
90 | emit_c (b, "0123456789abcdef" [(n >> i) & 0xf]); |
91 | } |
92 | } else { |
93 | ASSERT (0); |
94 | } |
95 | } |
96 | } |
97 | va_end (ap); |
98 | } |
99 | |
100 | /* Map a bit in a uint32_t to a human-readable name. */ |
101 | struct bit_name { |
102 | uint32_t mask; |
103 | const char *name; |
104 | }; |
105 | |
106 | /* names for bits in a mu word */ |
107 | static const struct bit_name mu_bit[] = { |
108 | { MU_WLOCK, "wlock" }, |
109 | { MU_SPINLOCK, "spin" }, |
110 | { MU_WAITING, "wait" }, |
111 | { MU_DESIG_WAKER, "desig" }, |
112 | { MU_CONDITION, "cond" }, |
113 | { MU_WRITER_WAITING, "writer" }, |
114 | { MU_LONG_WAIT, "long" }, |
115 | { MU_ALL_FALSE, "false" }, |
116 | { 0, "" } /* sentinel */ |
117 | }; |
118 | |
119 | /* names for bits in a cv word */ |
120 | static const struct bit_name cv_bit[] = { |
121 | { CV_SPINLOCK, "spin" }, |
122 | { CV_NON_EMPTY, "wait" }, |
123 | { 0, "" } /* sentinel */ |
124 | }; |
125 | |
126 | /* names for bits in a waiter flags word */ |
127 | static const struct bit_name waiter_flags_bit[] = { |
128 | { WAITER_RESERVED, "rsrvd" }, |
129 | { WAITER_IN_USE, "in_use" }, |
130 | { 0, "" } /* sentinel */ |
131 | }; |
132 | |
133 | /* Emit the names of bits in word to buffer *b using names[] */ |
134 | static void emit_word (struct emit_buf *b, const struct bit_name *name, uint32_t word) { |
135 | int i; |
136 | for (i = 0; name[i].mask != 0; i++) { |
137 | if ((word & name[i].mask) != 0) { |
138 | emit_print (b, " %s" , name[i].name); |
139 | } |
140 | } |
141 | } |
142 | |
143 | /* Emit the waiter queue *q to *b. */ |
144 | static void emit_waiters (struct emit_buf *b, nsync_dll_list_ list) { |
145 | nsync_dll_element_ *p = nsync_dll_first_ (list); |
146 | nsync_dll_element_ *next; |
147 | if (p != NULL) { |
148 | emit_print (b, "\nwaiters =\n" ); |
149 | } |
150 | for (; p != NULL && !b->overflow; p = next) { |
151 | struct nsync_waiter_s *nw = DLL_NSYNC_WAITER (p); |
152 | waiter *w = DLL_WAITER (p); |
153 | next = NULL; |
154 | emit_print (b, " %i" , (uintptr_t) w); |
155 | if (w->tag != WAITER_TAG) { |
156 | emit_print (b, "bad WAITER_TAG %i" , |
157 | (uintptr_t) w->tag); |
158 | } else { |
159 | next = nsync_dll_next_ (list, p); |
160 | if (nw->tag != NSYNC_WAITER_TAG) { |
161 | emit_print (b, " bad WAITER_TAG %i" , |
162 | (uintptr_t) nw->tag); |
163 | } else { |
164 | emit_print (b, " embedded=%i waiting=%i" , |
165 | (uintptr_t) (w->flags & NSYNC_WAITER_FLAG_MUCV), |
166 | (uintptr_t) ATM_LOAD (&nw->waiting)); |
167 | } |
168 | emit_word (b, waiter_flags_bit, w->flags); |
169 | emit_print (b, " %s removes=%i cond=(%i %i %i)" , |
170 | w->l_type == nsync_writer_type_? "writer" : |
171 | w->l_type == nsync_reader_type_? "reader" : |
172 | "??????" , |
173 | (uintptr_t) ATM_LOAD (&w->remove_count), |
174 | (uintptr_t) w->cond.f, |
175 | (uintptr_t) w->cond.v, |
176 | (uintptr_t) w->cond.eq); |
177 | if (w->same_condition.next != &w->same_condition) { |
178 | emit_print (b, " same_as %i" , |
179 | (uintptr_t) DLL_WAITER_SAMECOND ( |
180 | w->same_condition.next)); |
181 | } |
182 | } |
183 | emit_c (b, '\n'); |
184 | } |
185 | } |
186 | |
187 | /* Emit to *b the state of *mu, and return a pointer to *b's buffer. |
188 | |
189 | If blocking!=0, print_waiters!=0, and *mu's waiter list is non-empty, the |
190 | call will block until it can acquire the spinlock. |
191 | If print_waiters!=0, the waiter list is printed. |
192 | The spinlock is released before return if it was acquired. |
193 | blocking==0 && print_waiters!=0 is unsafe and is intended for use within |
194 | interactive debuggers. */ |
195 | static char *emit_mu_state (struct emit_buf *b, nsync_mu *mu, |
196 | int blocking, int print_waiters) { |
197 | uintptr_t word; |
198 | uintptr_t readers; |
199 | int acquired = 0; |
200 | IGNORE_RACES_START (); |
201 | word = ATM_LOAD (&mu->word); |
202 | if ((word & MU_WAITING) != 0 && print_waiters && /* can benefit from lock */ |
203 | (blocking || (word & MU_SPINLOCK) == 0)) { /* willing, or no need to wait */ |
204 | word = nsync_spin_test_and_set_ (&mu->word, MU_SPINLOCK, MU_SPINLOCK, 0); |
205 | acquired = 1; |
206 | } |
207 | readers = word / MU_RLOCK; |
208 | emit_print (b, "mu 0x%i -> 0x%i = {" , (uintptr_t) mu, word); |
209 | emit_word (b, mu_bit, word); |
210 | if (readers != 0) { |
211 | emit_print (b, " readers=0x%i" , readers); |
212 | } |
213 | emit_print (b, " }" ); |
214 | if (print_waiters) { |
215 | emit_waiters (b, mu->waiters); |
216 | } |
217 | if (acquired) { |
218 | ATM_STORE_REL (&mu->word, word); /* release store */ |
219 | } |
220 | emit_c (b, 0); |
221 | IGNORE_RACES_END (); |
222 | return (b->start); |
223 | } |
224 | |
225 | /* Emit to *b the state of *cv, and return a pointer to *b's buffer. |
226 | |
227 | If blocking!=0, print_waiters!=0, and *cv's waiter list is non-empty, the |
228 | call will block until it can acquire the spinlock. |
229 | If print_waiters!=0, the waiter list is printed. |
230 | The spinlock is released before return if it was acquired. |
231 | blocking==0 && print_waiters!=0 is unsafe and is intended for use within |
232 | interactive debuggers. */ |
233 | static char *emit_cv_state (struct emit_buf *b, nsync_cv *cv, |
234 | int blocking, int print_waiters) { |
235 | uintptr_t word; |
236 | int acquired = 0; |
237 | IGNORE_RACES_START (); |
238 | word = ATM_LOAD (&cv->word); |
239 | if ((word & CV_NON_EMPTY) != 0 && print_waiters && /* can benefit from lock */ |
240 | (blocking || (word & CV_SPINLOCK) == 0)) { /* willing, or no need to wait */ |
241 | word = nsync_spin_test_and_set_ (&cv->word, CV_SPINLOCK, CV_SPINLOCK, 0); |
242 | acquired = 1; |
243 | } |
244 | emit_print (b, "cv 0x%i -> 0x%i = {" , (uintptr_t) cv, word); |
245 | emit_word (b, cv_bit, word); |
246 | emit_print (b, " }" ); |
247 | if (print_waiters) { |
248 | emit_waiters (b, cv->waiters); |
249 | } |
250 | if (acquired) { |
251 | ATM_STORE_REL (&cv->word, word); /* release store */ |
252 | } |
253 | emit_c (b, 0); |
254 | IGNORE_RACES_END (); |
255 | return (b->start); |
256 | } |
257 | |
258 | char *nsync_mu_debug_state (nsync_mu *mu, char *buf, int n) { |
259 | struct emit_buf b; |
260 | return (emit_mu_state (emit_init (&b, buf, n), mu, 0, 0)); |
261 | } |
262 | |
263 | char *nsync_cv_debug_state (nsync_cv *cv, char *buf, int n) { |
264 | struct emit_buf b; |
265 | return (emit_cv_state (emit_init (&b, buf, n), cv, 0, 0)); |
266 | } |
267 | |
268 | char *nsync_mu_debug_state_and_waiters (nsync_mu *mu, char *buf, int n) { |
269 | struct emit_buf b; |
270 | return (emit_mu_state (emit_init (&b, buf, n), mu, 1, 1)); |
271 | } |
272 | |
273 | char *nsync_cv_debug_state_and_waiters (nsync_cv *cv, char *buf, int n) { |
274 | struct emit_buf b; |
275 | return (emit_cv_state (emit_init (&b, buf, n), cv, 1, 1)); |
276 | } |
277 | |
278 | static char nsync_debug_buf[1024]; |
279 | |
280 | char *nsync_mu_debugger (nsync_mu *mu) { |
281 | struct emit_buf b; |
282 | return (emit_mu_state (emit_init (&b, nsync_debug_buf, |
283 | (int) sizeof (nsync_debug_buf)), |
284 | mu, 0, 1)); |
285 | } |
286 | char *nsync_cv_debugger (nsync_cv *cv) { |
287 | struct emit_buf b; |
288 | return (emit_cv_state (emit_init (&b, nsync_debug_buf, |
289 | (int) sizeof (nsync_debug_buf)), |
290 | cv, 0, 1)); |
291 | } |
292 | |
293 | NSYNC_CPP_END_ |
294 | |