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

Function butex_wait

src/bthread/butex.cpp:670–750  ·  view source on GitHub ↗

Source from the content-addressed store, hash-verified

668}
669
670int butex_wait(void* arg, int expected_value, const timespec* abstime, bool prepend) {
671 Butex* b = container_of(static_cast<butil::atomic<int>*>(arg), Butex, value);
672 if (b->value.load(butil::memory_order_relaxed) != expected_value) {
673 errno = EWOULDBLOCK;
674 // Sometimes we may take actions immediately after unmatched butex,
675 // this fence makes sure that we see changes before changing butex.
676 butil::atomic_thread_fence(butil::memory_order_acquire);
677 return -1;
678 }
679 TaskGroup* g = tls_task_group;
680 if (NULL == g || g->is_current_pthread_task()) {
681 return butex_wait_from_pthread(g, b, expected_value, abstime, prepend);
682 }
683 ButexBthreadWaiter bbw;
684 // tid is 0 iff the thread is non-bthread
685 bbw.tid = g->current_tid();
686 bbw.container.store(NULL, butil::memory_order_relaxed);
687 bbw.task_meta = g->current_task();
688 bbw.sleep_id = 0;
689 bbw.waiter_state = WAITER_STATE_READY;
690 bbw.expected_value = expected_value;
691 bbw.initial_butex = b;
692 bbw.control = g->control();
693 bbw.abstime = abstime;
694 bbw.tag = g->tag();
695
696 if (abstime != NULL) {
697 // Schedule timer before queueing. If the timer is triggered before
698 // queueing, cancel queueing. This is a kind of optimistic locking.
699 if (butil::timespec_to_microseconds(*abstime) <
700 (butil::gettimeofday_us() + MIN_SLEEP_US)) {
701 // Already timed out.
702 errno = ETIMEDOUT;
703 return -1;
704 }
705 }
706#ifdef SHOW_BTHREAD_BUTEX_WAITER_COUNT_IN_VARS
707 bvar::Adder<int64_t>& num_waiters = butex_waiter_count();
708 num_waiters << 1;
709#endif
710
711 // release fence matches with acquire fence in interrupt_and_consume_waiters
712 // in task_group.cpp to guarantee visibility of `interrupted'.
713 bbw.task_meta->current_waiter.store(&bbw, butil::memory_order_release);
714 WaitForButexArgs args{ &bbw, prepend };
715 g->set_remained(wait_for_butex, &args);
716 TaskGroup::sched(&g);
717
718 // erase_from_butex_and_wakeup (called by TimerThread) is possibly still
719 // running and using bbw. The chance is small, just spin until it's done.
720 BT_LOOP_WHEN(unsleep_if_necessary(&bbw, get_global_timer_thread()) < 0,
721 30/*nops before sched_yield*/);
722
723 // If current_waiter is NULL, TaskGroup::interrupt() is running and using bbw.
724 // Spin until current_waiter != NULL.
725 BT_LOOP_WHEN(bbw.task_meta->current_waiter.exchange(
726 NULL, butil::memory_order_acquire) == NULL,
727 30/*nops before sched_yield*/);

Callers 15

odd_threadFunction · 0.85
even_threadFunction · 0.85
TESTFunction · 0.85
waiterFunction · 0.85
wait_butexFunction · 0.85
butex_playerFunction · 0.85
WaitEpollOutMethod · 0.85
joinMethod · 0.85
WaitEpollOutMethod · 0.85
ReadFromFdMethod · 0.85

Calls 15

atomic_thread_fenceFunction · 0.85
butex_wait_from_pthreadFunction · 0.85
timespec_to_microsecondsFunction · 0.85
unsleep_if_necessaryFunction · 0.85
get_global_timer_threadFunction · 0.85
current_tidMethod · 0.80
current_taskMethod · 0.80
controlMethod · 0.80
tagMethod · 0.80
set_remainedMethod · 0.80
gettimeofday_usFunction · 0.50

Tested by 6

odd_threadFunction · 0.68
even_threadFunction · 0.68
TESTFunction · 0.68
waiterFunction · 0.68
wait_butexFunction · 0.68
butex_playerFunction · 0.68