| 565 | } |
| 566 | |
| 567 | int bthread_id_unlock(bthread_id_t id) { |
| 568 | bthread::Id* const meta = address_resource(bthread::get_slot(id)); |
| 569 | if (!meta) { |
| 570 | return EINVAL; |
| 571 | } |
| 572 | uint32_t* butex = meta->butex; |
| 573 | // Release fence makes sure all changes made before signal visible to |
| 574 | // woken-up waiters. |
| 575 | const uint32_t id_ver = bthread::get_version(id); |
| 576 | meta->mutex.lock(); |
| 577 | if (!meta->has_version(id_ver)) { |
| 578 | meta->mutex.unlock(); |
| 579 | LOG(FATAL) << "Invalid bthread_id=" << id.value; |
| 580 | return EINVAL; |
| 581 | } |
| 582 | if (*butex == meta->first_ver) { |
| 583 | meta->mutex.unlock(); |
| 584 | LOG(FATAL) << "bthread_id=" << id.value << " is not locked!"; |
| 585 | return EPERM; |
| 586 | } |
| 587 | bthread::PendingError front; |
| 588 | if (meta->pending_q.pop(&front)) { |
| 589 | meta->lock_location = front.location; |
| 590 | meta->mutex.unlock(); |
| 591 | if (meta->on_error) { |
| 592 | return meta->on_error(front.id, meta->data, front.error_code); |
| 593 | } else { |
| 594 | return meta->on_error2(front.id, meta->data, front.error_code, |
| 595 | front.error_text); |
| 596 | } |
| 597 | } else { |
| 598 | const bool contended = (*butex == meta->contended_ver()); |
| 599 | *butex = meta->first_ver; |
| 600 | meta->mutex.unlock(); |
| 601 | if (contended) { |
| 602 | // We may wake up already-reused id, but that's OK. |
| 603 | bthread::butex_wake(butex); |
| 604 | } |
| 605 | return 0; |
| 606 | } |
| 607 | } |
| 608 | |
| 609 | int bthread_id_unlock_and_destroy(bthread_id_t id) { |
| 610 | bthread::Id* const meta = address_resource(bthread::get_slot(id)); |