blob: 6ea87047319181f95533540c4b23c06030e0f118 [file] [log] [blame]
// Copyright 2016 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef GARNET_LIB_MAGMA_SRC_MAGMA_UTIL_MACROS_H_
#define GARNET_LIB_MAGMA_SRC_MAGMA_UTIL_MACROS_H_
#include <assert.h>
#include <limits.h> // PAGE_SIZE
#include <stdarg.h>
#include <stdio.h>
// Files #including macros.h may assume that it #includes inttypes.h.
// So, for convenience, they don't need to follow "#include-what-you-use" for that header.
#include <inttypes.h>
#ifndef MAGMA_DEBUG_INTERNAL_USE_ONLY
#error MAGMA_DEBUG_INTERNAL_USE_ONLY not defined, your gn foo needs magma_util_config
#endif
namespace magma {
static constexpr bool kDebug = MAGMA_DEBUG_INTERNAL_USE_ONLY;
#define DASSERT(...) \
do { \
if (magma::kDebug && !(__VA_ARGS__)) { \
printf("%s:%d ASSERT\n", __FILE__, __LINE__); \
assert(__VA_ARGS__); \
} \
} while (0)
#define DMESSAGE(...) \
do { \
if (magma::kDebug) { \
printf("%s:%d ", __FILE__, __LINE__); \
printf(__VA_ARGS__); \
} \
} while (0)
static constexpr bool kMagmaDretEnable = kDebug;
template <typename T>
__attribute__((format(printf, 4, 5))) static inline T dret(const char* file, int line, T ret,
const char* msg, ...)
{
printf(sizeof(T) == sizeof(uint64_t) ? "%s:%d returning error %lu" : "%s:%d returning error %d",
file, line, ret);
if (msg) {
va_list args;
va_start(args, msg);
printf(": ");
vprintf(msg, args);
va_end(args);
}
printf("\n");
return ret;
}
#define DRET(ret) \
(magma::kMagmaDretEnable ? (ret == 0 ? ret : magma::dret(__FILE__, __LINE__, ret, nullptr)) \
: ret)
// Must provide const char* msg as the 2nd parameter; other parameters optional.
#define DRET_MSG(ret, ...) \
(magma::kMagmaDretEnable \
? (ret == 0 ? ret : magma::dret(__FILE__, __LINE__, ret, __VA_ARGS__)) \
: ret)
__attribute__((format(printf, 3, 4))) static inline bool dret_false(const char* file, int line,
const char* msg, ...)
{
printf("%s:%d returning false: ", file, line);
va_list args;
va_start(args, msg);
vprintf(msg, args);
va_end(args);
printf("\n");
return false;
}
// Must provide const char* msg as the 2nd parameter; other parameters optional.
#define DRETF(ret, ...) \
(magma::kMagmaDretEnable \
? (ret == true ? true : magma::dret_false(__FILE__, __LINE__, __VA_ARGS__)) \
: ret)
__attribute__((format(printf, 3, 4))) static inline void dret_null(const char* file, int line,
const char* msg, ...)
{
printf("%s:%d returning null: ", file, line);
va_list args;
va_start(args, msg);
vprintf(msg, args);
va_end(args);
printf("\n");
}
// Must provide const char* msg as the 2nd parameter; other parameters optional.
#define DRETP(ret, ...) \
(magma::kMagmaDretEnable \
? (ret != nullptr ? ret : (magma::dret_null(__FILE__, __LINE__, __VA_ARGS__), nullptr)) \
: ret)
enum LogLevel { LOG_WARNING, LOG_INFO };
__attribute__((format(printf, 2, 3))) static inline void log(LogLevel level, const char* msg, ...)
{
switch (level) {
case LOG_WARNING:
printf("[WARNING] ");
break;
case LOG_INFO:
printf("[INFO] ");
break;
}
va_list args;
va_start(args, msg);
vprintf(msg, args);
va_end(args);
printf("\n");
}
#define UNIMPLEMENTED(...) \
do { \
DLOG("UNIMPLEMENTED: " #__VA_ARGS__); \
DASSERT(false); \
} while (0)
#define ATTRIBUTE_UNUSED __attribute__((unused))
#ifndef DISALLOW_COPY_AND_ASSIGN
#define DISALLOW_COPY_AND_ASSIGN(TypeName) \
TypeName(const TypeName&) = delete; \
void operator=(const TypeName&) = delete
#endif
static inline bool is_page_aligned(uint64_t val) { return (val & (PAGE_SIZE - 1)) == 0; }
static inline uint32_t upper_32_bits(uint64_t n) { return static_cast<uint32_t>(n >> 32); }
static inline uint32_t lower_32_bits(uint64_t n) { return static_cast<uint32_t>(n); }
static inline bool get_pow2(uint64_t val, uint64_t* pow2_out)
{
if (val == 0)
return DRETF(false, "zero is not a power of two");
uint64_t result = 0;
while ((val & 1) == 0) {
val >>= 1;
result++;
}
if (val >> 1)
return DRETF(false, "not a power of 2");
*pow2_out = result;
return true;
}
static inline bool is_pow2(uint64_t val)
{
uint64_t out;
return get_pow2(val, &out);
}
// Note, alignment must be a power of 2
template <class T> static inline T round_up(T val, uint32_t alignment)
{
DASSERT(is_pow2(alignment));
return ((val - 1) | (alignment - 1)) + 1;
}
static inline uint64_t ns_to_ms(uint64_t ns) { return ns / 1000000ull; }
static inline int64_t ms_to_signed_ns(uint64_t ms)
{
if (ms > INT64_MAX / 1000000)
return INT64_MAX;
return static_cast<int64_t>(ms) * 1000000;
}
#define MAGMA_THREAD_ANNOTATION(x) __attribute__((x))
#define MAGMA_CAPABILITY(x) MAGMA_THREAD_ANNOTATION(__capability__(x))
#define MAGMA_GUARDED(x) MAGMA_THREAD_ANNOTATION(__guarded_by__(x))
#define MAGMA_ACQUIRE(...) MAGMA_THREAD_ANNOTATION(__acquire_capability__(__VA_ARGS__))
#define MAGMA_TRY_ACQUIRE(...) MAGMA_THREAD_ANNOTATION(__try_acquire_capability__(__VA_ARGS__))
#define MAGMA_ACQUIRED_BEFORE(...) MAGMA_THREAD_ANNOTATION(__acquired_before__(__VA_ARGS__))
#define MAGMA_ACQUIRED_AFTER(...) MAGMA_THREAD_ANNOTATION(__acquired_after__(__VA_ARGS__))
#define MAGMA_RELEASE(...) MAGMA_THREAD_ANNOTATION(__release_capability__(__VA_ARGS__))
#define MAGMA_REQUIRES(...) MAGMA_THREAD_ANNOTATION(__requires_capability__(__VA_ARGS__))
#define MAGMA_EXCLUDES(...) MAGMA_THREAD_ANNOTATION(__locks_excluded__(__VA_ARGS__))
#define MAGMA_RETURN_CAPABILITY(x) MAGMA_THREAD_ANNOTATION(__lock_returned__(x))
#define MAGMA_SCOPED_CAPABILITY MAGMA_THREAD_ANNOTATION(__scoped_lockable__)
#define MAGMA_NO_THREAD_SAFETY_ANALYSIS MAGMA_THREAD_ANNOTATION(__no_thread_safety_analysis__)
} // namespace magma
#endif // GARNET_LIB_MAGMA_SRC_MAGMA_UTIL_MACROS_H_