From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.io!.POSTED.blaine.gmane.org!not-for-mail From: Pip Cet via "Emacs development discussions." Newsgroups: gmane.emacs.devel Subject: Re: Some experience with the igc branch Date: Wed, 25 Dec 2024 17:40:42 +0000 Message-ID: <87cyhf8xw5.fsf@protonmail.com> References: <87o713wwsi.fsf@telefonica.net> <86o7112rnq.fsf@gnu.org> <867c7p2nz4.fsf@gnu.org> <861pxx2lh7.fsf@gnu.org> <86ldw40xbo.fsf@gnu.org> Reply-To: Pip Cet Mime-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: quoted-printable Injection-Info: ciao.gmane.io; posting-host="blaine.gmane.org:116.202.254.214"; logging-data="32543"; mail-complaints-to="usenet@ciao.gmane.io" Cc: Eli Zaretskii , ofv@wanadoo.es, emacs-devel@gnu.org, eller.helmut@gmail.com, acorallo@gnu.org To: =?utf-8?Q?Gerd_M=C3=B6llmann?= Original-X-From: emacs-devel-bounces+ged-emacs-devel=m.gmane-mx.org@gnu.org Wed Dec 25 18:47:33 2024 Return-path: Envelope-to: ged-emacs-devel@m.gmane-mx.org Original-Received: from lists.gnu.org ([209.51.188.17]) by ciao.gmane.io with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.92) (envelope-from ) id 1tQVTo-0008Hv-Bh for ged-emacs-devel@m.gmane-mx.org; Wed, 25 Dec 2024 18:47:32 +0100 Original-Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1tQVT6-0004AM-6t; Wed, 25 Dec 2024 12:46:48 -0500 Original-Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1tQVNN-00036E-Ia for emacs-devel@gnu.org; Wed, 25 Dec 2024 12:40:53 -0500 Original-Received: from mail-10629.protonmail.ch ([79.135.106.29]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1tQVNK-0006TA-K4 for emacs-devel@gnu.org; Wed, 25 Dec 2024 12:40:53 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=protonmail.com; s=protonmail3; t=1735148446; x=1735407646; bh=h3+cKs3DsLZrm4YYjRSHBOrHovEvnxB5TzfUnylHb2Q=; h=Date:To:From:Cc:Subject:Message-ID:In-Reply-To:References: Feedback-ID:From:To:Cc:Date:Subject:Reply-To:Feedback-ID: Message-ID:BIMI-Selector:List-Unsubscribe:List-Unsubscribe-Post; b=Dde1OeuvBfAFXiQiyw0p0X1sTX0W1d9ykykRqeSUDsjdvggs4OGPgakqD0JskZvj+ X7fKwLA3i8bYzBwGFse2FBVOC+nhQ/IGBenfZWw78d6++fUol7l3yQonnvLXWkS6SV 9Mfi6uv9agZcKyP4eJ0/fawVI8EdMnFwyvS/k/+ZIS7aphDxZu3pYAniMF02L515l/ zf4nlfrNwM64WEfioyL/jfYidus47ry52K6x7g8BlbS4Lm3MDa2fz4DEbqLVmDRXqJ z1UCjfmrQjIIFO0JKb7pB5jVcAYj0sySC30f+okYRpLxX1w5eJrL8cmpGc8ZNBYv89 3pZByP4ImndJQ== In-Reply-To: Feedback-ID: 112775352:user:proton X-Pm-Message-ID: 0620c8a264820d1bdf85a77af20351b231ef9303 Received-SPF: pass client-ip=79.135.106.29; envelope-from=pipcet@protonmail.com; helo=mail-10629.protonmail.ch X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, FREEMAIL_FROM=0.001, RCVD_IN_MSPIKE_H3=0.001, RCVD_IN_MSPIKE_WL=0.001, RCVD_IN_VALIDITY_CERTIFIED_BLOCKED=0.001, RCVD_IN_VALIDITY_RPBL_BLOCKED=0.001, SPF_HELO_PASS=-0.001, SPF_PASS=-0.001 autolearn=unavailable autolearn_force=no X-Spam_action: no action X-Mailman-Approved-At: Wed, 25 Dec 2024 12:46:45 -0500 X-BeenThere: emacs-devel@gnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: "Emacs development discussions." List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: emacs-devel-bounces+ged-emacs-devel=m.gmane-mx.org@gnu.org Original-Sender: emacs-devel-bounces+ged-emacs-devel=m.gmane-mx.org@gnu.org Xref: news.gmane.io gmane.emacs.devel:327115 Archived-At: Gerd M=C3=B6llmann writes: > DEFUN ("function-equal", Ffunction_equal, Sfunction_equal, 2, 2, 0, > doc: /* Return non-nil if F1 and F2 come from the same source. > Used to determine if different closures are just different instances of > the same lambda expression, or are really unrelated function. */) > (Lisp_Object f1, Lisp_Object f2) > { > bool res; > if (EQ (f1, f2)) This EQ can also trip. Sorry to insist on that, but I think it's an important point: if we change Lisp internals (such as the slow EQ thing), the "we're not dereferencing it, just looking at the bit representation of the pointer" approach will fail again, in unexpected places. I haven't seen a technical argument against using separate stacks for MPS and signals (I don't consider "it's a change and we'd need to test it" to be any more true for this change than for any other proposed change, or for what's in scratch/igc now). It would get us on par with master. (Both versions need to add the best memory barrier we have to the specpdl_ptr++ code) (I don't think MPS works on multi-threaded systems if word stores aren't atomic. If thread A is in the middle of updating an mps_word referencing another object, and thread B triggers a GC, thread A is stopped and thread B might scan the segment in the inconsistent state.) Miraculously, everything can be made to work out in the WIDE_EMACS_INT case, even though 64-bit words are stored in two insns: we only look at the LSB 32-bit word when fixing (because we USE_LSB_TAG), so that'll just work. Late exthdr creation needed to be changed a little, and now assumes changing a 64-bit value to another 64-bit value which differs only in one 32-bit half is atomic. Here's a snapshot of the current code. It still assumes strong memory ordering between threads because I'm pretty sure MPS needs that, too, so it's just asm volatile ("" ::: "memory") for now. diff --git a/src/igc.c b/src/igc.c index 136667aefea..4342964382a 100644 --- a/src/igc.c +++ b/src/igc.c @@ -747,19 +747,42 @@ IGC_DEFINE_LIST (igc_root); =20 /* Registry entry for an MPS thread mps_thr_t. */ =20 +/* FIXME */ +#include + +struct emacs_ap +{ + mps_ap_t mps_ap; + struct igc *gc; + size_t requested_bytes; + void *usable_memory; + void *usable_memory_end; + +#ifdef ENABLE_CHECKING + atomic_uintptr_t waiting_threads; /* debug only */ + sys_thread_t emacs_thread; +#endif +}; + +typedef struct emacs_ap emacs_ap_t; + +#ifndef ATOMIC_POINTER_LOCK_FREE +#error "this probably won't work" +#endif + struct igc_thread { struct igc *gc; mps_thr_t thr; =20 /* Allocation points for the thread. */ - mps_ap_t dflt_ap; - mps_ap_t leaf_ap; - mps_ap_t weak_strong_ap; - mps_ap_t weak_weak_ap; - mps_ap_t weak_hash_strong_ap; - mps_ap_t weak_hash_weak_ap; - mps_ap_t immovable_ap; + emacs_ap_t dflt_ap; + emacs_ap_t leaf_ap; + emacs_ap_t weak_strong_ap; + emacs_ap_t weak_weak_ap; + emacs_ap_t weak_hash_strong_ap; + emacs_ap_t weak_hash_weak_ap; + emacs_ap_t immovable_ap; =20 /* Quick access to the roots used for specpdl, bytecode stack and control stack. */ @@ -814,6 +837,15 @@ IGC_DEFINE_LIST (igc_thread); /* The real signal mask we want to restore after handling pending * signals. */ sigset_t signal_mask; + + sys_thread_t allocation_thread; + sys_mutex_t mutex; + sys_cond_t cond; + atomic_uintptr_t which_ap; + atomic_uintptr_t fault_address; + atomic_uintptr_t manual_collections; + atomic_uintptr_t idle_time; + atomic_uintptr_t idle_work; }; =20 static bool process_one_message (struct igc *gc); @@ -2913,8 +2945,179 @@ igc_root_destroy_comp_unit_eph (struct Lisp_Native_= Comp_Unit *u) maybe_destroy_root (&u->data_eph_relocs_root); } =20 +static mps_addr_t alloc_impl_raw (size_t size, mps_ap_t ap); +static mps_addr_t alloc_impl (size_t size, enum igc_obj_type type, emacs_a= p_t *ap); +static void igc_collect_raw (void); + +static void *igc_allocation_thread (void *igc_v) +{ + uint64_t n_alloc =3D 0; + uint64_t bytes_alloc =3D 0; + struct igc *gc =3D igc_v; + sys_mutex_lock (&gc->mutex); + while (true) + { + uintptr_t fault_address =3D gc->fault_address; + + if (fault_address) +=09{ +=09 volatile char *cp =3D (void *)fault_address; +=09 volatile char c =3D *cp; +=09 (void) c; +=09 atomic_store (&gc->fault_address, 0); +=09 continue; +=09} + + uintptr_t which_ap =3D gc->which_ap; + if (which_ap) +=09{ +=09 atomic_store (&gc->which_ap, 0); +=09 emacs_ap_t *ap =3D (void *)which_ap; +=09 if (gc->allocation_thread !=3D sys_thread_self ()) +=09 emacs_abort(); +=09 if (!ap->usable_memory) +=09 { +=09 igc_root_create_ambig ((char *)&ap->usable_memory, +=09=09=09=09 (char *)(&ap->usable_memory+1), +=09=09=09=09 "thread ap memory root"); +=09 } +=09 while (ap->requested_bytes) +=09 { +=09 size_t size =3D ap->requested_bytes; +=09 if (size < 1024 * 1024) +=09=09size =3D 1024 * 1024; +=09 void *p =3D alloc_impl_raw (size, ap->mps_ap); +=09 n_alloc++; +=09 bytes_alloc +=3D size; +#if 0 +=09 if (0 =3D=3D ((n_alloc-1)&n_alloc)) +=09=09fprintf (stderr, "%ld %ld\n", n_alloc, bytes_alloc); +#endif +=09 ap->usable_memory =3D p; +=09 ap->usable_memory_end =3D (char *)p + size; +=09 ap->requested_bytes =3D 0; +=09 sched_yield (); +=09 } +=09 continue; +=09} + + uintptr_t manual_collections =3D gc->manual_collections; + if (manual_collections) +=09{ +=09 igc_collect_raw (); +=09 atomic_store (&gc->manual_collections, 0); +=09 continue; +=09} + + uintptr_t idle_time =3D gc->idle_time; + if (idle_time) +=09{ +=09 double interval =3D idle_time * 1e-9; +=09 atomic_store (&gc->idle_time, 0); +=09 if (mps_arena_step (global_igc->arena, interval, 0)) +=09 atomic_store (&gc->idle_work, 1); +=09 else +=09 atomic_store (&gc->idle_work, 0); + +=09 continue; +=09} + + sys_cond_wait (&gc->cond, &gc->mutex); + } + sys_mutex_unlock (&gc->mutex); /* in case the infloop returns */ + + return NULL; +} + +static mps_addr_t alloc_impl (size_t size, enum igc_obj_type type, emacs_a= p_t *ap) +{ + if (size =3D=3D 0) + return 0; + + while (size & 7) + size++; + + mps_addr_t ret =3D 0; + while (!ret) + { +#ifdef ENABLE_CHECKING + if (ap->emacs_thread !=3D sys_thread_self ()) +=09emacs_abort (); + uintptr_t other_threads =3D atomic_fetch_add (&ap->waiting_threads, = 1); + if (other_threads !=3D 0) +=09{ +=09 /* we know that the other "thread" is actually on top of us, +=09 * and we're a signal handler, so we shouldn't be allocating +=09 * memory. */ +=09 emacs_abort (); +=09} +#endif + + void *candidate =3D ap->usable_memory; + void *end =3D ap->usable_memory_end; + if ((char *)candidate + size <=3D (char *)end) +=09{ +=09 void *actual =3D ap->usable_memory; +=09 void *actual_end =3D (char *)actual + size; +=09 ap->usable_memory =3D actual_end; +=09 if (actual_end < end) +=09 { +=09 set_header ((struct igc_header *)actual_end, IGC_OBJ_PAD, (char *= )end - (char *)actual_end, 0); +=09 } +=09 asm volatile ("" : : : "memory"); +=09 set_header ((struct igc_header *)actual, type, size, alloc_hash ()); +=09 ret =3D actual; +=09} + else +=09{ +=09 ap->requested_bytes =3D (size_t) size; + +=09 while (ap->requested_bytes) +=09 { +=09 /* No MPS data can be accessed by the main thread while it holds = the mutex! */ +=09 sys_mutex_lock (&ap->gc->mutex); +=09 atomic_store (&ap->gc->which_ap, (uintptr_t) ap); +=09 sys_cond_broadcast (&ap->gc->cond); +=09 sys_mutex_unlock (&ap->gc->mutex); +=09 sched_yield (); +=09 } +=09} +#ifdef ENABLE_CHECKING + atomic_fetch_add (&ap->waiting_threads, -1); +#endif + } + return (mps_addr_t) ret; +} + +static mps_res_t emacs_ap_create_k (emacs_ap_t *ap, mps_pool_t pool, +=09=09=09=09 mps_arg_s *args) +{ + ap->gc =3D global_igc; + ap->usable_memory =3D NULL; + ap->usable_memory_end =3D NULL; +#ifdef ENABLE_CHECKING + atomic_store(&ap->waiting_threads, 0); +#endif + ap->requested_bytes =3D 0; + + static int just_one; + if (!(just_one++)) + if (!sys_thread_create(&ap->gc->allocation_thread, igc_allocation_thre= ad, ap->gc)) + emacs_abort (); + +#ifdef ENABLE_CHECKING + ap->emacs_thread =3D sys_thread_self (); +#endif + return mps_ap_create_k (&ap->mps_ap, pool, args); +} + +static void emacs_ap_destroy (emacs_ap_t *ap) +{ + return; +} + static mps_res_t -create_weak_ap (mps_ap_t *ap, struct igc_thread *t, bool weak) +create_weak_ap (emacs_ap_t *ap, struct igc_thread *t, bool weak) { struct igc *gc =3D t->gc; mps_res_t res; @@ -2923,14 +3126,14 @@ create_weak_ap (mps_ap_t *ap, struct igc_thread *t,= bool weak) { MPS_ARGS_ADD (args, MPS_KEY_RANK, =09=09 weak ? mps_rank_weak () : mps_rank_exact ()); - res =3D mps_ap_create_k (ap, pool, args); + res =3D emacs_ap_create_k (ap, pool, args); } MPS_ARGS_END (args); return res; } =20 static mps_res_t -create_weak_hash_ap (mps_ap_t *ap, struct igc_thread *t, bool weak) +create_weak_hash_ap (emacs_ap_t *ap, struct igc_thread *t, bool weak) { struct igc *gc =3D t->gc; mps_res_t res; @@ -2939,7 +3142,7 @@ create_weak_hash_ap (mps_ap_t *ap, struct igc_thread = *t, bool weak) { MPS_ARGS_ADD (args, MPS_KEY_RANK, =09=09 weak ? mps_rank_weak () : mps_rank_exact ()); - res =3D mps_ap_create_k (ap, pool, args); + res =3D emacs_ap_create_k (ap, pool, args); } MPS_ARGS_END (args); return res; @@ -2949,12 +3152,14 @@ create_weak_hash_ap (mps_ap_t *ap, struct igc_threa= d *t, bool weak) create_thread_aps (struct igc_thread *t) { struct igc *gc =3D t->gc; + sys_cond_init (&gc->cond); + sys_mutex_init (&gc->mutex); mps_res_t res; - res =3D mps_ap_create_k (&t->dflt_ap, gc->dflt_pool, mps_args_none); + res =3D emacs_ap_create_k (&t->dflt_ap, gc->dflt_pool, mps_args_none); IGC_CHECK_RES (res); - res =3D mps_ap_create_k (&t->leaf_ap, gc->leaf_pool, mps_args_none); + res =3D emacs_ap_create_k (&t->leaf_ap, gc->leaf_pool, mps_args_none); IGC_CHECK_RES (res); - res =3D mps_ap_create_k (&t->immovable_ap, gc->immovable_pool, mps_args_= none); + res =3D emacs_ap_create_k (&t->immovable_ap, gc->immovable_pool, mps_arg= s_none); IGC_CHECK_RES (res); res =3D create_weak_ap (&t->weak_strong_ap, t, false); res =3D create_weak_hash_ap (&t->weak_hash_strong_ap, t, false); @@ -3016,13 +3221,13 @@ igc_thread_remove (void **pinfo) destroy_root (&t->d.stack_root); destroy_root (&t->d.specpdl_root); destroy_root (&t->d.bc_root); - mps_ap_destroy (t->d.dflt_ap); - mps_ap_destroy (t->d.leaf_ap); - mps_ap_destroy (t->d.weak_strong_ap); - mps_ap_destroy (t->d.weak_weak_ap); - mps_ap_destroy (t->d.weak_hash_strong_ap); - mps_ap_destroy (t->d.weak_hash_weak_ap); - mps_ap_destroy (t->d.immovable_ap); + emacs_ap_destroy (&t->d.dflt_ap); + emacs_ap_destroy (&t->d.leaf_ap); + emacs_ap_destroy (&t->d.weak_strong_ap); + emacs_ap_destroy (&t->d.weak_weak_ap); + emacs_ap_destroy (&t->d.weak_hash_strong_ap); + emacs_ap_destroy (&t->d.weak_hash_weak_ap); + emacs_ap_destroy (&t->d.immovable_ap); mps_thread_dereg (deregister_thread (t)); } =20 @@ -3635,7 +3840,16 @@ arena_step (void) =09 interval =3D 0.05; =09} =20 - if (mps_arena_step (global_igc->arena, interval, 0)) + atomic_store (&global_igc->idle_time, interval * 1e9); + sys_cond_broadcast (&global_igc->cond); + while (global_igc->idle_time) +=09{ +=09 sched_yield (); +=09 sys_mutex_lock (&global_igc->mutex); +=09 sched_yield (); +=09 sys_mutex_unlock (&global_igc->mutex); +=09} + if (global_igc->idle_work) =09return true; } =20 @@ -3686,7 +3900,7 @@ igc_on_idle (void) } } =20 -static mps_ap_t +static emacs_ap_t * thread_ap (enum igc_obj_type type) { struct igc_thread_list *t =3D current_thread->gc_info; @@ -3707,13 +3921,13 @@ thread_ap (enum igc_obj_type type) emacs_abort (); =20 case IGC_OBJ_MARKER_VECTOR: - return t->d.weak_weak_ap; + return &t->d.weak_weak_ap; =20 case IGC_OBJ_WEAK_HASH_TABLE_WEAK_PART: - return t->d.weak_hash_weak_ap; + return &t->d.weak_hash_weak_ap; =20 case IGC_OBJ_WEAK_HASH_TABLE_STRONG_PART: - return t->d.weak_hash_strong_ap; + return &t->d.weak_hash_strong_ap; =20 case IGC_OBJ_VECTOR: case IGC_OBJ_CONS: @@ -3728,12 +3942,12 @@ thread_ap (enum igc_obj_type type) case IGC_OBJ_FACE_CACHE: case IGC_OBJ_BLV: case IGC_OBJ_HANDLER: - return t->d.dflt_ap; + return &t->d.dflt_ap; =20 case IGC_OBJ_STRING_DATA: case IGC_OBJ_FLOAT: case IGC_OBJ_BYTES: - return t->d.leaf_ap; + return &t->d.leaf_ap; } emacs_abort (); } @@ -3746,8 +3960,8 @@ igc_break (void) { } =20 -void -igc_collect (void) +static void +igc_collect_raw (void) { struct igc *gc =3D global_igc; if (gc->park_count =3D=3D 0) @@ -3758,6 +3972,26 @@ igc_collect (void) } } =20 +void +igc_collect (void) +{ + struct igc *gc =3D global_igc; + if (gc->park_count =3D=3D 0) + { + atomic_store (&gc->manual_collections, 1); + while (gc->manual_collections) +=09{ +=09 sys_cond_broadcast (&gc->cond); +=09 sched_yield (); +=09 sys_mutex_lock (&gc->mutex); +=09 /* pthread_mutex_lock () directly followed by +=09 * pthread_mutex_unlock () doesn't work, IIRC */ +=09 sched_yield (); +=09 sys_mutex_unlock (&gc->mutex); +=09} + } +} + DEFUN ("igc--collect", Figc__collect, Sigc__collect, 0, 0, 0, doc: /* Force an immediate arena garbage collection. */) (void) @@ -3805,7 +4039,7 @@ igc_hash (Lisp_Object key) object. */ =20 static mps_addr_t -alloc_impl (size_t size, enum igc_obj_type type, mps_ap_t ap) +alloc_impl_raw (size_t size, mps_ap_t ap) { mps_addr_t p UNINIT; size =3D alloc_size (size); @@ -3820,14 +4054,14 @@ alloc_impl (size_t size, enum igc_obj_type type, mp= s_ap_t ap) =09 memory_full (0); =09 /* Object _must_ have valid contents before commit. */ =09 memclear (p, size); -=09 set_header (p, type, size, alloc_hash ()); +=09 set_header (p, IGC_OBJ_PAD, size, 0); =09} while (!mps_commit (ap, p, size)); break; =20 case IGC_STATE_DEAD: p =3D xzalloc (size); - set_header (p, type, size, alloc_hash ()); + set_header (p, IGC_OBJ_PAD, size, alloc_hash ()); break; =20 case IGC_STATE_INITIAL: @@ -3854,7 +4088,7 @@ alloc (size_t size, enum igc_obj_type type) alloc_immovable (size_t size, enum igc_obj_type type) { struct igc_thread_list *t =3D current_thread->gc_info; - return alloc_impl (size, type, t->d.immovable_ap); + return alloc_impl (size, type, &t->d.immovable_ap); } =20 #ifdef HAVE_MODULES @@ -4087,6 +4321,8 @@ weak_hash_find_dependent (mps_addr_t base) =09struct Lisp_Weak_Hash_Table_Strong_Part *w =3D client; =09return w->weak; } + case IGC_OBJ_PAD: + return 0; default: emacs_abort (); } @@ -4448,8 +4684,12 @@ igc_external_header (struct igc_header *h) exthdr->hash =3D header_hash (h); exthdr->obj_type =3D header_type (h); exthdr->extra_dependency =3D Qnil; - /* On IA-32, the upper 32-bit word is 0 after this, which is okay. = */ - h->v =3D (intptr_t)exthdr + IGC_TAG_EXTHDR; + asm volatile ("" : : : "memory"); + uint64_t v =3D h->v; + /* maintain the upper 32-bit word for WIDE_EMACS_INT builds. */ + v -=3D (uintptr_t) v; + v +=3D (intptr_t)exthdr + IGC_TAG_EXTHDR; + h->v =3D v; mps_addr_t ref =3D (mps_addr_t) h; mps_res_t res =3D mps_finalize (global_igc->arena, &ref); IGC_CHECK_RES (res); @@ -4893,17 +5133,17 @@ igc_on_pdump_loaded (void *dump_base, void *hot_sta= rt, void *hot_end, igc_alloc_dump (size_t nbytes) { igc_assert (global_igc->park_count > 0); - mps_ap_t ap =3D thread_ap (IGC_OBJ_CONS); + emacs_ap_t *ap =3D thread_ap (IGC_OBJ_CONS); size_t block_size =3D igc_header_size () + nbytes; mps_addr_t block; do { - mps_res_t res =3D mps_reserve (&block, ap, block_size); + mps_res_t res =3D mps_reserve (&block, ap->mps_ap, block_size); if (res !=3D MPS_RES_OK) =09memory_full (0); set_header (block, IGC_OBJ_INVALID, block_size, 0); } - while (!mps_commit (ap, block, block_size)); + while (!mps_commit (ap->mps_ap, block, block_size)); return (char *) block + igc_header_size (); } =20 @@ -5050,6 +5290,40 @@ DEFUN ("igc--remove-extra-dependency", Figc__remove_= extra_dependency, return Qt; } =20 +static struct sigaction mps_sigaction; + +static void sigsegv_sigaction (int sig, siginfo_t *info, void *uap) +{ + if (sys_thread_self () =3D=3D main_thread.s.thread_id) + { + atomic_store (&global_igc->fault_address, (uintptr_t) info->si_addr)= ; + sys_cond_broadcast (&global_igc->cond); + sched_yield (); + sys_mutex_lock (&global_igc->mutex); + /* IIRC, pthread_mutex_lock directly followed by +=09 pthread_mutex_unlock causes problems somehow... */ + sched_yield (); + sys_mutex_unlock (&global_igc->mutex); + } + else + { + /* Recipe for disaster here, I guess. */ + mps_sigaction.sa_sigaction (sig, info, uap); + } +} + +#ifdef SIGSEGV +static void steal_sigsegv (void) +{ + struct sigaction emacs_sigaction; + emacs_sigaction.sa_sigaction =3D sigsegv_sigaction; + sigemptyset (&emacs_sigaction.sa_mask); + emacs_sigaction.sa_flags =3D SA_SIGINFO | SA_RESTART; + + sigaction (SIGSEGV, &emacs_sigaction, &mps_sigaction); +} +#endif + /*********************************************************************** =09=09=09=09 Init ***********************************************************************/ @@ -5061,6 +5335,9 @@ init_igc (void) (void) mps_lib_assert_fail_install (igc_assert_fail); global_igc =3D make_igc (); add_main_thread (); +#ifdef SIGSEGV + steal_sigsegv (); +#endif set_state (IGC_STATE_USABLE_PARKED); } =20 diff --git a/src/lisp.h b/src/lisp.h index 48585c2d8a1..37cc62052c1 100644 --- a/src/lisp.h +++ b/src/lisp.h @@ -4102,7 +4102,14 @@ backtrace_debug_on_exit (union specbinding *pdl) INLINE void grow_specpdl (void) { + /* we don't need a memory bus barrier here, but a logical memory + barrier so GCC doesn't reorder stores. */ + asm volatile ("" : : : "memory"); + /* This increment doesn't need to be atomic in its entirety, but it + can't expose an intermediate state of specpdl_ptr; IOW, the store + needs to be a single CPU instruction. */ specpdl_ptr++; + asm volatile ("" : : : "memory"); if (specpdl_ptr =3D=3D specpdl_end) grow_specpdl_allocation (); }