| 213 | } |
| 214 | |
| 215 | void OnSubDoneRun(SubDone* fin) { |
| 216 | if (fin != NULL) { |
| 217 | // [ called from SubDone::Run() ] |
| 218 | |
| 219 | int error_code = fin->cntl.ErrorCode(); |
| 220 | // EPCHANFINISH is not an error of sub calls. |
| 221 | bool fail = 0 != error_code && EPCHANFINISH != error_code; |
| 222 | bool cancel = |
| 223 | // Count failed sub calls, if `fail_limit' is reached, cancel others. |
| 224 | (fail && _current_fail.fetch_add(1, butil::memory_order_relaxed) + 1 |
| 225 | == _fail_limit) || |
| 226 | // Count successful sub calls, if `success_limit' is reached, cancel others. |
| 227 | (0 == error_code && |
| 228 | _current_success.fetch_add(1, butil::memory_order_relaxed) + 1 |
| 229 | == _success_limit); |
| 230 | |
| 231 | if (cancel) { |
| 232 | // Only cancel once by `fail_limit' or `success_limit'. |
| 233 | for (int i = 0; i < _ndone; ++i) { |
| 234 | SubDone* sd = sub_done(i); |
| 235 | if (fin != sd) { |
| 236 | bthread_id_error( |
| 237 | sd->cntl.call_id(), fail ? ECANCELED : EPCHANFINISH); |
| 238 | } |
| 239 | } |
| 240 | } |
| 241 | // NOTE: Don't access any member after the fetch_add because |
| 242 | // another thread may already go down and Destroy()-ed this object. |
| 243 | const uint32_t saved_ndone = _ndone; |
| 244 | const CallId saved_cid = _cntl->_correlation_id; |
| 245 | // Add 1 to finished sub calls. |
| 246 | // The release fence is matched with acquire fence below to |
| 247 | // guarantee visibilities of all other variables. |
| 248 | const uint32_t val = |
| 249 | _current_done.fetch_add(1, butil::memory_order_release); |
| 250 | // Lower 31 bits are number of finished sub calls. If caller is not |
| 251 | // the last call that finishes, return. |
| 252 | if ((val & 0x7fffffff) + 1 != saved_ndone) { |
| 253 | return; |
| 254 | } |
| 255 | // If _cntl->call_id() is still there, stop it by sending a special |
| 256 | // error(which will be cleared) and return. |
| 257 | if (!(val & 0x80000000)) { |
| 258 | bthread_id_error(saved_cid, EPCHANFINISH); |
| 259 | return; |
| 260 | } |
| 261 | } else { |
| 262 | // [ Called from this->Run() ] |
| 263 | |
| 264 | // We may cancel sub calls even if all sub calls finish because |
| 265 | // of reading the value relaxly (and CPU cache is not sync yet). |
| 266 | // It's OK and we have to, because sub_done can't be accessed |
| 267 | // after fetch_or. |
| 268 | uint32_t val = _current_done.load(butil::memory_order_relaxed); |
| 269 | // Lower 31 bits are number of finished sub calls. Cancel sub calls |
| 270 | // if not all of them finish. |
| 271 | if ((val & 0x7fffffff) != (uint32_t)_ndone) { |
| 272 | for (int i = 0; i < _ndone; ++i) { |
no test coverage detected