diff --git a/src/fs_statvfs_cache.cpp b/src/fs_statvfs_cache.cpp index 1d2fa708..6328e528 100644 --- a/src/fs_statvfs_cache.cpp +++ b/src/fs_statvfs_cache.cpp @@ -80,7 +80,7 @@ fs::statvfs_cache(const std::string &path_, rv = 0; now = ::_get_time(); - mutex_lock(g_cache_lock); + mutex_lockguard(g_cache_lock); e = &g_cache[path_]; @@ -92,8 +92,6 @@ fs::statvfs_cache(const std::string &path_, *st_ = e->st; - mutex_unlock(g_cache_lock); - return rv; } diff --git a/src/fuse_readdir_cor_getdents.icpp b/src/fuse_readdir_cor_getdents.icpp index 3df46a5b..4ebac133 100644 --- a/src/fuse_readdir_cor_getdents.icpp +++ b/src/fuse_readdir_cor_getdents.icpp @@ -67,7 +67,7 @@ _readdir(const fs::path &branch_path_, if(nread <= 0) return nread; - LockGuard lk(mutex_); + mutex_lockguard(mutex_); for(ssize_t pos = 0; pos < nread;) { int rv; diff --git a/src/fuse_readdir_cor_readdir.icpp b/src/fuse_readdir_cor_readdir.icpp index 3c944917..d0a72a32 100644 --- a/src/fuse_readdir_cor_readdir.icpp +++ b/src/fuse_readdir_cor_readdir.icpp @@ -70,7 +70,7 @@ _readdir(const fs::path &branch_path_, fs::inode::ReaddirCalc inodecalc(branch_path_,rel_dirpath_); while(true) { - LockGuard lk(mutex_); + mutex_lockguard(mutex_); for(int i = 0; i < MAX_ENTRIES_PER_LOOP; i++) { int rv; diff --git a/vendored/libfuse/include/mutex.hpp b/vendored/libfuse/include/mutex.hpp index 0f2cf302..a8a26c4d 100644 --- a/vendored/libfuse/include/mutex.hpp +++ b/vendored/libfuse/include/mutex.hpp @@ -6,8 +6,6 @@ #include "mutex_ndebug.hpp" #endif -#include "scope_guard/scope_guard.hpp" - typedef pthread_mutex_t mutex_t; // Simple mutex_t wrapper to provide RAII @@ -29,33 +27,29 @@ public: mutex_destroy(_mutex); } + Mutex(const Mutex&) = delete; + Mutex& operator=(const Mutex&) = delete; + Mutex(Mutex&&) = delete; + Mutex& operator=(Mutex&&) = delete; + operator mutex_t&() { return _mutex; } }; -class LockGuard -{ -private: - mutex_t &_mutex; +// RAII mutex guard macro. Expands to a single variable declaration, +// so it is safe in unbraced if/else/for/while. +// In debug builds the call-site __FILE__/__func__/__LINE__ are +// forwarded to _mutex_lock/_mutex_unlock for diagnostics. +#define MUTEX_LOCKGUARD_CONCAT_(a,b) a##b +#define MUTEX_LOCKGUARD_CONCAT(a,b) MUTEX_LOCKGUARD_CONCAT_(a,b) -public: - LockGuard(mutex_t &mutex_) - : _mutex(mutex_) - { - mutex_lock(_mutex); - } - - ~LockGuard() - { - mutex_unlock(_mutex); - } -}; - -// Single-line mutex guard using scope_guard -// Expands to mutex_lock() followed by DEFER mutex_unlock() -// Both lock and unlock capture __FILE__/__func__/__LINE__ from the call site +#ifdef DEBUG #define mutex_lockguard(m) \ - mutex_lock(m); \ - DEFER { mutex_unlock(m); } + ScopedMutexLock MUTEX_LOCKGUARD_CONCAT(_mtx_guard_,__COUNTER__) \ + ((m),__FILE__,__func__,__LINE__) +#else +#define mutex_lockguard(m) \ + ScopedMutexLock MUTEX_LOCKGUARD_CONCAT(_mtx_guard_,__COUNTER__)(m) +#endif diff --git a/vendored/libfuse/include/mutex_debug.hpp b/vendored/libfuse/include/mutex_debug.hpp index 02f4809a..c45d1b02 100644 --- a/vendored/libfuse/include/mutex_debug.hpp +++ b/vendored/libfuse/include/mutex_debug.hpp @@ -2,8 +2,16 @@ #include "fmt/core.h" -#include +#include #include +#include +#include + +#if defined(__has_include) +# if __has_include() +# include +# endif +#endif #include @@ -11,6 +19,12 @@ # define PTHREAD_MUTEX_ADAPTIVE_NP PTHREAD_MUTEX_NORMAL #endif +#if defined(_GNU_SOURCE) && defined(__GLIBC_PREREQ) +# if __GLIBC_PREREQ(2,30) +# define MUTEX_HAS_PTHREAD_MUTEX_CLOCKLOCK 1 +# endif +#endif + #define mutex_init(M) _mutex_init((M),__FILE__,__func__,__LINE__) #define mutex_destroy(M) _mutex_destroy((M),__FILE__,__func__,__LINE__) #define mutex_lock(M) _mutex_lock((M),__FILE__,__func__,__LINE__) @@ -48,14 +62,27 @@ _mutex_init(pthread_mutex_t &mutex_, int rv; pthread_mutexattr_t attr; - pthread_mutexattr_init(&attr); - pthread_mutexattr_settype(&attr,PTHREAD_MUTEX_ADAPTIVE_NP); + rv = pthread_mutexattr_init(&attr); + if(rv != 0) + _print_error_and_abort("pthread_mutexattr_init",rv,file_,func_,linenum_); + + rv = pthread_mutexattr_settype(&attr,PTHREAD_MUTEX_ADAPTIVE_NP); + if(rv != 0) + { + pthread_mutexattr_destroy(&attr); + _print_error_and_abort("pthread_mutexattr_settype",rv,file_,func_,linenum_); + } rv = pthread_mutex_init(&mutex_,&attr); if(rv != 0) - _print_error_and_abort(__func__,rv,file_,func_,linenum_); + { + pthread_mutexattr_destroy(&attr); + _print_error_and_abort("pthread_mutex_init",rv,file_,func_,linenum_); + } - pthread_mutexattr_destroy(&attr); + rv = pthread_mutexattr_destroy(&attr); + if(rv != 0) + _print_error_and_abort("pthread_mutexattr_destroy",rv,file_,func_,linenum_); } static @@ -87,7 +114,14 @@ _mutex_lock(pthread_mutex_t &mutex_, while(true) { - clock_gettime(CLOCK_REALTIME,&timeout); +#ifdef MUTEX_HAS_PTHREAD_MUTEX_CLOCKLOCK + rv = clock_gettime(CLOCK_MONOTONIC,&timeout); +#else + rv = clock_gettime(CLOCK_REALTIME,&timeout); +#endif + if(rv != 0) + _print_error_and_abort("clock_gettime",errno,file_,func_,linenum_); + timeout.tv_nsec += 1000000 * 1; // 1ms if(timeout.tv_nsec >= 1000000000) { @@ -95,7 +129,11 @@ _mutex_lock(pthread_mutex_t &mutex_, timeout.tv_nsec -= 1000000000; } +#ifdef MUTEX_HAS_PTHREAD_MUTEX_CLOCKLOCK + rv = pthread_mutex_clocklock(&mutex_,CLOCK_MONOTONIC,&timeout); +#else rv = pthread_mutex_timedlock(&mutex_,&timeout); +#endif switch(rv) { case 0: @@ -103,7 +141,7 @@ _mutex_lock(pthread_mutex_t &mutex_, case ETIMEDOUT: cnt++; fmt::println(stderr, - "NOTICE: pthread_mutex_timedlock expired - count={}; ({}:{}:{})", + "NOTICE: mutex timed lock expired - count={}; ({}:{}:{})", cnt, file_, func_, @@ -130,3 +168,31 @@ _mutex_unlock(pthread_mutex_t &mutex_, if(rv != 0) _print_error_and_abort(__func__,rv,file_,func_,linenum_); } + +class ScopedMutexLock +{ +private: + pthread_mutex_t &_mutex; + const char *_file; + const char *_func; + int _line; + +public: + explicit + ScopedMutexLock(pthread_mutex_t &mutex_, + const char *file_, + const char *func_, + int line_) + : _mutex(mutex_), _file(file_), _func(func_), _line(line_) + { + _mutex_lock(_mutex,_file,_func,_line); + } + + ~ScopedMutexLock() noexcept + { + _mutex_unlock(_mutex,_file,_func,_line); + } + + ScopedMutexLock(const ScopedMutexLock&) = delete; + ScopedMutexLock& operator=(const ScopedMutexLock&) = delete; +}; diff --git a/vendored/libfuse/include/mutex_ndebug.hpp b/vendored/libfuse/include/mutex_ndebug.hpp index f8beb571..3a07750c 100644 --- a/vendored/libfuse/include/mutex_ndebug.hpp +++ b/vendored/libfuse/include/mutex_ndebug.hpp @@ -1,5 +1,6 @@ #pragma once +#include #include #include @@ -17,14 +18,27 @@ mutex_init(pthread_mutex_t &mutex_) int rv; pthread_mutexattr_t attr; - pthread_mutexattr_init(&attr); - pthread_mutexattr_settype(&attr,PTHREAD_MUTEX_ADAPTIVE_NP); - - rv = pthread_mutex_init(&mutex_,&attr); + rv = pthread_mutexattr_init(&attr); if(rv != 0) std::abort(); - pthread_mutexattr_destroy(&attr); + rv = pthread_mutexattr_settype(&attr,PTHREAD_MUTEX_ADAPTIVE_NP); + if(rv != 0) + { + pthread_mutexattr_destroy(&attr); + std::abort(); + } + + rv = pthread_mutex_init(&mutex_,&attr); + if(rv != 0) + { + pthread_mutexattr_destroy(&attr); + std::abort(); + } + + rv = pthread_mutexattr_destroy(&attr); + if(rv != 0) + std::abort(); } static @@ -62,3 +76,25 @@ mutex_destroy(pthread_mutex_t &mutex_) if(rv != 0) std::abort(); } + +class ScopedMutexLock +{ +private: + pthread_mutex_t &_mutex; + +public: + explicit + ScopedMutexLock(pthread_mutex_t &mutex_) + : _mutex(mutex_) + { + mutex_lock(_mutex); + } + + ~ScopedMutexLock() noexcept + { + mutex_unlock(_mutex); + } + + ScopedMutexLock(const ScopedMutexLock&) = delete; + ScopedMutexLock& operator=(const ScopedMutexLock&) = delete; +}; diff --git a/vendored/libfuse/include/objpool.hpp b/vendored/libfuse/include/objpool.hpp index 6e4facdb..2b2f444a 100644 --- a/vendored/libfuse/include/objpool.hpp +++ b/vendored/libfuse/include/objpool.hpp @@ -81,7 +81,7 @@ private: } private: - mutex_t _mtx; + Mutex _mtx; Node *_head = nullptr; std::atomic _pool_count{0}; Allocator _allocator; @@ -124,7 +124,7 @@ private: Node* _pop_node(const size_t required_size_) { - mutex_lock(_mtx); + mutex_lockguard(_mtx); Node **prev = &_head; while(*prev) @@ -134,15 +134,12 @@ private: { *prev = node->next; _pool_count.fetch_sub(1,std::memory_order_relaxed); - mutex_unlock(_mtx); return node; } prev = &node->next; } - mutex_unlock(_mtx); - return nullptr;; } @@ -152,13 +149,11 @@ private: { node_->alloc_size = alloc_size_; - mutex_lock(_mtx); + mutex_lockguard(_mtx); node_->next = _head; _head = node_; _pool_count.fetch_add(1,std::memory_order_relaxed); - - mutex_unlock(_mtx); } public: @@ -167,13 +162,13 @@ public: { Node *head; - mutex_lock(_mtx); + { + mutex_lockguard(_mtx); - head = _head; - _head = nullptr; - _pool_count.store(0,std::memory_order_relaxed); - - mutex_unlock(_mtx); + head = _head; + _head = nullptr; + _pool_count.store(0,std::memory_order_relaxed); + } while(head) { diff --git a/vendored/libfuse/lib/fuse_loop.cpp b/vendored/libfuse/lib/fuse_loop.cpp index 408853b9..c6e4dfe9 100644 --- a/vendored/libfuse/lib/fuse_loop.cpp +++ b/vendored/libfuse/lib/fuse_loop.cpp @@ -326,8 +326,8 @@ fuse_loop_mt(struct fuse *f_) if(f_ == NULL) return -1; - MaintenanceThread::setup(); fuse_populate_maintenance_thread(f_); + MaintenanceThread::setup(); res = fuse_session_loop_mt(fuse_get_session(), fuse_cfg.read_thread_count, diff --git a/vendored/libfuse/lib/fuse_lowlevel.cpp b/vendored/libfuse/lib/fuse_lowlevel.cpp index 9c06a940..dc067a09 100644 --- a/vendored/libfuse/lib/fuse_lowlevel.cpp +++ b/vendored/libfuse/lib/fuse_lowlevel.cpp @@ -1326,17 +1326,18 @@ do_notify_reply(fuse_req_t *req, struct fuse_notify_req *nreq; struct fuse_notify_req *head; - mutex_lock(f.lock); - head = &f.notify_list; - for(nreq = head->next; nreq != head; nreq = nreq->next) - { - if(nreq->unique == req->ctx.unique) - { - list_del_nreq(nreq); - break; - } - } - mutex_unlock(f.lock); + { + mutex_lockguard(f.lock); + head = &f.notify_list; + for(nreq = head->next; nreq != head; nreq = nreq->next) + { + if(nreq->unique == req->ctx.unique) + { + list_del_nreq(nreq); + break; + } + } + } if(nreq != head) nreq->reply(nreq, req, hdr_->nodeid, &hdr_[1]); @@ -1574,12 +1575,13 @@ fuse_lowlevel_notify_retrieve(struct fuse_session *se, if(rreq == NULL) return -ENOMEM; - mutex_lock(f.lock); - rreq->cookie = cookie; - rreq->nreq.unique = f.notify_ctr++; - rreq->nreq.reply = fuse_ll_retrieve_reply; - list_add_nreq(&rreq->nreq, &f.notify_list); - mutex_unlock(f.lock); + { + mutex_lockguard(f.lock); + rreq->cookie = cookie; + rreq->nreq.unique = f.notify_ctr++; + rreq->nreq.reply = fuse_ll_retrieve_reply; + list_add_nreq(&rreq->nreq, &f.notify_list); + } outarg.notify_unique = rreq->nreq.unique; outarg.nodeid = ino; @@ -1592,9 +1594,10 @@ fuse_lowlevel_notify_retrieve(struct fuse_session *se, err = send_notify_iov(se, FUSE_NOTIFY_RETRIEVE, iov, 2); if(err) { - mutex_lock(f.lock); - list_del_nreq(&rreq->nreq); - mutex_unlock(f.lock); + { + mutex_lockguard(f.lock); + list_del_nreq(&rreq->nreq); + } free(rreq); } diff --git a/vendored/libfuse/lib/fuse_session.cpp b/vendored/libfuse/lib/fuse_session.cpp index de356330..9486a625 100644 --- a/vendored/libfuse/lib/fuse_session.cpp +++ b/vendored/libfuse/lib/fuse_session.cpp @@ -14,6 +14,8 @@ #include #include #include +#include + #include #include diff --git a/vendored/libfuse/lib/maintenance_thread.cpp b/vendored/libfuse/lib/maintenance_thread.cpp index a2be0f49..75a039d1 100644 --- a/vendored/libfuse/lib/maintenance_thread.cpp +++ b/vendored/libfuse/lib/maintenance_thread.cpp @@ -10,7 +10,7 @@ static pthread_t g_thread; static std::vector> g_funcs; -static mutex_t g_mutex; +static Mutex g_mutex; static void* @@ -25,8 +25,14 @@ _thread_loop(void *) { pthread_setcancelstate(PTHREAD_CANCEL_DISABLE,NULL); { - LockGuard lg(g_mutex); - for(auto &func : g_funcs) + std::vector> funcs; + + { + mutex_lockguard(g_mutex); + funcs = g_funcs; + } + + for(auto &func : funcs) func(count); } pthread_setcancelstate(PTHREAD_CANCEL_ENABLE,NULL); @@ -51,7 +57,7 @@ MaintenanceThread::setup() void MaintenanceThread::push_job(const std::function &func_) { - LockGuard lg(g_mutex); + mutex_lockguard(g_mutex); g_funcs.emplace_back(func_); } @@ -61,4 +67,9 @@ MaintenanceThread::stop() { pthread_cancel(g_thread); pthread_join(g_thread,NULL); + + { + mutex_lockguard(g_mutex); + g_funcs.clear(); + } }