| 146 | bool erase_from_butex(ButexWaiter*, bool, WaiterState); |
| 147 | |
| 148 | int wait_pthread(ButexPthreadWaiter& pw, const timespec* abstime) { |
| 149 | timespec* ptimeout = NULL; |
| 150 | timespec timeout; |
| 151 | int64_t timeout_us = 0; |
| 152 | int rc; |
| 153 | |
| 154 | while (true) { |
| 155 | if (abstime != NULL) { |
| 156 | timeout_us = butil::timespec_to_microseconds(*abstime) - butil::gettimeofday_us(); |
| 157 | timeout = butil::microseconds_to_timespec(timeout_us); |
| 158 | ptimeout = &timeout; |
| 159 | } |
| 160 | if (timeout_us > MIN_SLEEP_US || abstime == NULL) { |
| 161 | rc = futex_wait_private(&pw.sig, PTHREAD_NOT_SIGNALLED, ptimeout); |
| 162 | if (PTHREAD_NOT_SIGNALLED != pw.sig.load(butil::memory_order_acquire)) { |
| 163 | // If `sig' is changed, wakeup_pthread() must be called and `pw' |
| 164 | // is already removed from the butex. |
| 165 | // Acquire fence makes this thread sees changes before wakeup. |
| 166 | return rc; |
| 167 | } |
| 168 | } else { |
| 169 | errno = ETIMEDOUT; |
| 170 | rc = -1; |
| 171 | } |
| 172 | // Handle ETIMEDOUT when abstime is valid. |
| 173 | // If futex_wait_private return EINTR, just continue the loop. |
| 174 | if (rc != 0 && errno == ETIMEDOUT) { |
| 175 | // wait futex timeout, `pw' is still in the queue, remove it. |
| 176 | if (!erase_from_butex(&pw, false, WAITER_STATE_TIMEDOUT)) { |
| 177 | // Another thread is erasing `pw' as well, wait for the signal. |
| 178 | // Acquire fence makes this thread sees changes before wakeup. |
| 179 | if (pw.sig.load(butil::memory_order_acquire) == PTHREAD_NOT_SIGNALLED) { |
| 180 | // already timedout, abstime and ptimeout are expired. |
| 181 | abstime = NULL; |
| 182 | ptimeout = NULL; |
| 183 | continue; |
| 184 | } |
| 185 | } |
| 186 | return rc; |
| 187 | } |
| 188 | } |
| 189 | } |
| 190 | |
| 191 | extern BAIDU_THREAD_LOCAL TaskGroup* tls_task_group; |
| 192 |
no test coverage detected