summaryrefslogtreecommitdiff
path: root/gc.c
diff options
context:
space:
mode:
authorNobuyoshi Nakada <nobu@ruby-lang.org>2022-07-10 17:56:36 +0900
committerNobuyoshi Nakada <nobu@ruby-lang.org>2022-07-10 17:56:36 +0900
commitec09ba58d11f9679dade7df1973b60b1f6ebcaf3 (patch)
treeb19bd919c48b627488bb09aa3bf2291a7da17c5c /gc.c
parent072a8bf76088232ac6e38d689e75323f560fa76d (diff)
Extract `atomic_inc_wraparound` function
Diffstat (limited to 'gc.c')
-rw-r--r--gc.c22
1 files changed, 12 insertions, 10 deletions
diff --git a/gc.c b/gc.c
index af3b6ec054..a1dc054414 100644
--- a/gc.c
+++ b/gc.c
@@ -13979,23 +13979,25 @@ rb_raw_obj_info(char *const buff, const size_t buff_size, VALUE obj)
static rb_atomic_t obj_info_buffers_index = 0;
static char obj_info_buffers[OBJ_INFO_BUFFERS_NUM][OBJ_INFO_BUFFERS_SIZE];
-static char *
-obj_info_next_buffer(void)
+/* Increments *var atomically and resets *var to 0 when maxval is
+ * reached. Returns the wraparound old *var value (0...maxval). */
+static rb_atomic_t
+atomic_inc_wraparound(rb_atomic_t *var, const rb_atomic_t maxval)
{
- const rb_atomic_t index = RUBY_ATOMIC_FETCH_ADD(obj_info_buffers_index, 1);
-
- rb_atomic_t next_index = (index + 1);
- if (UNLIKELY(next_index >= OBJ_INFO_BUFFERS_NUM)) {
- rb_atomic_t reset_index = next_index % OBJ_INFO_BUFFERS_NUM;
- RUBY_ATOMIC_CAS(obj_info_buffers_index, next_index, reset_index);
+ rb_atomic_t oldval = RUBY_ATOMIC_FETCH_ADD(*var, 1);
+ if (UNLIKELY(oldval >= maxval - 1)) { // wraparound *var
+ const rb_atomic_t newval = oldval + 1;
+ RUBY_ATOMIC_CAS(*var, newval, newval % maxval);
+ oldval %= maxval;
}
- return obj_info_buffers[index % OBJ_INFO_BUFFERS_NUM];
+ return oldval;
}
static const char *
obj_info(VALUE obj)
{
- char *const buff = obj_info_next_buffer();
+ rb_atomic_t index = atomic_inc_wraparound(&obj_info_buffers_index, OBJ_INFO_BUFFERS_NUM);
+ char *const buff = obj_info_buffers[index];
return rb_raw_obj_info(buff, OBJ_INFO_BUFFERS_SIZE, obj);
}
#else