| 662 | } |
| 663 | |
| 664 | void |
| 665 | lock_profile_release_lock(struct lock_object *lo) |
| 666 | { |
| 667 | struct lock_profile_object *l; |
| 668 | struct lock_prof_type *type; |
| 669 | struct lock_prof *lp; |
| 670 | uint64_t curtime, holdtime; |
| 671 | struct lpohead *head; |
| 672 | int spin; |
| 673 | |
| 674 | if (SCHEDULER_STOPPED()) |
| 675 | return; |
| 676 | if (lo->lo_flags & LO_NOPROFILE) |
| 677 | return; |
| 678 | spin = (LOCK_CLASS(lo)->lc_flags & LC_SPINLOCK) ? 1 : 0; |
| 679 | head = &curthread->td_lprof[spin]; |
| 680 | if (LIST_FIRST(head) == NULL) |
| 681 | return; |
| 682 | critical_enter(); |
| 683 | /* Recheck enabled now that we're in a critical section. */ |
| 684 | if (lock_prof_enable == 0 && lock_prof_resetting == 1) |
| 685 | goto out; |
| 686 | /* |
| 687 | * If lock profiling is not enabled we still want to remove the |
| 688 | * lpo from our queue. |
| 689 | */ |
| 690 | LIST_FOREACH(l, head, lpo_link) |
| 691 | if (l->lpo_obj == lo) |
| 692 | break; |
| 693 | if (l == NULL) |
| 694 | goto out; |
| 695 | if (--l->lpo_ref > 0) |
| 696 | goto out; |
| 697 | lp = lock_profile_lookup(lo, spin, l->lpo_file, l->lpo_line); |
| 698 | if (lp == NULL) |
| 699 | goto release; |
| 700 | curtime = nanoseconds(); |
| 701 | if (curtime < l->lpo_acqtime) |
| 702 | goto release; |
| 703 | holdtime = curtime - l->lpo_acqtime; |
| 704 | |
| 705 | /* |
| 706 | * Record if the lock has been held longer now than ever |
| 707 | * before. |
| 708 | */ |
| 709 | if (holdtime > lp->cnt_max) |
| 710 | lp->cnt_max = holdtime; |
| 711 | if (l->lpo_waittime > lp->cnt_wait_max) |
| 712 | lp->cnt_wait_max = l->lpo_waittime; |
| 713 | lp->cnt_tot += holdtime; |
| 714 | lp->cnt_wait += l->lpo_waittime; |
| 715 | lp->cnt_contest_locking += l->lpo_contest_locking; |
| 716 | lp->cnt_cur += l->lpo_cnt; |
| 717 | release: |
| 718 | LIST_REMOVE(l, lpo_link); |
| 719 | type = &LP_CPU_SELF->lpc_types[spin]; |
| 720 | LIST_INSERT_HEAD(&type->lpt_lpoalloc, l, lpo_link); |
| 721 | out: |
no test coverage detected