diff options
Diffstat (limited to 'mwrap_core.h')
-rw-r--r-- | mwrap_core.h | 166 |
1 files changed, 123 insertions, 43 deletions
diff --git a/mwrap_core.h b/mwrap_core.h index 02b60f3..15df857 100644 --- a/mwrap_core.h +++ b/mwrap_core.h @@ -9,8 +9,8 @@ # define MWRAP_PERL 0 #endif -#if !MWRAP_PERL -typedef void COP; +#ifndef MWRAP_RUBY +# define MWRAP_RUBY 0 #endif /* set a sensible max to avoid stack overflows */ @@ -18,20 +18,13 @@ typedef void COP; # define MWRAP_BT_MAX 32 #endif - -#if MWRAP_PERL -# include "EXTERN.h" -# include "perl.h" -# include "XSUB.h" -# include "embed.h" -# include "ppport.h" +#ifndef _GNU_SOURCE +# define _GNU_SOURCE #endif - #include <execinfo.h> #include <stdio.h> #include <stdlib.h> #include <string.h> -#include <dlfcn.h> #include <assert.h> #include <errno.h> #include <sys/types.h> @@ -44,6 +37,14 @@ typedef void COP; #include <urcu/rculist.h> #include <limits.h> +#if MWRAP_PERL +# include "EXTERN.h" +# include "perl.h" +# include "XSUB.h" +# include "embed.h" +# include "ppport.h" +#endif + /* * XXH3 (truncated to 32-bits) seems to provide a ~2% speedup. * XXH32 doesn't show improvements over jhash despite rculfhash @@ -75,12 +76,24 @@ static uint32_t bt_req_depth; #if MWRAP_PERL extern pthread_key_t __attribute__((weak)) PL_thr_key; extern const char __attribute__((weak)) PL_memory_wrap[]; /* needed for -O0 */ -#endif +# if !defined(PERL_IMPLICIT_CONTEXT) +static size_t *root_locating; /* determines if PL_curcop is our thread */ +# endif +#endif /* MWRAP_PERL */ +#if MWRAP_RUBY +static void mw_ruby_set_generation(size_t *, size_t); +# define SET_GENERATION(gen, size) mw_ruby_set_generation(gen, size) +static size_t last_gc_count; /* for httpd which runs in a non-GVL thread */ +#endif /* MWRAP_RUBY */ + +#ifndef SET_GENERATION /* C-only builds w/o Perl|Ruby */ +# define SET_GENERATION(gen, size) \ + *gen = uatomic_add_return(&total_bytes_inc, size) +#endif /* !SET_GENERATION */ + +/* generic stuff: */ static MWRAP_TSD size_t locating; -#if MWRAP_PERL && !defined(PERL_IMPLICIT_CONTEXT) -static size_t *root_locating; /* determines if PL_curcop is our thread */ -#endif static struct cds_lfht *files, *totals; union padded_mutex { pthread_mutex_t mtx; @@ -142,6 +155,7 @@ static void *my_mempcpy(void *dest, const void *src, size_t n) /* * only for interpreted sources (Perl/Ruby/etc), not backtrace_symbols* files + * Allocated via real_malloc / real_free */ struct src_file { struct cds_lfht_node nd; /* <=> files table */ @@ -179,7 +193,7 @@ struct alloc_hdr { struct cds_list_head anode; /* <=> src_loc.allocs */ union { struct { - size_t gen; /* global age */ + size_t gen; /* global age || rb_gc_count() */ struct src_loc *loc; } live; struct rcu_head dead; @@ -319,20 +333,6 @@ again: return l; } -static const COP *mwp_curcop(void) -{ -#if MWRAP_PERL - if (&PL_thr_key) { /* are we even in a Perl process? */ -# ifdef PERL_IMPLICIT_CONTEXT - if (aTHX) return PL_curcop; -# else /* !PERL_IMPLICIT_CONTEXT */ - if (&locating == root_locating) return PL_curcop; -# endif /* PERL_IMPLICIT_CONTEXT */ - } -#endif /* MWRAP_PERL */ - return NULL; -} - static uint32_t do_hash(const void *p, size_t len) { #if defined(XXH3_64bits) @@ -372,18 +372,43 @@ static struct src_file *src_file_get(struct cds_lfht *t, struct src_file *k, return cur ? caa_container_of(cur, struct src_file, nd) : NULL; } -#if !MWRAP_PERL -# define CopFILE(cop) NULL -# define CopLINE(cop) 0 -#endif -static struct src_loc *assign_line(size_t size, const COP *cop, - struct src_loc *sl) +#if MWRAP_PERL +static const COP *mwp_curcop(void) { - /* avoid vsnprintf or anything which could call malloc here: */ + if (&PL_thr_key) { /* are we even in a Perl process? */ +# ifdef PERL_IMPLICIT_CONTEXT + if (aTHX) return PL_curcop; +# else /* !PERL_IMPLICIT_CONTEXT */ + if (&locating == root_locating) return PL_curcop; +# endif /* PERL_IMPLICIT_CONTEXT */ + } + return NULL; +} + +static const char *mw_perl_src_file_cstr(unsigned *lineno) +{ + const COP *cop = mwp_curcop(); if (!cop) return NULL; const char *fn = CopFILE(cop); if (!fn) return NULL; - unsigned lineno = CopLINE(cop); + *lineno = CopLINE(cop); + return fn; +} +# define SRC_FILE_CSTR(lineno) mw_perl_src_file_cstr(lineno) +#endif /* MWRAP_PERL */ + +#if MWRAP_RUBY +static const char *mw_ruby_src_file_cstr(unsigned *lineno); +# define SRC_FILE_CSTR(lineno) mw_ruby_src_file_cstr(lineno) +#endif /* MWRAP_RUBY */ + +#ifndef SRC_FILE_CSTR /* for C-only compilation */ +# define SRC_FILE_CSTR(lineno) (NULL) +#endif /* !SRC_FILE_CSTR */ + +static struct src_loc *assign_line(size_t size, struct src_loc *sl, + const char *fn, unsigned lineno) +{ struct src_file *f; union stk_sf sf; struct cds_lfht_node *cur; @@ -430,7 +455,7 @@ again: } static struct src_loc * -update_stats_rcu_lock(size_t *generation, size_t size, struct src_loc *sl) +update_stats_rcu_lock(size_t *gen, size_t size, struct src_loc *sl) { struct cds_lfht *t = CMM_LOAD_SHARED(totals); struct src_loc *ret = NULL; @@ -438,11 +463,15 @@ update_stats_rcu_lock(size_t *generation, size_t size, struct src_loc *sl) if (caa_unlikely(!t)) return 0; /* not initialized */ if (locating++) goto out; /* do not recurse into another *alloc */ - *generation = uatomic_add_return(&total_bytes_inc, size); - const COP *cop = mwp_curcop(); + SET_GENERATION(gen, size); + + unsigned lineno; + const char *fn = SRC_FILE_CSTR(&lineno); + rcu_read_lock(); - ret = assign_line(size, cop, sl); - if (!ret) { /* no associated Perl code, just C/C++ */ + if (fn) + ret = assign_line(size, sl, fn, lineno); + if (!ret) { /* no associated Perl|Ruby code, just C/C++ */ sl->total = size; sl->f = NULL; sl->lineno = 0; @@ -1012,3 +1041,54 @@ __attribute__((constructor)) static void mwrap_ctor(void) } --locating; } + +#if MWRAP_RUBY +# undef _GNU_SOURCE /* ruby.h redefines it */ +# include <ruby.h> /* defines HAVE_RUBY_RACTOR_H on 3.0+ */ +# include <ruby/thread.h> +# include <ruby/io.h> +# ifdef HAVE_RUBY_RACTOR_H /* Ruby 3.0+ */ +extern MWRAP_TSD void * __attribute__((weak)) ruby_current_ec; +# else /* Ruby 2.6-2.7 */ +extern void * __attribute__((weak)) ruby_current_execution_context_ptr; +# define ruby_current_ec ruby_current_execution_context_ptr +# endif /* HAVE_RUBY_RACTOR_H */ + +extern void * __attribute__((weak)) ruby_current_vm_ptr; /* for rb_gc_count */ +extern size_t __attribute__((weak)) rb_gc_count(void); +int __attribute__((weak)) ruby_thread_has_gvl_p(void); + +const char *rb_source_location_cstr(int *line); /* requires 2.6.0dev or later */ +/* + * rb_source_location_cstr relies on GET_EC(), and it's possible + * to have a native thread but no EC during the early and late + * (teardown) phases of the Ruby process + */ +static int has_ec_p(void) +{ + return ruby_thread_has_gvl_p && ruby_thread_has_gvl_p() && + ruby_current_vm_ptr && ruby_current_ec; +} + +static void mw_ruby_set_generation(size_t *gen, size_t size) +{ + if (rb_gc_count) { + uatomic_add_return(&total_bytes_inc, size); + if (has_ec_p()) { + *gen = rb_gc_count(); + uatomic_set(&last_gc_count, *gen); + } + } else { + *gen = uatomic_add_return(&total_bytes_inc, size); + } +} + +static const char *mw_ruby_src_file_cstr(unsigned *lineno) +{ + if (!has_ec_p()) return NULL; + int line; + const char *fn = rb_source_location_cstr(&line); + *lineno = line < 0 ? UINT_MAX : (unsigned)line; + return fn; +} +#endif /* !MWRAP_RUBY */ |