Commit 19cc838
Stop thread-jumps before shutdown frees the proxies
Summary:
`CarbonRouterInstance::shutdownImpl()` calls `proxyEvbs_.clear()`, which
destroys the `VirtualEventBase`s one at a time and frees each `Proxy` along
with them (`Proxy::createProxy` ties the two together via `runOnDestruction`).
The other proxy IO threads are still routing at that point -- the join comes
later -- and `proxies_` is a vector of raw `Proxy*` that is never cleared. So a
request that thread-jumps on a live proxy can resolve a target that `clear()`
has already freed.
Confirmed on two coredumps (aarch64 and x86-64) from the `fbpkg` /
`fbpkg.fetch` CLIs, which stand up and tear down a router on every invocation:
mov (%rcx,%rdx,8),%rax ; rax = proxies_[idx] -- ok
mov 0x18(%rax),%rbx ; rbx = Proxy->eventBase_ -- ok, read 0
...
mov 0x18(%rbx),%rcx ; SIGSEGV at 0x18, rbx == 0
`proxies_[i]` was still readable, but `eventBase_` -- a reference member that
cannot be null in a live `Proxy` -- read 0. The object had been freed and its
memory recycled. The x86 faulting `rip` matches the stack reported in S688594.
Two halves, because there are two populations of dangerous hops:
- New hops. `proxiesDraining_` is set at the start of proxy teardown (after
`joinAuxiliaryThreads()`, before anything is destroyed) and checked by the
two accessors that resolve a hop target, `getProxyForThreadJump()` and
`getProxyBaseForThreadJump()`. While draining they return nullptr and the
caller routes locally -- the existing "stay on this thread" path, which every
hop site already handles.
- In-flight hops. `fenceProxyEventBases()` round-trips every proxy event base
before any `VirtualEventBase` is destroyed. No hop site suspends between
resolving a target and enqueueing on it, so a hop that read the flag as false
is still running inline on its source proxy's thread, and the fence task
queued there cannot run until it finishes. Once every proxy has passed the
fence, each pending hop is covered by a keep-alive on its target, and
`~VirtualEventBase()` blocks on those.
Relaxed ordering is sufficient: the happens-before comes from the fence's
notification queue, not from the flag.
Cost is one relaxed load of a read-mostly flag per hop resolution, behind a
consistent-hash lookup (SRRoute) or a full route-handle traverse
(Multi\*Routes). `getProxyFromHash()` is replaced by `getProxyForThreadJump()`;
it had one in-tree caller, but was public on an OSS-mirrored header, so this is
an API break for the GitHub mirror.
Reviewed By: vrishal, stuclar
Differential Revision: D115935603
fbshipit-source-id: 3927b8d85512262cf222b106e6aa3d8230cee68f1 parent c2b8413 commit 19cc838
3 files changed
Lines changed: 177 additions & 2 deletions
File tree
- mcrouter
- test/cpp_unit_tests
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
403 | 403 | | |
404 | 404 | | |
405 | 405 | | |
| 406 | + | |
| 407 | + | |
| 408 | + | |
| 409 | + | |
| 410 | + | |
| 411 | + | |
| 412 | + | |
| 413 | + | |
| 414 | + | |
| 415 | + | |
| 416 | + | |
406 | 417 | | |
407 | 418 | | |
408 | 419 | | |
| |||
412 | 423 | | |
413 | 424 | | |
414 | 425 | | |
| 426 | + | |
| 427 | + | |
| 428 | + | |
415 | 429 | | |
416 | 430 | | |
417 | 431 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
15 | 15 | | |
16 | 16 | | |
17 | 17 | | |
| 18 | + | |
| 19 | + | |
18 | 20 | | |
19 | 21 | | |
20 | 22 | | |
| |||
241 | 243 | | |
242 | 244 | | |
243 | 245 | | |
244 | | - | |
245 | | - | |
| 246 | + | |
| 247 | + | |
| 248 | + | |
| 249 | + | |
| 250 | + | |
| 251 | + | |
| 252 | + | |
| 253 | + | |
| 254 | + | |
| 255 | + | |
| 256 | + | |
246 | 257 | | |
247 | 258 | | |
248 | 259 | | |
| |||
267 | 278 | | |
268 | 279 | | |
269 | 280 | | |
| 281 | + | |
| 282 | + | |
| 283 | + | |
| 284 | + | |
| 285 | + | |
| 286 | + | |
| 287 | + | |
270 | 288 | | |
271 | 289 | | |
272 | 290 | | |
| |||
305 | 323 | | |
306 | 324 | | |
307 | 325 | | |
| 326 | + | |
| 327 | + | |
| 328 | + | |
| 329 | + | |
308 | 330 | | |
309 | 331 | | |
310 | 332 | | |
| |||
Lines changed: 139 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
| 81 | + | |
| 82 | + | |
| 83 | + | |
| 84 | + | |
| 85 | + | |
| 86 | + | |
| 87 | + | |
| 88 | + | |
| 89 | + | |
| 90 | + | |
| 91 | + | |
| 92 | + | |
| 93 | + | |
| 94 | + | |
| 95 | + | |
| 96 | + | |
| 97 | + | |
| 98 | + | |
| 99 | + | |
| 100 | + | |
| 101 | + | |
| 102 | + | |
| 103 | + | |
| 104 | + | |
| 105 | + | |
| 106 | + | |
| 107 | + | |
| 108 | + | |
| 109 | + | |
| 110 | + | |
| 111 | + | |
| 112 | + | |
| 113 | + | |
| 114 | + | |
| 115 | + | |
| 116 | + | |
| 117 | + | |
| 118 | + | |
| 119 | + | |
| 120 | + | |
| 121 | + | |
| 122 | + | |
| 123 | + | |
| 124 | + | |
| 125 | + | |
| 126 | + | |
| 127 | + | |
| 128 | + | |
| 129 | + | |
| 130 | + | |
| 131 | + | |
| 132 | + | |
| 133 | + | |
| 134 | + | |
| 135 | + | |
| 136 | + | |
| 137 | + | |
| 138 | + | |
| 139 | + | |
0 commit comments