Skip to content

std::sync::Once has way more barriers than necessary #27610

Closed
@talchas

Description

@talchas

I believe that (comments removed)

    pub fn call_once<F>(&'static self, f: F) where F: FnOnce() {
        if self.cnt.load(Ordering::Acquire) < 0 {
            return
        }

        let prev = self.cnt.fetch_add(1, Ordering::Acquire);
        if prev < 0 {
            self.cnt.store(isize::MIN, Ordering::Release);
            return
        }

        let guard = self.mutex.lock();
        if self.cnt.load(Ordering::Relaxed) > 0 {
            f();
            let prev = self.cnt.swap(isize::MIN, Ordering::Release);
            self.lock_cnt.store(prev, Ordering::Release);
        }
        drop(guard);

        if self.lock_cnt.fetch_add(-1, Ordering::AcqRel) == 1 {
            unsafe { self.mutex.destroy() }
        }
    }

is the correct set of barriers (I'm not certain if the lock_cnt barriers can be Relaxed instead, but it's pretty irrelevant and these are safe).

At the very least I am /certain/ that the very first load can be Acquire instead of SeqCst, which removes the barrier from the fast-path on x86.

Metadata

Metadata

Assignees

No one assigned

    Labels

    C-enhancementCategory: An issue proposing an enhancement or a PR with one.I-slowIssue: Problems and improvements with respect to performance of generated code.T-libs-apiRelevant to the library API team, which will review and decide on the PR/issue.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions