| 30 | namespace bthread { |
| 31 | |
| 32 | int bthread_once_impl(bthread_once_t* once_control, void (*init_routine)()) { |
| 33 | butil::atomic<int>* butex = once_control->_butex; |
| 34 | // We need acquire memory order for this load because if the value |
| 35 | // signals that initialization has finished, we need to see any |
| 36 | // data modifications done during initialization. |
| 37 | int val = butex->load(butil::memory_order_acquire); |
| 38 | if (BAIDU_LIKELY(val == bthread_once_t::INITIALIZED)) { |
| 39 | // The initialization has already been done. |
| 40 | return 0; |
| 41 | } |
| 42 | val = bthread_once_t::UNINITIALIZED; |
| 43 | if (butex->compare_exchange_strong(val, bthread_once_t::INPROGRESS, |
| 44 | butil::memory_order_relaxed, |
| 45 | butil::memory_order_relaxed)) { |
| 46 | // This (b)thread is the first and the Only one here. Do the initialization. |
| 47 | init_routine(); |
| 48 | // Mark *once_control as having finished the initialization. We need |
| 49 | // release memory order here because we need to synchronize with other |
| 50 | // (b)threads that want to use the initialized data. |
| 51 | butex->store(bthread_once_t::INITIALIZED, butil::memory_order_release); |
| 52 | // Wake up all other (b)threads. |
| 53 | bthread::butex_wake_all(butex); |
| 54 | return 0; |
| 55 | } |
| 56 | |
| 57 | while (true) { |
| 58 | // Same as above, we need acquire memory order. |
| 59 | val = butex->load(butil::memory_order_acquire); |
| 60 | if (BAIDU_LIKELY(val == bthread_once_t::INITIALIZED)) { |
| 61 | // The initialization has already been done. |
| 62 | return 0; |
| 63 | } |
| 64 | // Unless your constructor can be very time consuming, it is very unlikely o hit |
| 65 | // this race. When it does, we just wait the thread until the object has been created. |
| 66 | if (bthread::butex_wait(butex, val, NULL) < 0 && |
| 67 | errno != EWOULDBLOCK && errno != EINTR/*note*/) { |
| 68 | return errno; |
| 69 | } |
| 70 | } |
| 71 | } |
| 72 | |
| 73 | } // namespace bthread |
| 74 |
no test coverage detected