From 27b0850af47a6c257cf19f025c1b7c44aa07591c Mon Sep 17 00:00:00 2001 From: Patrick Pelissier Date: Tue, 12 Nov 2024 22:26:45 +0100 Subject: [PATCH] Fix case of the same variable is passed as 2/3 arguments of a function. --- m-shared-ptr.h | 49 +++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 47 insertions(+), 2 deletions(-) diff --git a/m-shared-ptr.h b/m-shared-ptr.h index 78379c18..799dfa37 100644 --- a/m-shared-ptr.h +++ b/m-shared-ptr.h @@ -508,6 +508,8 @@ static inline type const *M_F(name, _cref)(const shared_t *out) \ \ static inline void M_F(name, _write_read_lock)(shared_t *out, const shared_t *src) \ { \ + /* We cannot perform a write_lock and a read_lock on the same variable at the same time */ \ + M_ASSERT(out != src); \ /* Need to order the locks in a total way to avoid lock deadlock. \ Indeed, two call to _set can be done in two threads with : \ T1: A := B \ @@ -530,13 +532,39 @@ static inline void M_F(name, _write_read_lock)(shared_t *out, const shared_t *sr \ static inline void M_F(name, _write_read_unlock)(shared_t *out, const shared_t *src) \ { \ + M_ASSERT(out != src); \ /* NOTE: No need to order the unlock */ \ M_F(name, _read_unlock)(src); \ M_F(name, _write_unlock)(out); \ } \ \ -static inline void M_F(name, _write_read2_lock)(shared_t *out, const shared_t *src1, const shared_t *src2) \ +fattr void M_F(name, _write_read2_lock)(shared_t *out, const shared_t *src1, const shared_t *src2); \ +fattr void M_F(name, _write_read2_lock)(shared_t *out, const shared_t *src1, const shared_t *src2) \ { \ + /* We can have out == src1 or out == src2 or src1 == src2 */ \ + /* if src1 == src2, nothing special to do (read_lock are compatible each other )*/ \ + if (out == src1) { \ + if (out == src2) { \ + M_F(name, _write_lock)(out); \ + } else if (out < src2) { \ + M_F(name, _write_lock)(out); \ + M_F(name, _read_lock)(src2); \ + } else { \ + M_F(name, _read_lock)(src2); \ + M_F(name, _write_lock)(out); \ + } \ + return; \ + } else if (out == src2) { \ + M_ASSERT(out != src1); \ + if (out < src1) { \ + M_F(name, _write_lock)(out); \ + M_F(name, _read_lock)(src1); \ + } else { \ + M_F(name, _read_lock)(src1); \ + M_F(name, _write_lock)(out); \ + } \ + return; \ + } \ /* See above */ \ if (src1 > src2) { \ M_SWAP(const shared_t *, src1, src2); \ @@ -560,8 +588,25 @@ static inline void M_F(name, _write_read2_lock)(shared_t *out, const shared_t *s } \ } \ \ -static inline void M_F(name, _write_read2_unlock)(shared_t *out, const shared_t *src1, const shared_t *src2) \ +fattr void M_F(name, _write_read2_unlock)(shared_t *out, const shared_t *src1, const shared_t *src2); \ +fattr void M_F(name, _write_read2_unlock)(shared_t *out, const shared_t *src1, const shared_t *src2) \ { \ + /* We can have out == src1 or out == src2 or src1 == src2 */ \ + /* if src1 == src2, nothing special to do (read_lock are compatible each other )*/ \ + if (out == src1) { \ + if (out == src2) { \ + M_F(name, _write_unlock)(out); \ + } else { \ + M_F(name, _read_unlock)(src2); \ + M_F(name, _write_unlock)(out); \ + } \ + return; \ + } else if (out == src2) { \ + M_ASSERT(out != src1); \ + M_F(name, _read_unlock)(src1); \ + M_F(name, _write_unlock)(out); \ + return; \ + } \ /* NOTE: No need to order the unlock */ \ M_F(name, _read_unlock)(src1); \ M_F(name, _read_unlock)(src2); \