From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on dcvr.yhbt.net X-Spam-Level: X-Spam-ASN: X-Spam-Status: No, score=-4.2 required=3.0 tests=ALL_TRUSTED,BAYES_00, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF, T_SCC_BODY_TEXT_LINE shortcircuit=no autolearn=ham autolearn_force=no version=3.4.2 Received: from localhost (dcvr.yhbt.net [127.0.0.1]) by dcvr.yhbt.net (Postfix) with ESMTP id A32721F619; Sat, 3 Sep 2022 09:27:41 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=80x24.org; s=selector1; t=1662197261; bh=3D5TcSHbNn2uUhUahBu6rZWxt1Z73b2UpTIM6qQDdgo=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=DxDptPHbk+1Prlr1fFqJxBoLG6C4DXRRQ6SaJoDX2BgQSl+xUv1fwSGBvbajLKbCJ Dhs78lUrV4EldC6FAjJr3dJVdEqFDgXrS4dujDNb8fPrsiu8PwZ5778yrA0ch0J8UF Xgd7wLFtrS6ZjSVpQttxaMkSZivc+J2+JaNKctek= From: Eric Wong To: mwrap-public@80x24.org Cc: Sam Saffron Subject: [PATCH 3/3] cleanup some FreeBSD-related workarounds Date: Sat, 3 Sep 2022 09:27:41 +0000 Message-Id: <20220903092741.2284559-4-e@80x24.org> In-Reply-To: <20220903092741.2284559-1-e@80x24.org> References: <20220903092741.2284559-1-e@80x24.org> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit List-Id: While FreeBSD 12.3 + Ruby 3.0.4p208 remains broken with mwrap (likely due to threading bugs in Ruby) at least get the code more consistently closer to a working state. Thus we'll remember to account for PTHREAD_MUTEX_INITIALIZER requiring malloc for HeapPageBody tracking, as we do with other mutexes. For reference, the Perl5 port of mwrap seems to have no problems on FreeBSD 12.3, so it seems down to misbehavior w.r.t. pthreads usage within Ruby itself. Perl5 on FreeBSD is configured with threads support, but Perl5 doesn't spawn background threads by default like Ruby can. --- README | 2 +- ext/mwrap/mwrap.c | 93 +++++++++++++++++++++++++++-------------------- 2 files changed, 54 insertions(+), 41 deletions(-) diff --git a/README b/README index f387bc4..539073e 100644 --- a/README +++ b/README @@ -23,7 +23,7 @@ It does not require recompiling or rebuilding Ruby, but only supports Ruby trunk (2.6.0dev+) on a few platforms: * GNU/Linux -* FreeBSD (tested 11.1) +* FreeBSD (tested 11.1 on Ruby 2.6, currently broken with Ruby 3.x) It may work on NetBSD, OpenBSD and DragonFly BSD. diff --git a/ext/mwrap/mwrap.c b/ext/mwrap/mwrap.c index 9d90298..1d6baec 100644 --- a/ext/mwrap/mwrap.c +++ b/ext/mwrap/mwrap.c @@ -99,9 +99,43 @@ union padded_mutex { /* a round-robin pool of mutexes */ #define MUTEX_NR (1 << 6) #define MUTEX_MASK (MUTEX_NR - 1) +#ifdef __FreeBSD__ +# define STATIC_MTX_INIT_OK (0) +#else /* only tested on Linux + glibc */ +# define STATIC_MTX_INIT_OK (1) +#endif static size_t mutex_i; static union padded_mutex mutexes[MUTEX_NR] = { +#if STATIC_MTX_INIT_OK [0 ... (MUTEX_NR-1)].mtx = PTHREAD_MUTEX_INITIALIZER +#endif +}; + +#define ACC_INIT(name) { .nr=0, .min=INT64_MAX, .max=-1, .m2=0, .mean=0 } +struct acc { + uint64_t nr; + int64_t min; + int64_t max; + double m2; + double mean; +}; + +/* for tracking 16K-aligned heap page bodies (protected by GVL) */ +struct { + pthread_mutex_t lock; + struct cds_list_head bodies; + struct cds_list_head freed; + + struct acc alive; + struct acc reborn; +} hpb_stats = { +#if STATIC_MTX_INIT_OK + .lock = PTHREAD_MUTEX_INITIALIZER, +#endif + .bodies = CDS_LIST_HEAD_INIT(hpb_stats.bodies), + .freed = CDS_LIST_HEAD_INIT(hpb_stats.freed), + .alive = ACC_INIT(hpb_stats.alive), + .reborn = ACC_INIT(hpb_stats.reborn) }; static pthread_mutex_t *mutex_assign(void) @@ -120,12 +154,11 @@ __attribute__((constructor)) static void resolve_malloc(void) int err; ++locating; -#ifdef __FreeBSD__ /* * PTHREAD_MUTEX_INITIALIZER on FreeBSD means lazy initialization, * which happens at pthread_mutex_lock, and that calls calloc */ - { + if (!STATIC_MTX_INIT_OK) { size_t i; for (i = 0; i < MUTEX_NR; i++) { @@ -135,22 +168,28 @@ __attribute__((constructor)) static void resolve_malloc(void) _exit(1); } } + err = pthread_mutex_init(&hpb_stats.lock, 0); + if (err) { + fprintf(stderr, "error: %s\n", strerror(err)); + _exit(1); + } /* initialize mutexes used by urcu-bp */ rcu_read_lock(); rcu_read_unlock(); +#ifndef __FreeBSD__ + } else { + if (!real_malloc) { + resolving_malloc = 1; + real_malloc = dlsym(RTLD_NEXT, "malloc"); + } + real_free = dlsym(RTLD_NEXT, "free"); + if (!real_malloc || !real_free) { + fprintf(stderr, "missing malloc/aligned_alloc/free\n" + "\t%p %p\n", real_malloc, real_free); + _exit(1); + } +#endif /* !__FreeBSD__ */ } -#else /* !FreeBSD (tested on GNU/Linux) */ - if (!real_malloc) { - resolving_malloc = 1; - real_malloc = dlsym(RTLD_NEXT, "malloc"); - } - real_free = dlsym(RTLD_NEXT, "free"); - if (!real_malloc || !real_free) { - fprintf(stderr, "missing malloc/aligned_alloc/free\n" - "\t%p %p\n", real_malloc, real_free); - _exit(1); - } -#endif /* !FreeBSD */ CMM_STORE_SHARED(totals, lfht_new()); if (!CMM_LOAD_SHARED(totals)) fprintf(stderr, "failed to allocate totals table\n"); @@ -237,32 +276,6 @@ static int has_ec_p(void) ruby_current_vm_ptr && ruby_current_ec; } -struct acc { - uint64_t nr; - int64_t min; - int64_t max; - double m2; - double mean; -}; - -#define ACC_INIT(name) { .nr=0, .min=INT64_MAX, .max=-1, .m2=0, .mean=0 } - -/* for tracking 16K-aligned heap page bodies (protected by GVL) */ -struct { - pthread_mutex_t lock; - struct cds_list_head bodies; - struct cds_list_head freed; - - struct acc alive; - struct acc reborn; -} hpb_stats = { - .lock = PTHREAD_MUTEX_INITIALIZER, - .bodies = CDS_LIST_HEAD_INIT(hpb_stats.bodies), - .freed = CDS_LIST_HEAD_INIT(hpb_stats.freed), - .alive = ACC_INIT(hpb_stats.alive), - .reborn = ACC_INIT(hpb_stats.reborn) -}; - /* allocated via real_malloc/real_free */ struct src_loc { pthread_mutex_t *mtx;