MCPcopy Create free account
hub / github.com/apache/brpc / dereference

Method dereference

src/bthread/execution_queue_inl.h:529–585  ·  view source on GitHub ↗

Source from the content-addressed store, hash-verified

527}
528
529inline int ExecutionQueueBase::dereference() {
530 const uint64_t vref = _versioned_ref.fetch_sub(
531 1, butil::memory_order_release);
532 const int32_t nref = _ref_of_vref(vref);
533 // We need make the fast path as fast as possible, don't put any extra
534 // code before this point
535 if (nref > 1) {
536 return 0;
537 }
538 const uint64_t id = _this_id;
539 if (__builtin_expect(nref == 1, 1)) {
540 const uint32_t ver = _version_of_vref(vref);
541 const uint32_t id_ver = _version_of_id(id);
542 // Besides first successful stop() adds 1 to version, one of
543 // those dereferencing nref from 1->0 adds another 1 to version.
544 // Notice "one of those": The wait-free address() may make ref of a
545 // version-unmatched slot change from 1 to 0 for mutiple times, we
546 // have to use version as a guard variable to prevent returning the
547 // executor to pool more than once.
548 if (__builtin_expect(ver == id_ver || ver == id_ver + 1, 1)) {
549 // sees nref:1->0, try to set version=id_ver+2,--nref.
550 // No retry: if version changes, the slot is already returned by
551 // another one who sees nref:1->0 concurrently; if nref changes,
552 // which must be non-zero, the slot will be returned when
553 // nref changes from 1->0 again.
554 // Example:
555 // stop(): --nref, sees nref:1->0 (1)
556 // try to set version=id_ver+2 (2)
557 // address(): ++nref, unmatched version (3)
558 // --nref, sees nref:1->0 (4)
559 // try to set version=id_ver+2 (5)
560 // 1,2,3,4,5 or 1,3,4,2,5:
561 // stop() succeeds, address() fails at (5).
562 // 1,3,2,4,5: stop() fails with (2), the slot will be
563 // returned by (5) of address()
564 // 1,3,4,5,2: stop() fails with (2), the slot is already
565 // returned by (5) of address().
566 uint64_t expected_vref = vref - 1;
567 if (_versioned_ref.compare_exchange_strong(
568 expected_vref, _make_vref(id_ver + 2, 0),
569 butil::memory_order_acquire,
570 butil::memory_order_relaxed)) {
571 _on_recycle();
572 // We don't return m immediately when the reference count
573 // reaches 0 as there might be in processing tasks. Instead
574 // _on_recycle would push a `stop_task' after which is executed
575 // m would be finally returned and reset
576 return 1;
577 }
578 return 0;
579 }
580 LOG(FATAL) << "Invalid id=" << id;
581 return -1;
582 }
583 LOG(FATAL) << "Over dereferenced id=" << id;
584 return -1;
585}
586

Callers 2

operator()Method · 0.80
operator()Method · 0.80

Calls 6

_ref_of_vrefFunction · 0.85
_version_of_vrefFunction · 0.85
_version_of_idFunction · 0.85
_make_vrefFunction · 0.85
fetch_subMethod · 0.80

Tested by

no test coverage detected