mirror of https://github.com/trapexit/mergerfs.git
Browse Source
Add manual GC triggering + configurable process queue depth
Add manual GC triggering + configurable process queue depth
Yes, these are unrelated changes but somehow ended up being prototyped together and I'm too lazy to separate them.pull/1204/head
Antonio SJ Musumeci
2 years ago
27 changed files with 1442 additions and 345 deletions
-
44README.md
-
12libfuse/Makefile
-
5libfuse/include/fuse.h
-
1libfuse/include/fuse_lowlevel.h
-
3libfuse/include/fuse_msgbuf.h
-
31libfuse/lib/bounded_queue.hpp
-
143libfuse/lib/bounded_thread_pool.hpp
-
401libfuse/lib/fuse.c
-
267libfuse/lib/fuse_loop_mt.cpp
-
106libfuse/lib/fuse_msgbuf.cpp
-
9libfuse/lib/fuse_msgbuf.hpp
-
1libfuse/lib/fuse_mt.c
-
16libfuse/lib/fuse_signals.c
-
13libfuse/lib/lock.h
-
41libfuse/lib/make_unique.hpp
-
60libfuse/lib/node.c
-
30libfuse/lib/node.h
-
369libfuse/lib/scope_guard.hpp
-
110libfuse/lib/syslog.c
-
30libfuse/lib/syslog.h
-
1libfuse/lib/thread_pool.hpp
-
49man/mergerfs.1
-
3src/config.cpp
-
1src/config.hpp
-
14src/fuse_ioctl.cpp
-
26src/mergerfs.cpp
-
1src/option_parser.cpp
@ -0,0 +1,143 @@ |
|||||
|
#pragma once
|
||||
|
|
||||
|
#include "bounded_queue.hpp"
|
||||
|
#include "make_unique.hpp"
|
||||
|
|
||||
|
#include <signal.h>
|
||||
|
|
||||
|
#include <tuple>
|
||||
|
#include <atomic>
|
||||
|
#include <vector>
|
||||
|
#include <thread>
|
||||
|
#include <memory>
|
||||
|
#include <future>
|
||||
|
#include <utility>
|
||||
|
#include <functional>
|
||||
|
#include <type_traits>
|
||||
|
|
||||
|
|
||||
|
class BoundedThreadPool |
||||
|
{ |
||||
|
private: |
||||
|
using Proc = std::function<void(void)>; |
||||
|
using Queue = BoundedQueue<Proc>; |
||||
|
using Queues = std::vector<std::unique_ptr<Queue>>; |
||||
|
|
||||
|
public: |
||||
|
explicit |
||||
|
BoundedThreadPool(const std::size_t thread_count_ = std::thread::hardware_concurrency(), |
||||
|
const std::size_t queue_depth_ = 1) |
||||
|
: _queues(), |
||||
|
_count(thread_count_) |
||||
|
{ |
||||
|
for(std::size_t i = 0; i < thread_count_; i++) |
||||
|
_queues.emplace_back(std::make_unique<Queue>(queue_depth_)); |
||||
|
|
||||
|
auto worker = [this](std::size_t i) |
||||
|
{ |
||||
|
while(true) |
||||
|
{ |
||||
|
Proc f; |
||||
|
|
||||
|
for(std::size_t n = 0; n < (_count * K); ++n) |
||||
|
{ |
||||
|
if(_queues[(i + n) % _count]->pop(f)) |
||||
|
break; |
||||
|
} |
||||
|
|
||||
|
if(!f && !_queues[i]->pop(f)) |
||||
|
break; |
||||
|
|
||||
|
f(); |
||||
|
} |
||||
|
}; |
||||
|
|
||||
|
sigset_t oldset; |
||||
|
sigset_t newset; |
||||
|
|
||||
|
sigfillset(&newset); |
||||
|
pthread_sigmask(SIG_BLOCK,&newset,&oldset); |
||||
|
|
||||
|
_threads.reserve(thread_count_); |
||||
|
for(std::size_t i = 0; i < thread_count_; ++i) |
||||
|
_threads.emplace_back(worker, i); |
||||
|
|
||||
|
pthread_sigmask(SIG_SETMASK,&oldset,NULL); |
||||
|
} |
||||
|
|
||||
|
~BoundedThreadPool() |
||||
|
{ |
||||
|
for(auto &queue : _queues) |
||||
|
queue->unblock(); |
||||
|
for(auto &thread : _threads) |
||||
|
pthread_cancel(thread.native_handle()); |
||||
|
for(auto &thread : _threads) |
||||
|
thread.join(); |
||||
|
} |
||||
|
|
||||
|
template<typename F> |
||||
|
void |
||||
|
enqueue_work(F&& f_) |
||||
|
{ |
||||
|
auto i = _index++; |
||||
|
|
||||
|
for(std::size_t n = 0; n < (_count * K); ++n) |
||||
|
{ |
||||
|
if(_queues[(i + n) % _count]->push(f_)) |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
_queues[i % _count]->push(std::move(f_)); |
||||
|
} |
||||
|
|
||||
|
template<typename F> |
||||
|
[[nodiscard]] |
||||
|
std::future<typename std::result_of<F()>::type> |
||||
|
enqueue_task(F&& f_) |
||||
|
{ |
||||
|
using TaskReturnType = typename std::result_of<F()>::type; |
||||
|
using Promise = std::promise<TaskReturnType>; |
||||
|
|
||||
|
auto i = _index++; |
||||
|
auto promise = std::make_shared<Promise>(); |
||||
|
auto future = promise->get_future(); |
||||
|
auto work = [=]() { |
||||
|
auto rv = f_(); |
||||
|
promise->set_value(rv); |
||||
|
}; |
||||
|
|
||||
|
for(std::size_t n = 0; n < (_count * K); ++n) |
||||
|
{ |
||||
|
if(_queues[(i + n) % _count]->push(work)) |
||||
|
return future; |
||||
|
} |
||||
|
|
||||
|
_queues[i % _count]->push(std::move(work)); |
||||
|
|
||||
|
return future; |
||||
|
} |
||||
|
|
||||
|
public: |
||||
|
std::vector<pthread_t> |
||||
|
threads() |
||||
|
{ |
||||
|
std::vector<pthread_t> rv; |
||||
|
|
||||
|
for(auto &thread : _threads) |
||||
|
rv.push_back(thread.native_handle()); |
||||
|
|
||||
|
return rv; |
||||
|
} |
||||
|
|
||||
|
private: |
||||
|
Queues _queues; |
||||
|
|
||||
|
private: |
||||
|
std::vector<std::thread> _threads; |
||||
|
|
||||
|
private: |
||||
|
const std::size_t _count; |
||||
|
std::atomic_uint _index; |
||||
|
|
||||
|
static const unsigned int K = 2; |
||||
|
}; |
@ -0,0 +1,13 @@ |
|||||
|
#include <stdint.h> |
||||
|
#include <sys/types.h> |
||||
|
|
||||
|
typedef struct lock_s lock_t; |
||||
|
struct lock_s |
||||
|
{ |
||||
|
int type; |
||||
|
off_t start; |
||||
|
off_t end; |
||||
|
pid_t pid; |
||||
|
uint64_t owner; |
||||
|
lock_t *next; |
||||
|
}; |
@ -0,0 +1,41 @@ |
|||||
|
#include <cstddef>
|
||||
|
#include <memory>
|
||||
|
#include <type_traits>
|
||||
|
#include <utility>
|
||||
|
|
||||
|
namespace std |
||||
|
{ |
||||
|
template<class T> struct _Unique_if |
||||
|
{ |
||||
|
typedef unique_ptr<T> _Single_object; |
||||
|
}; |
||||
|
|
||||
|
template<class T> struct _Unique_if<T[]> |
||||
|
{ |
||||
|
typedef unique_ptr<T[]> _Unknown_bound; |
||||
|
}; |
||||
|
|
||||
|
template<class T, size_t N> struct _Unique_if<T[N]> |
||||
|
{ |
||||
|
typedef void _Known_bound; |
||||
|
}; |
||||
|
|
||||
|
template<class T, class... Args> |
||||
|
typename _Unique_if<T>::_Single_object |
||||
|
make_unique(Args&&... args) |
||||
|
{ |
||||
|
return unique_ptr<T>(new T(std::forward<Args>(args)...)); |
||||
|
} |
||||
|
|
||||
|
template<class T> |
||||
|
typename _Unique_if<T>::_Unknown_bound |
||||
|
make_unique(size_t n) |
||||
|
{ |
||||
|
typedef typename remove_extent<T>::type U; |
||||
|
return unique_ptr<T>(new U[n]()); |
||||
|
} |
||||
|
|
||||
|
template<class T, class... Args> |
||||
|
typename _Unique_if<T>::_Known_bound |
||||
|
make_unique(Args&&...) = delete; |
||||
|
} |
@ -0,0 +1,60 @@ |
|||||
|
#include "node.h" |
||||
|
|
||||
|
#include "lfmp.h" |
||||
|
|
||||
|
static lfmp_t g_NODE_FMP; |
||||
|
|
||||
|
static |
||||
|
__attribute__((constructor)) |
||||
|
void |
||||
|
node_constructor() |
||||
|
{ |
||||
|
lfmp_init(&g_NODE_FMP,sizeof(node_t),256); |
||||
|
} |
||||
|
|
||||
|
static |
||||
|
__attribute__((destructor)) |
||||
|
void |
||||
|
node_destructor() |
||||
|
{ |
||||
|
lfmp_destroy(&g_NODE_FMP); |
||||
|
} |
||||
|
|
||||
|
node_t * |
||||
|
node_alloc() |
||||
|
{ |
||||
|
return lfmp_calloc(&g_NODE_FMP); |
||||
|
} |
||||
|
|
||||
|
void |
||||
|
node_free(node_t *node_) |
||||
|
{ |
||||
|
lfmp_free(&g_NODE_FMP,node_); |
||||
|
} |
||||
|
|
||||
|
int |
||||
|
node_gc1() |
||||
|
{ |
||||
|
return lfmp_gc(&g_NODE_FMP); |
||||
|
} |
||||
|
|
||||
|
void |
||||
|
node_gc() |
||||
|
{ |
||||
|
int rv; |
||||
|
int fails; |
||||
|
|
||||
|
fails = 0; |
||||
|
do |
||||
|
{ |
||||
|
rv = node_gc1(); |
||||
|
if(rv == 0) |
||||
|
fails++; |
||||
|
} while(rv || (fails < 3)); |
||||
|
} |
||||
|
|
||||
|
lfmp_t* |
||||
|
node_lfmp() |
||||
|
{ |
||||
|
return &g_NODE_FMP; |
||||
|
} |
@ -0,0 +1,30 @@ |
|||||
|
#include "lock.h" |
||||
|
#include "lfmp.h" |
||||
|
|
||||
|
typedef struct node_s node_t; |
||||
|
struct node_s |
||||
|
{ |
||||
|
node_t *name_next; |
||||
|
node_t *id_next; |
||||
|
|
||||
|
uint64_t nodeid; |
||||
|
char *name; |
||||
|
node_t *parent; |
||||
|
|
||||
|
uint64_t nlookup; |
||||
|
uint32_t refctr; |
||||
|
uint32_t open_count; |
||||
|
uint64_t hidden_fh; |
||||
|
|
||||
|
int32_t treelock; |
||||
|
lock_t *locks; |
||||
|
|
||||
|
uint32_t stat_crc32b; |
||||
|
uint8_t is_stat_cache_valid:1; |
||||
|
}; |
||||
|
|
||||
|
node_t *node_alloc(); |
||||
|
void node_free(node_t*); |
||||
|
int node_gc1(); |
||||
|
void node_gc(); |
||||
|
lfmp_t *node_lfmp(); |
@ -0,0 +1,369 @@ |
|||||
|
// _____ _____ _ _____
|
||||
|
// / ____| / ____| | | / ____|_ _
|
||||
|
// | (___ ___ ___ _ __ ___ | | __ _ _ __ _ _ __ __| | | | _| |_ _| |_
|
||||
|
// \___ \ / __/ _ \| '_ \ / _ \ | | |_ | | | |/ _` | '__/ _` | | | |_ _|_ _|
|
||||
|
// ____) | (_| (_) | |_) | __/ | |__| | |_| | (_| | | | (_| | | |____|_| |_|
|
||||
|
// |_____/ \___\___/| .__/ \___| \_____|\__,_|\__,_|_| \__,_| \_____|
|
||||
|
// | | https://github.com/Neargye/scope_guard
|
||||
|
// |_| version 0.9.1
|
||||
|
//
|
||||
|
// Licensed under the MIT License <http://opensource.org/licenses/MIT>.
|
||||
|
// SPDX-License-Identifier: MIT
|
||||
|
// Copyright (c) 2018 - 2021 Daniil Goncharov <neargye@gmail.com>.
|
||||
|
//
|
||||
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
|
// of this software and associated documentation files (the "Software"), to deal
|
||||
|
// in the Software without restriction, including without limitation the rights
|
||||
|
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
|
// copies of the Software, and to permit persons to whom the Software is
|
||||
|
// furnished to do so, subject to the following conditions:
|
||||
|
//
|
||||
|
// The above copyright notice and this permission notice shall be included in all
|
||||
|
// copies or substantial portions of the Software.
|
||||
|
//
|
||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
|
// SOFTWARE.
|
||||
|
|
||||
|
#ifndef NEARGYE_SCOPE_GUARD_HPP
|
||||
|
#define NEARGYE_SCOPE_GUARD_HPP
|
||||
|
|
||||
|
#define SCOPE_GUARD_VERSION_MAJOR 0
|
||||
|
#define SCOPE_GUARD_VERSION_MINOR 9
|
||||
|
#define SCOPE_GUARD_VERSION_PATCH 1
|
||||
|
|
||||
|
#include <type_traits>
|
||||
|
#if (defined(_MSC_VER) && _MSC_VER >= 1900) || ((defined(__clang__) || defined(__GNUC__)) && __cplusplus >= 201700L)
|
||||
|
#include <exception>
|
||||
|
#endif
|
||||
|
|
||||
|
// scope_guard throwable settings:
|
||||
|
// SCOPE_GUARD_NO_THROW_CONSTRUCTIBLE requires nothrow constructible action.
|
||||
|
// SCOPE_GUARD_MAY_THROW_ACTION action may throw exceptions.
|
||||
|
// SCOPE_GUARD_NO_THROW_ACTION requires noexcept action.
|
||||
|
// SCOPE_GUARD_SUPPRESS_THROW_ACTION exceptions during action will be suppressed.
|
||||
|
// SCOPE_GUARD_CATCH_HANDLER exceptions handler. If SCOPE_GUARD_SUPPRESS_THROW_ACTIONS is not defined, it will do nothing.
|
||||
|
|
||||
|
#if !defined(SCOPE_GUARD_MAY_THROW_ACTION) && !defined(SCOPE_GUARD_NO_THROW_ACTION) && !defined(SCOPE_GUARD_SUPPRESS_THROW_ACTION)
|
||||
|
# define SCOPE_GUARD_MAY_THROW_ACTION
|
||||
|
#elif (defined(SCOPE_GUARD_MAY_THROW_ACTION) + defined(SCOPE_GUARD_NO_THROW_ACTION) + defined(SCOPE_GUARD_SUPPRESS_THROW_ACTION)) > 1
|
||||
|
# error Only one of SCOPE_GUARD_MAY_THROW_ACTION and SCOPE_GUARD_NO_THROW_ACTION and SCOPE_GUARD_SUPPRESS_THROW_ACTION may be defined.
|
||||
|
#endif
|
||||
|
|
||||
|
#if !defined(SCOPE_GUARD_CATCH_HANDLER)
|
||||
|
# define SCOPE_GUARD_CATCH_HANDLER /* Suppress exception.*/
|
||||
|
#endif
|
||||
|
|
||||
|
namespace scope_guard { |
||||
|
|
||||
|
namespace detail { |
||||
|
|
||||
|
#if defined(SCOPE_GUARD_SUPPRESS_THROW_ACTION) && (defined(__cpp_exceptions) || defined(__EXCEPTIONS) || (_HAS_EXCEPTIONS))
|
||||
|
# define NEARGYE_NOEXCEPT(...) noexcept
|
||||
|
# define NEARGYE_TRY try {
|
||||
|
# define NEARGYE_CATCH } catch (...) { SCOPE_GUARD_CATCH_HANDLER }
|
||||
|
#else
|
||||
|
# define NEARGYE_NOEXCEPT(...) noexcept(__VA_ARGS__)
|
||||
|
# define NEARGYE_TRY
|
||||
|
# define NEARGYE_CATCH
|
||||
|
#endif
|
||||
|
|
||||
|
#define NEARGYE_MOV(...) static_cast<typename std::remove_reference<decltype(__VA_ARGS__)>::type&&>(__VA_ARGS__)
|
||||
|
#define NEARGYE_FWD(...) static_cast<decltype(__VA_ARGS__)&&>(__VA_ARGS__)
|
||||
|
|
||||
|
// NEARGYE_NODISCARD encourages the compiler to issue a warning if the return value is discarded.
|
||||
|
#if !defined(NEARGYE_NODISCARD)
|
||||
|
# if defined(__clang__)
|
||||
|
# if (__clang_major__ * 10 + __clang_minor__) >= 39 && __cplusplus >= 201703L
|
||||
|
# define NEARGYE_NODISCARD [[nodiscard]]
|
||||
|
# else
|
||||
|
# define NEARGYE_NODISCARD __attribute__((__warn_unused_result__))
|
||||
|
# endif
|
||||
|
# elif defined(__GNUC__)
|
||||
|
# if __GNUC__ >= 7 && __cplusplus >= 201703L
|
||||
|
# define NEARGYE_NODISCARD [[nodiscard]]
|
||||
|
# else
|
||||
|
# define NEARGYE_NODISCARD __attribute__((__warn_unused_result__))
|
||||
|
# endif
|
||||
|
# elif defined(_MSC_VER)
|
||||
|
# if _MSC_VER >= 1911 && defined(_MSVC_LANG) && _MSVC_LANG >= 201703L
|
||||
|
# define NEARGYE_NODISCARD [[nodiscard]]
|
||||
|
# elif defined(_Check_return_)
|
||||
|
# define NEARGYE_NODISCARD _Check_return_
|
||||
|
# else
|
||||
|
# define NEARGYE_NODISCARD
|
||||
|
# endif
|
||||
|
# else
|
||||
|
# define NEARGYE_NODISCARD
|
||||
|
# endif
|
||||
|
#endif
|
||||
|
|
||||
|
#if defined(_MSC_VER) && _MSC_VER < 1900
|
||||
|
inline int uncaught_exceptions() noexcept { |
||||
|
return *(reinterpret_cast<int*>(static_cast<char*>(static_cast<void*>(_getptd())) + (sizeof(void*) == 8 ? 0x100 : 0x90))); |
||||
|
} |
||||
|
#elif (defined(__clang__) || defined(__GNUC__)) && __cplusplus < 201700L
|
||||
|
struct __cxa_eh_globals; |
||||
|
extern "C" __cxa_eh_globals* __cxa_get_globals() noexcept; |
||||
|
inline int uncaught_exceptions() noexcept { |
||||
|
return static_cast<int>(*(reinterpret_cast<unsigned int*>(static_cast<char*>(static_cast<void*>(__cxa_get_globals())) + sizeof(void*)))); |
||||
|
} |
||||
|
#else
|
||||
|
inline int uncaught_exceptions() noexcept { |
||||
|
return std::uncaught_exceptions(); |
||||
|
} |
||||
|
#endif
|
||||
|
|
||||
|
class on_exit_policy { |
||||
|
bool execute_; |
||||
|
|
||||
|
public: |
||||
|
explicit on_exit_policy(bool execute) noexcept : execute_{execute} {} |
||||
|
|
||||
|
void dismiss() noexcept { |
||||
|
execute_ = false; |
||||
|
} |
||||
|
|
||||
|
bool should_execute() const noexcept { |
||||
|
return execute_; |
||||
|
} |
||||
|
}; |
||||
|
|
||||
|
class on_fail_policy { |
||||
|
int ec_; |
||||
|
|
||||
|
public: |
||||
|
explicit on_fail_policy(bool execute) noexcept : ec_{execute ? uncaught_exceptions() : -1} {} |
||||
|
|
||||
|
void dismiss() noexcept { |
||||
|
ec_ = -1; |
||||
|
} |
||||
|
|
||||
|
bool should_execute() const noexcept { |
||||
|
return ec_ != -1 && ec_ < uncaught_exceptions(); |
||||
|
} |
||||
|
}; |
||||
|
|
||||
|
class on_success_policy { |
||||
|
int ec_; |
||||
|
|
||||
|
public: |
||||
|
explicit on_success_policy(bool execute) noexcept : ec_{execute ? uncaught_exceptions() : -1} {} |
||||
|
|
||||
|
void dismiss() noexcept { |
||||
|
ec_ = -1; |
||||
|
} |
||||
|
|
||||
|
bool should_execute() const noexcept { |
||||
|
return ec_ != -1 && ec_ >= uncaught_exceptions(); |
||||
|
} |
||||
|
}; |
||||
|
|
||||
|
template <typename T, typename = void> |
||||
|
struct is_noarg_returns_void_action |
||||
|
: std::false_type {}; |
||||
|
|
||||
|
template <typename T> |
||||
|
struct is_noarg_returns_void_action<T, decltype((std::declval<T>())())> |
||||
|
: std::true_type {}; |
||||
|
|
||||
|
template <typename T, bool = is_noarg_returns_void_action<T>::value> |
||||
|
struct is_nothrow_invocable_action |
||||
|
: std::false_type {}; |
||||
|
|
||||
|
template <typename T> |
||||
|
struct is_nothrow_invocable_action<T, true> |
||||
|
: std::integral_constant<bool, noexcept((std::declval<T>())())> {}; |
||||
|
|
||||
|
template <typename F, typename P> |
||||
|
class scope_guard { |
||||
|
using A = typename std::decay<F>::type; |
||||
|
|
||||
|
static_assert(is_noarg_returns_void_action<A>::value, |
||||
|
"scope_guard requires no-argument action, that returns void."); |
||||
|
static_assert(std::is_same<P, on_exit_policy>::value || std::is_same<P, on_fail_policy>::value || std::is_same<P, on_success_policy>::value, |
||||
|
"scope_guard requires on_exit_policy, on_fail_policy or on_success_policy."); |
||||
|
#if defined(SCOPE_GUARD_NO_THROW_ACTION)
|
||||
|
static_assert(is_nothrow_invocable_action<A>::value, |
||||
|
"scope_guard requires noexcept invocable action."); |
||||
|
#endif
|
||||
|
#if defined(SCOPE_GUARD_NO_THROW_CONSTRUCTIBLE)
|
||||
|
static_assert(std::is_nothrow_move_constructible<A>::value, |
||||
|
"scope_guard requires nothrow constructible action."); |
||||
|
#endif
|
||||
|
|
||||
|
P policy_; |
||||
|
A action_; |
||||
|
|
||||
|
void* operator new(std::size_t) = delete; |
||||
|
void operator delete(void*) = delete; |
||||
|
|
||||
|
public: |
||||
|
scope_guard() = delete; |
||||
|
scope_guard(const scope_guard&) = delete; |
||||
|
scope_guard& operator=(const scope_guard&) = delete; |
||||
|
scope_guard& operator=(scope_guard&&) = delete; |
||||
|
|
||||
|
scope_guard(scope_guard&& other) noexcept(std::is_nothrow_move_constructible<A>::value) |
||||
|
: policy_{false}, |
||||
|
action_{NEARGYE_MOV(other.action_)} { |
||||
|
policy_ = NEARGYE_MOV(other.policy_); |
||||
|
other.policy_.dismiss(); |
||||
|
} |
||||
|
|
||||
|
scope_guard(const A& action) = delete; |
||||
|
scope_guard(A& action) = delete; |
||||
|
|
||||
|
explicit scope_guard(A&& action) noexcept(std::is_nothrow_move_constructible<A>::value) |
||||
|
: policy_{true}, |
||||
|
action_{NEARGYE_MOV(action)} {} |
||||
|
|
||||
|
void dismiss() noexcept { |
||||
|
policy_.dismiss(); |
||||
|
} |
||||
|
|
||||
|
~scope_guard() NEARGYE_NOEXCEPT(is_nothrow_invocable_action<A>::value) { |
||||
|
if (policy_.should_execute()) { |
||||
|
NEARGYE_TRY |
||||
|
action_(); |
||||
|
NEARGYE_CATCH |
||||
|
} |
||||
|
} |
||||
|
}; |
||||
|
|
||||
|
template <typename F> |
||||
|
using scope_exit = scope_guard<F, on_exit_policy>; |
||||
|
|
||||
|
template <typename F, typename std::enable_if<is_noarg_returns_void_action<F>::value, int>::type = 0> |
||||
|
NEARGYE_NODISCARD scope_exit<F> make_scope_exit(F&& action) noexcept(noexcept(scope_exit<F>{NEARGYE_FWD(action)})) { |
||||
|
return scope_exit<F>{NEARGYE_FWD(action)}; |
||||
|
} |
||||
|
|
||||
|
template <typename F> |
||||
|
using scope_fail = scope_guard<F, on_fail_policy>; |
||||
|
|
||||
|
template <typename F, typename std::enable_if<is_noarg_returns_void_action<F>::value, int>::type = 0> |
||||
|
NEARGYE_NODISCARD scope_fail<F> make_scope_fail(F&& action) noexcept(noexcept(scope_fail<F>{NEARGYE_FWD(action)})) { |
||||
|
return scope_fail<F>{NEARGYE_FWD(action)}; |
||||
|
} |
||||
|
|
||||
|
template <typename F> |
||||
|
using scope_success = scope_guard<F, on_success_policy>; |
||||
|
|
||||
|
template <typename F, typename std::enable_if<is_noarg_returns_void_action<F>::value, int>::type = 0> |
||||
|
NEARGYE_NODISCARD scope_success<F> make_scope_success(F&& action) noexcept(noexcept(scope_success<F>{NEARGYE_FWD(action)})) { |
||||
|
return scope_success<F>{NEARGYE_FWD(action)}; |
||||
|
} |
||||
|
|
||||
|
struct scope_exit_tag {}; |
||||
|
|
||||
|
template <typename F, typename std::enable_if<is_noarg_returns_void_action<F>::value, int>::type = 0> |
||||
|
scope_exit<F> operator<<(scope_exit_tag, F&& action) noexcept(noexcept(scope_exit<F>{NEARGYE_FWD(action)})) { |
||||
|
return scope_exit<F>{NEARGYE_FWD(action)}; |
||||
|
} |
||||
|
|
||||
|
struct scope_fail_tag {}; |
||||
|
|
||||
|
template <typename F, typename std::enable_if<is_noarg_returns_void_action<F>::value, int>::type = 0> |
||||
|
scope_fail<F> operator<<(scope_fail_tag, F&& action) noexcept(noexcept(scope_fail<F>{NEARGYE_FWD(action)})) { |
||||
|
return scope_fail<F>{NEARGYE_FWD(action)}; |
||||
|
} |
||||
|
|
||||
|
struct scope_success_tag {}; |
||||
|
|
||||
|
template <typename F, typename std::enable_if<is_noarg_returns_void_action<F>::value, int>::type = 0> |
||||
|
scope_success<F> operator<<(scope_success_tag, F&& action) noexcept(noexcept(scope_success<F>{NEARGYE_FWD(action)})) { |
||||
|
return scope_success<F>{NEARGYE_FWD(action)}; |
||||
|
} |
||||
|
|
||||
|
#undef NEARGYE_MOV
|
||||
|
#undef NEARGYE_FWD
|
||||
|
#undef NEARGYE_NOEXCEPT
|
||||
|
#undef NEARGYE_TRY
|
||||
|
#undef NEARGYE_CATCH
|
||||
|
#undef NEARGYE_NODISCARD
|
||||
|
|
||||
|
} // namespace scope_guard::detail
|
||||
|
|
||||
|
using detail::make_scope_exit; |
||||
|
using detail::make_scope_fail; |
||||
|
using detail::make_scope_success; |
||||
|
|
||||
|
} // namespace scope_guard
|
||||
|
|
||||
|
// NEARGYE_MAYBE_UNUSED suppresses compiler warnings on unused entities, if any.
|
||||
|
#if !defined(NEARGYE_MAYBE_UNUSED)
|
||||
|
# if defined(__clang__)
|
||||
|
# if (__clang_major__ * 10 + __clang_minor__) >= 39 && __cplusplus >= 201703L
|
||||
|
# define NEARGYE_MAYBE_UNUSED [[maybe_unused]]
|
||||
|
# else
|
||||
|
# define NEARGYE_MAYBE_UNUSED __attribute__((__unused__))
|
||||
|
# endif
|
||||
|
# elif defined(__GNUC__)
|
||||
|
# if __GNUC__ >= 7 && __cplusplus >= 201703L
|
||||
|
# define NEARGYE_MAYBE_UNUSED [[maybe_unused]]
|
||||
|
# else
|
||||
|
# define NEARGYE_MAYBE_UNUSED __attribute__((__unused__))
|
||||
|
# endif
|
||||
|
# elif defined(_MSC_VER)
|
||||
|
# if _MSC_VER >= 1911 && defined(_MSVC_LANG) && _MSVC_LANG >= 201703L
|
||||
|
# define NEARGYE_MAYBE_UNUSED [[maybe_unused]]
|
||||
|
# else
|
||||
|
# define NEARGYE_MAYBE_UNUSED __pragma(warning(suppress : 4100 4101 4189))
|
||||
|
# endif
|
||||
|
# else
|
||||
|
# define NEARGYE_MAYBE_UNUSED
|
||||
|
# endif
|
||||
|
#endif
|
||||
|
|
||||
|
#if !defined(NEARGYE_STR_CONCAT)
|
||||
|
# define NEARGYE_STR_CONCAT_(s1, s2) s1##s2
|
||||
|
# define NEARGYE_STR_CONCAT(s1, s2) NEARGYE_STR_CONCAT_(s1, s2)
|
||||
|
#endif
|
||||
|
|
||||
|
#if !defined(NEARGYE_COUNTER)
|
||||
|
# if defined(__COUNTER__)
|
||||
|
# define NEARGYE_COUNTER __COUNTER__
|
||||
|
# elif defined(__LINE__)
|
||||
|
# define NEARGYE_COUNTER __LINE__
|
||||
|
# endif
|
||||
|
#endif
|
||||
|
|
||||
|
#if defined(SCOPE_GUARD_NO_THROW_ACTION)
|
||||
|
# define NEARGYE_MAKE_SCOPE_GUARD_ACTION [&]() noexcept -> void
|
||||
|
#else
|
||||
|
# define NEARGYE_MAKE_SCOPE_GUARD_ACTION [&]() -> void
|
||||
|
#endif
|
||||
|
|
||||
|
#define NEARGYE_MAKE_SCOPE_EXIT ::scope_guard::detail::scope_exit_tag{} << NEARGYE_MAKE_SCOPE_GUARD_ACTION
|
||||
|
#define NEARGYE_MAKE_SCOPE_FAIL ::scope_guard::detail::scope_fail_tag{} << NEARGYE_MAKE_SCOPE_GUARD_ACTION
|
||||
|
#define NEARGYE_MAKE_SCOPE_SUCCESS ::scope_guard::detail::scope_success_tag{} << NEARGYE_MAKE_SCOPE_GUARD_ACTION
|
||||
|
|
||||
|
#define NEARGYE_SCOPE_GUARD_WITH_(g, i) for (int i = 1; i--; g)
|
||||
|
#define NEARGYE_SCOPE_GUARD_WITH(g) NEARGYE_SCOPE_GUARD_WITH_(g, NEARGYE_STR_CONCAT(NEARGYE_INTERNAL_OBJECT_, NEARGYE_COUNTER))
|
||||
|
|
||||
|
// SCOPE_EXIT executing action on scope exit.
|
||||
|
#define MAKE_SCOPE_EXIT(name) auto name = NEARGYE_MAKE_SCOPE_EXIT
|
||||
|
#define SCOPE_EXIT NEARGYE_MAYBE_UNUSED const MAKE_SCOPE_EXIT(NEARGYE_STR_CONCAT(NEARGYE_SCOPE_EXIT_, NEARGYE_COUNTER))
|
||||
|
#define WITH_SCOPE_EXIT(guard) NEARGYE_SCOPE_GUARD_WITH(NEARGYE_MAKE_SCOPE_EXIT{ guard })
|
||||
|
|
||||
|
// SCOPE_FAIL executing action on scope exit when an exception has been thrown before scope exit.
|
||||
|
#define MAKE_SCOPE_FAIL(name) auto name = NEARGYE_MAKE_SCOPE_FAIL
|
||||
|
#define SCOPE_FAIL NEARGYE_MAYBE_UNUSED const MAKE_SCOPE_FAIL(NEARGYE_STR_CONCAT(NEARGYE_SCOPE_FAIL_, NEARGYE_COUNTER))
|
||||
|
#define WITH_SCOPE_FAIL(guard) NEARGYE_SCOPE_GUARD_WITH(NEARGYE_MAKE_SCOPE_FAIL{ guard })
|
||||
|
|
||||
|
// SCOPE_SUCCESS executing action on scope exit when no exceptions have been thrown before scope exit.
|
||||
|
#define MAKE_SCOPE_SUCCESS(name) auto name = NEARGYE_MAKE_SCOPE_SUCCESS
|
||||
|
#define SCOPE_SUCCESS NEARGYE_MAYBE_UNUSED const MAKE_SCOPE_SUCCESS(NEARGYE_STR_CONCAT(NEARGYE_SCOPE_SUCCESS_, NEARGYE_COUNTER))
|
||||
|
#define WITH_SCOPE_SUCCESS(guard) NEARGYE_SCOPE_GUARD_WITH(NEARGYE_MAKE_SCOPE_SUCCESS{ guard })
|
||||
|
|
||||
|
// DEFER executing action on scope exit.
|
||||
|
#define MAKE_DEFER(name) MAKE_SCOPE_EXIT(name)
|
||||
|
#define DEFER SCOPE_EXIT
|
||||
|
#define WITH_DEFER(guard) WITH_SCOPE_EXIT(guard)
|
||||
|
|
||||
|
#endif // NEARGYE_SCOPE_GUARD_HPP
|
@ -0,0 +1,110 @@ |
|||||
|
/* |
||||
|
ISC License |
||||
|
|
||||
|
Copyright (c) 2023, Antonio SJ Musumeci <trapexit@spawn.link> |
||||
|
|
||||
|
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. |
||||
|
*/ |
||||
|
|
||||
|
#include <stdarg.h> |
||||
|
#include <syslog.h> |
||||
|
#include <stdbool.h> |
||||
|
|
||||
|
|
||||
|
static bool g_SYSLOG_ENABLED = false; |
||||
|
|
||||
|
void |
||||
|
syslog_open() |
||||
|
{ |
||||
|
const char *ident = "mergerfs"; |
||||
|
const int option = (LOG_CONS|LOG_PID); |
||||
|
const int facility = LOG_USER; |
||||
|
|
||||
|
openlog(ident,option,facility); |
||||
|
g_SYSLOG_ENABLED = true; |
||||
|
} |
||||
|
|
||||
|
void |
||||
|
syslog_close() |
||||
|
{ |
||||
|
closelog(); |
||||
|
g_SYSLOG_ENABLED = false; |
||||
|
} |
||||
|
|
||||
|
static |
||||
|
void |
||||
|
syslog_vlog(const int priority_, |
||||
|
const char *format_, |
||||
|
va_list valist_) |
||||
|
{ |
||||
|
if(g_SYSLOG_ENABLED == false) |
||||
|
return; |
||||
|
|
||||
|
vsyslog(priority_,format_,valist_); |
||||
|
} |
||||
|
|
||||
|
void |
||||
|
syslog_log(const int priority_, |
||||
|
const char *format_, |
||||
|
...) |
||||
|
{ |
||||
|
va_list valist; |
||||
|
|
||||
|
va_start(valist,format_); |
||||
|
syslog_vlog(priority_,format_,valist); |
||||
|
va_end(valist); |
||||
|
} |
||||
|
|
||||
|
void |
||||
|
syslog_info(const char *format_, |
||||
|
...) |
||||
|
{ |
||||
|
va_list valist; |
||||
|
|
||||
|
va_start(valist,format_); |
||||
|
syslog_vlog(LOG_INFO,format_,valist); |
||||
|
va_end(valist); |
||||
|
} |
||||
|
|
||||
|
void |
||||
|
syslog_notice(const char *format_, |
||||
|
...) |
||||
|
{ |
||||
|
va_list valist; |
||||
|
|
||||
|
va_start(valist,format_); |
||||
|
syslog_vlog(LOG_NOTICE,format_,valist); |
||||
|
va_end(valist); |
||||
|
} |
||||
|
|
||||
|
void |
||||
|
syslog_warning(const char *format_, |
||||
|
...) |
||||
|
{ |
||||
|
va_list valist; |
||||
|
|
||||
|
va_start(valist,format_); |
||||
|
syslog_vlog(LOG_WARNING,format_,valist); |
||||
|
va_end(valist); |
||||
|
} |
||||
|
|
||||
|
void |
||||
|
syslog_error(const char *format_, |
||||
|
...) |
||||
|
{ |
||||
|
va_list valist; |
||||
|
|
||||
|
va_start(valist,format_); |
||||
|
syslog_vlog(LOG_ERR,format_,valist); |
||||
|
va_end(valist); |
||||
|
} |
@ -0,0 +1,30 @@ |
|||||
|
/* |
||||
|
ISC License |
||||
|
|
||||
|
Copyright (c) 2023, Antonio SJ Musumeci <trapexit@spawn.link> |
||||
|
|
||||
|
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. |
||||
|
*/ |
||||
|
|
||||
|
#pragma once |
||||
|
|
||||
|
#include <syslog.h> |
||||
|
|
||||
|
|
||||
|
void syslog_open(); |
||||
|
void syslog_log(const int priority, const char *format, ...); |
||||
|
void syslog_info(const char *format, ...); |
||||
|
void syslog_notice(const char *format, ...); |
||||
|
void syslog_warning(const char *format, ...); |
||||
|
void syslog_error(const char *format, ...); |
||||
|
void syslog_close(); |
Write
Preview
Loading…
Cancel
Save
Reference in new issue