/* Copyright (c) 2022 Dennis Wölfing
 *
 * Permission to use, copy, modify, and/or distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

/* libc/src/thread/call_once.c
 * One-time initialization. (C11, called from POSIX2008)
 */

#define sched_yield __sched_yield
#include "thread.h"
#include <stdbool.h>

void __call_once(__once_t* once, void (*func)(void)) {
    if (__atomic_load_n(once, __ATOMIC_ACQUIRE) < 2) {
        unsigned char expected = 0;
        if (__atomic_compare_exchange_n(once, &expected, 1, false,
                __ATOMIC_RELAXED, __ATOMIC_RELAXED)) {
            func();
            __atomic_store_n(once, 2, __ATOMIC_RELEASE);
        } else {
            while (__atomic_load_n(once, __ATOMIC_ACQUIRE) == 1) {
                sched_yield();
            }
        }
    }
}
__weak_alias(__call_once, call_once);
