From bbb9f7235329380d9cf617530ca4d39ba07e1824 Mon Sep 17 00:00:00 2001 From: Kenta Murata Date: Sun, 13 Nov 2022 12:46:22 +0900 Subject: [ruby/bigdecimal] Rewrite allocation functions * Rename them * Make allocation count operations atomic https://github.com/ruby/bigdecimal/commit/a5ab34a115 --- ext/bigdecimal/bigdecimal.c | 159 +++++++++++++++++++++++++------------------- ext/bigdecimal/bigdecimal.h | 3 - 2 files changed, 90 insertions(+), 72 deletions(-) (limited to 'ext/bigdecimal') diff --git a/ext/bigdecimal/bigdecimal.c b/ext/bigdecimal/bigdecimal.c index 0b424f62ee..fcb4f460e9 100644 --- a/ext/bigdecimal/bigdecimal.c +++ b/ext/bigdecimal/bigdecimal.c @@ -112,6 +112,77 @@ static struct { #define BIGDECIMAL_POSITIVE_P(bd) ((bd)->sign > 0) #define BIGDECIMAL_NEGATIVE_P(bd) ((bd)->sign < 0) +/* + * ================== Memory allocation ============================ + */ + +#ifdef BIGDECIMAL_DEBUG +static size_t rbd_allocation_count = 0; /* Memory allocation counter */ +static inline void +atomic_allocation_count_inc(void) +{ + RUBY_ATOMIC_SIZE_INC(rbd_allocation_count); +} +static inline void +atomic_allocation_count_dec_nounderflow(void) +{ + if (rbd_allocation_count == 0) return; + RUBY_ATOMIC_SIZE_DEC(rbd_allocation_count); +} +static void +check_allocation_count_nonzero(void) +{ + if (rbd_allocation_count != 0) return; + rb_bug("[bigdecimal][rbd_free_struct] Too many memory free calls"); +} +#else +# define atomic_allocation_count_inc() /* nothing */ +# define atomic_allocation_count_dec_nounderflow() /* nothing */ +# define check_allocation_count_nonzero() /* nothing */ +#endif /* BIGDECIMAL_DEBUG */ + +PUREFUNC(static inline size_t rbd_struct_size(size_t const)); + +static inline size_t +rbd_struct_size(size_t const internal_digits) +{ + return offsetof(Real, frac) + sizeof(DECDIG) * internal_digits; +} + +static inline Real * +rbd_allocate_struct(size_t const internal_digits) +{ + size_t const size = rbd_struct_size(internal_digits); + Real *real = ruby_xcalloc(1, size); + atomic_allocation_count_inc(); + return real; +} + +static VALUE BigDecimal_wrap_struct(VALUE obj, Real *vp); + +static inline Real * +rbd_reallocate_struct(Real *real, size_t const internal_digits) +{ + size_t const size = rbd_struct_size(internal_digits); + VALUE obj = real ? real->obj : 0; + Real *new_real = (Real *)ruby_xrealloc(real, size); + if (obj) { + new_real->obj = 0; + BigDecimal_wrap_struct(obj, new_real); + } + return new_real; +} + +static void +rbd_free_struct(Real *real) +{ + if (real != NULL) { + check_allocation_count_nonzero(); + ruby_xfree(real); + atomic_allocation_count_dec_nounderflow(); + } +} + /* * ================== Ruby Interface part ========================== */ @@ -145,7 +216,7 @@ static VALUE BigDecimal_negative_zero(void); static void BigDecimal_delete(void *pv) { - VpFree(pv); + rbd_free_struct(pv); } static size_t @@ -980,26 +1051,12 @@ VpCreateRbObject(size_t mx, const char *str, bool raise_exception) return VpNewRbClass(mx, str, rb_cBigDecimal, true, raise_exception); } -#define VpAllocReal(prec) (Real *)VpMemAlloc(offsetof(Real, frac) + (prec) * sizeof(DECDIG)) - -static Real * -VpReallocReal(Real *pv, size_t prec) -{ - VALUE obj = pv ? pv->obj : 0; - Real *new_pv = (Real *)VpMemRealloc(pv, offsetof(Real, frac) + prec * sizeof(DECDIG)); - if (obj) { - new_pv->obj = 0; - BigDecimal_wrap_struct(obj, new_pv); - } - return new_pv; -} - static Real * VpCopy(Real *pv, Real const* const x) { assert(x != NULL); - pv = VpReallocReal(pv, x->MaxPrec); + pv = rbd_reallocate_struct(pv, x->MaxPrec); pv->MaxPrec = x->MaxPrec; pv->Prec = x->Prec; pv->exponent = x->exponent; @@ -1825,7 +1882,7 @@ BigDecimal_DoDivmod(VALUE self, VALUE r, Real **div, Real **mod) if (!VpIsZero(c) && (VpGetSign(a) * VpGetSign(b) < 0)) { /* result adjustment for negative case */ - res = VpReallocReal(res, d->MaxPrec); + res = rbd_reallocate_struct(res, d->MaxPrec); res->MaxPrec = d->MaxPrec; VpAddSub(res, d, VpOne(), -1); GUARD_OBJ(d, VpCreateRbObject(GetAddSubPrec(c, b) * 2*BASE_FIG, "0", true)); @@ -3116,7 +3173,7 @@ rb_uint64_convert_to_BigDecimal(uint64_t uval, RB_UNUSED_VAR(size_t digs), int r Real *vp; if (uval == 0) { - vp = VpAllocReal(1); + vp = rbd_allocate_struct(1); vp->MaxPrec = 1; vp->Prec = 1; vp->exponent = 1; @@ -3124,7 +3181,7 @@ rb_uint64_convert_to_BigDecimal(uint64_t uval, RB_UNUSED_VAR(size_t digs), int r vp->frac[0] = 0; } else if (uval < BASE) { - vp = VpAllocReal(1); + vp = rbd_allocate_struct(1); vp->MaxPrec = 1; vp->Prec = 1; vp->exponent = 1; @@ -3150,7 +3207,7 @@ rb_uint64_convert_to_BigDecimal(uint64_t uval, RB_UNUSED_VAR(size_t digs), int r } const size_t exp = len + ntz; - vp = VpAllocReal(len); + vp = rbd_allocate_struct(len); vp->MaxPrec = len; vp->Prec = len; vp->exponent = exp; @@ -4494,42 +4551,6 @@ static int VpRdup(Real *m, size_t ind_m); static int gnAlloc = 0; /* Memory allocation counter */ #endif /* BIGDECIMAL_DEBUG */ -VP_EXPORT void * -VpMemAlloc(size_t mb) -{ - void *p = xmalloc(mb); - memset(p, 0, mb); -#ifdef BIGDECIMAL_DEBUG - gnAlloc++; /* Count allocation call */ -#endif /* BIGDECIMAL_DEBUG */ - return p; -} - -VP_EXPORT void * -VpMemRealloc(void *ptr, size_t mb) -{ - return xrealloc(ptr, mb); -} - -VP_EXPORT void -VpFree(Real *pv) -{ - if (pv != NULL) { - xfree(pv); -#ifdef BIGDECIMAL_DEBUG - gnAlloc--; /* Decrement allocation count */ - if (gnAlloc == 0) { - printf(" *************** All memories allocated freed ****************\n"); - /*getchar();*/ - } - if (gnAlloc < 0) { - printf(" ??????????? Too many memory free calls(%d) ?????????????\n", gnAlloc); - /*getchar();*/ - } -#endif /* BIGDECIMAL_DEBUG */ - } -} - /* * EXCEPTION Handling. */ @@ -5009,7 +5030,7 @@ bigdecimal_parse_special_string(const char *str) p = str + table[i].len; while (*p && ISSPACE(*p)) ++p; if (*p == '\0') { - Real *vp = VpAllocReal(1); + Real *vp = rbd_allocate_struct(1); vp->MaxPrec = 1; switch (table[i].sign) { default: @@ -5079,7 +5100,7 @@ VpAlloc(size_t mx, const char *szVal, int strict_p, int exc) /* necessary to be able to store */ /* at least mx digits. */ /* szVal==NULL ==> allocate zero value. */ - vp = VpAllocReal(mx); + vp = rbd_allocate_struct(mx); vp->MaxPrec = mx; /* set max precision */ VpSetZero(vp, 1); /* initialize vp to zero. */ return vp; @@ -5254,7 +5275,7 @@ VpAlloc(size_t mx, const char *szVal, int strict_p, int exc) if (mx == 0) mx = 1; nalloc = Max(nalloc, mx); mx = nalloc; - vp = VpAllocReal(mx); + vp = rbd_allocate_struct(mx); vp->MaxPrec = mx; /* set max precision */ VpSetZero(vp, sign); VpCtoV(vp, psz, ni, psz + ipf, nf, psz + ipe, ne); @@ -5828,8 +5849,8 @@ VpMult(Real *c, Real *a, Real *b) c->exponent = a->exponent; /* set exponent */ if (!AddExponent(c, b->exponent)) { - if (w) VpFree(c); - return 0; + if (w) rbd_free_struct(c); + return 0; } VpSetSign(c, VpGetSign(a) * VpGetSign(b)); /* set sign */ carry = 0; @@ -5879,10 +5900,10 @@ VpMult(Real *c, Real *a, Real *b) } } if (w != NULL) { /* free work variable */ - VpNmlz(c); - VpAsgn(w, c, 1); - VpFree(c); - c = w; + VpNmlz(c); + VpAsgn(w, c, 1); + rbd_free_struct(c); + c = w; } else { VpLimitRound(c,0); @@ -7047,8 +7068,8 @@ converge: y->MaxPrec = y_prec; Exit: - VpFree(f); - VpFree(r); + rbd_free_struct(f); + rbd_free_struct(r); return 1; } @@ -7470,8 +7491,8 @@ Exit: printf(" n=%"PRIdVALUE"\n", n); } #endif /* BIGDECIMAL_DEBUG */ - VpFree(w2); - VpFree(w1); + rbd_free_struct(w2); + rbd_free_struct(w1); return 1; } diff --git a/ext/bigdecimal/bigdecimal.h b/ext/bigdecimal/bigdecimal.h index 38dee51e68..46fafde13e 100644 --- a/ext/bigdecimal/bigdecimal.h +++ b/ext/bigdecimal/bigdecimal.h @@ -224,9 +224,6 @@ VP_EXPORT int VpIsNegDoubleZero(double v); #endif VP_EXPORT size_t VpNumOfChars(Real *vp,const char *pszFmt); VP_EXPORT size_t VpInit(DECDIG BaseVal); -VP_EXPORT void *VpMemAlloc(size_t mb); -VP_EXPORT void *VpMemRealloc(void *ptr, size_t mb); -VP_EXPORT void VpFree(Real *pv); VP_EXPORT Real *VpAlloc(size_t mx, const char *szVal, int strict_p, int exc); VP_EXPORT size_t VpAsgn(Real *c, Real *a, int isw); VP_EXPORT size_t VpAddSub(Real *c,Real *a,Real *b,int operation); -- cgit v1.2.1