Details
-
Bug
-
Status: Closed
-
Major - P3
-
Resolution: Won't Fix
-
None
-
None
-
None
-
ALL
-
Service Arch 2021-11-15, Service Arch 2021-12-13, Service Arch 2022-1-10, Service Arch 2022-1-24
-
4
Description
If we call shutdown on a NetworkInterfaceTL before it starts up, we simply move kStopped into its _state member and do nothing else: see here
void NetworkInterfaceTL::shutdown() { |
if (_state.swap(kStopped) != kStarted) |
return; |
This becomes a problem if startup is ever called on the same NetworkInterfaceTL before shutdown completes; we'll fail this invariant in startup here:
void NetworkInterfaceTL::startup() { |
stdx::lock_guard<Latch> lk(_mutex);
|
|
_ioThread = stdx::thread([this] { |
setThreadName(_instanceName);
|
_run();
|
});
|
|
invariant(_state.swap(kStarted) == kDefault);
|
}
|
because the _state will will been kStopped, not kDefault, before this was called.
This is also a problem for the shutdown of ThreadPoolTaskExecutors, as they wrap a NetworkInterfaceTL. On startup, these executors call startup on the backing NetworkInterfaceTL. And if join is called on such an executor, it will call shutdown on the underlying NetworkInterface. So if join is called before startup is on such an executor, we'll encounter the same invariant.
Acceptance criteria: make the invariant an exception/investigate it thoroughly and ensure lifetime semantics of NetworkInterfaceTL is clear