mesa/src/util/u_call_once.h

72 lines
1.7 KiB
C

/*
* Copyright 2022 Yonggang Luo
* SPDX-License-Identifier: MIT
*
* Extend C11 call_once to support context parameter
*/
#ifndef U_CALL_ONCE_H_
#define U_CALL_ONCE_H_
#include <stdbool.h>
#include "c11/threads.h"
#include "macros.h"
#include "u_atomic.h"
#ifdef __cplusplus
extern "C" {
#endif
/* The data can be mutable or immutable. */
typedef void (*util_call_once_data_func)(const void *data);
struct util_once_flag {
bool called;
once_flag flag;
};
typedef struct util_once_flag util_once_flag;
#define UTIL_ONCE_FLAG_INIT { false, ONCE_FLAG_INIT }
/**
* This is used to optimize the call to call_once out when the func are
* already called and finished, so when util_call_once are called in
* hot path it's only incur an extra load instruction cost.
*/
static ALWAYS_INLINE void
util_call_once(util_once_flag *flag, void (*func)(void))
{
if (unlikely(!p_atomic_read_relaxed(&flag->called))) {
call_once(&flag->flag, func);
p_atomic_set(&flag->called, true);
}
}
/**
* @brief Wrapper around call_once to pass data to func
*/
void
util_call_once_data_slow(once_flag *once, util_call_once_data_func func, const void *data);
/**
* This is used to optimize the call to util_call_once_data_slow out when
* the func function are already called and finished,
* so when util_call_once_data are called in hot path it's only incur an extra
* load instruction cost.
*/
static ALWAYS_INLINE void
util_call_once_data(util_once_flag *flag, util_call_once_data_func func, const void *data)
{
if (unlikely(!p_atomic_read_relaxed(&flag->called))) {
util_call_once_data_slow(&(flag->flag), func, data);
p_atomic_set(&flag->called, true);
}
}
#ifdef __cplusplus
}
#endif
#endif /* U_CALL_ONCE_H_ */