unofficial mirror of emacs-devel@gnu.org 
 help / color / mirror / code / Atom feed
* MPS image cache
@ 2024-05-03  8:53 Gerd Möllmann
  2024-05-03 10:58 ` Helmut Eller
  2024-05-03 11:04 ` Eli Zaretskii
  0 siblings, 2 replies; 70+ messages in thread
From: Gerd Möllmann @ 2024-05-03  8:53 UTC (permalink / raw)
  To: Eli Zaretskii, Helmut Eller; +Cc: Emacs Devel

I think I have one: struct terminal's image_cache is not traced. AFAICS,
the cache is malloc'd and contains struct image which is an MPS object.

WDYT?



^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: MPS image cache
  2024-05-03  8:53 MPS image cache Gerd Möllmann
@ 2024-05-03 10:58 ` Helmut Eller
  2024-05-03 11:05   ` Po Lu
  2024-05-03 11:22   ` Gerd Möllmann
  2024-05-03 11:04 ` Eli Zaretskii
  1 sibling, 2 replies; 70+ messages in thread
From: Helmut Eller @ 2024-05-03 10:58 UTC (permalink / raw)
  To: Gerd Möllmann; +Cc: Eli Zaretskii, Emacs Devel

On Fri, May 03 2024, Gerd Möllmann wrote:

> I think I have one: struct terminal's image_cache is not traced. AFAICS,
> the cache is malloc'd and contains struct image which is an MPS object.
>
> WDYT?

Two options come to mind:
  1) trace it in fix_terminal
  2) register terminal.c:terminal_list as root.

It seems to me that creating a root is more "correct".

I have a similar problem with xterm.c:x_display_list which could be
registered as root or traced e.g. fix_frame.  (Also note that struct
struct terminal contains a x_display_info, which is probably the same as
the in x_display_list.)

So maybe we should indeed register terminal_list and as part of the
scan function, also trace the display_info.

There is a bit of an issue with proper initialization of the structs
pointed to by those roots.  E.g. x_term_init uses xzalloc, puts pointers
into the struct, and only then stores the pointer to the struct in
x_display_list.  So what should be the root, the struct (registred
immediately after the call to xzalloc) or the global variable
x_display_list?



^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: MPS image cache
  2024-05-03  8:53 MPS image cache Gerd Möllmann
  2024-05-03 10:58 ` Helmut Eller
@ 2024-05-03 11:04 ` Eli Zaretskii
  2024-05-03 11:08   ` Gerd Möllmann
  1 sibling, 1 reply; 70+ messages in thread
From: Eli Zaretskii @ 2024-05-03 11:04 UTC (permalink / raw)
  To: Gerd Möllmann; +Cc: eller.helmut, emacs-devel

> From: Gerd Möllmann <gerd.moellmann@gmail.com>
> Cc: Emacs Devel <emacs-devel@gnu.org>
> Date: Fri, 03 May 2024 10:53:50 +0200
> 
> I think I have one: struct terminal's image_cache is not traced. AFAICS,
> the cache is malloc'd and contains struct image which is an MPS object.
> 
> WDYT?

Is this related to Vterminal_frame, or is this a separate issue?



^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: MPS image cache
  2024-05-03 10:58 ` Helmut Eller
@ 2024-05-03 11:05   ` Po Lu
  2024-05-03 11:22   ` Gerd Möllmann
  1 sibling, 0 replies; 70+ messages in thread
From: Po Lu @ 2024-05-03 11:05 UTC (permalink / raw)
  To: Helmut Eller; +Cc: Gerd Möllmann, Eli Zaretskii, Emacs Devel

Helmut Eller <eller.helmut@gmail.com> writes:

> On Fri, May 03 2024, Gerd Möllmann wrote:
>
>> I think I have one: struct terminal's image_cache is not traced. AFAICS,
>> the cache is malloc'd and contains struct image which is an MPS object.
>>
>> WDYT?
>
> Two options come to mind:
>   1) trace it in fix_terminal
>   2) register terminal.c:terminal_list as root.
>
> It seems to me that creating a root is more "correct".
>
> I have a similar problem with xterm.c:x_display_list which could be
> registered as root or traced e.g. fix_frame.

It is valid for an open display not to have any frames under its name,
so they must be registered as roots.



^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: MPS image cache
  2024-05-03 11:04 ` Eli Zaretskii
@ 2024-05-03 11:08   ` Gerd Möllmann
  0 siblings, 0 replies; 70+ messages in thread
From: Gerd Möllmann @ 2024-05-03 11:08 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: eller.helmut, emacs-devel

Not related to terminal frame. It’s from running emacs interactively. 

Sent from my iPhone

> On 3. May 2024, at 13:05, Eli Zaretskii <eliz@gnu.org> wrote:
> 
> 
>> 
>> From: Gerd Möllmann <gerd.moellmann@gmail.com>
>> Cc: Emacs Devel <emacs-devel@gnu.org>
>> Date: Fri, 03 May 2024 10:53:50 +0200
>> 
>> I think I have one: struct terminal's image_cache is not traced. AFAICS,
>> the cache is malloc'd and contains struct image which is an MPS object.
>> 
>> WDYT?
> 
> Is this related to Vterminal_frame, or is this a separate issue?



^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: MPS image cache
  2024-05-03 10:58 ` Helmut Eller
  2024-05-03 11:05   ` Po Lu
@ 2024-05-03 11:22   ` Gerd Möllmann
  2024-05-03 11:43     ` Gerd Möllmann
                       ` (2 more replies)
  1 sibling, 3 replies; 70+ messages in thread
From: Gerd Möllmann @ 2024-05-03 11:22 UTC (permalink / raw)
  To: Helmut Eller; +Cc: Eli Zaretskii, Emacs Devel

Helmut Eller <eller.helmut@gmail.com> writes:

> On Fri, May 03 2024, Gerd Möllmann wrote:
>
>> I think I have one: struct terminal's image_cache is not traced. AFAICS,
>> the cache is malloc'd and contains struct image which is an MPS object.
>>
>> WDYT?
>
> Two options come to mind:
>   1) trace it in fix_terminal
>   2) register terminal.c:terminal_list as root.
>
> It seems to me that creating a root is more "correct".

I'm meanhile tending ta the third option: make iamge_cache an MPS object
like face_cache. For a reason that's proobably the reason why I made
fache_cache an MPS object:

While we scan an object, MPS gives us exclusive access to it. I think we
want that for these caches, so that scanning does not interfere iwth the
client modifying the cache?

Right?

> I have a similar problem with xterm.c:x_display_list which could be
> registered as root or traced e.g. fix_frame.  (Also note that struct
> struct terminal contains a x_display_info, which is probably the same as
> the in x_display_list.)
>
> So maybe we should indeed register terminal_list and as part of the
> scan function, also trace the display_info.
>
> There is a bit of an issue with proper initialization of the structs
> pointed to by those roots.  E.g. x_term_init uses xzalloc, puts pointers
> into the struct, and only then stores the pointer to the struct in
> x_display_list.  So what should be the root, the struct (registred
> immediately after the call to xzalloc) or the global variable
> x_display_list?

Hm.



^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: MPS image cache
  2024-05-03 11:22   ` Gerd Möllmann
@ 2024-05-03 11:43     ` Gerd Möllmann
  2024-05-03 13:24       ` Gerd Möllmann
  2024-05-03 14:59     ` MPS image cache Helmut Eller
  2024-05-03 15:02     ` Helmut Eller
  2 siblings, 1 reply; 70+ messages in thread
From: Gerd Möllmann @ 2024-05-03 11:43 UTC (permalink / raw)
  To: Helmut Eller; +Cc: Eli Zaretskii, Emacs Devel

Gerd Möllmann <gerd.moellmann@gmail.com> writes:

> Helmut Eller <eller.helmut@gmail.com> writes:
>
>> On Fri, May 03 2024, Gerd Möllmann wrote:
>>
>>> I think I have one: struct terminal's image_cache is not traced. AFAICS,
>>> the cache is malloc'd and contains struct image which is an MPS object.
>>>
>>> WDYT?
>>
>> Two options come to mind:
>>   1) trace it in fix_terminal
>>   2) register terminal.c:terminal_list as root.
>>
>> It seems to me that creating a root is more "correct".
>
> I'm meanhile tending ta the third option: make iamge_cache an MPS object
> like face_cache. For a reason that's proobably the reason why I made
> fache_cache an MPS object:
>
> While we scan an object, MPS gives us exclusive access to it. I think we
> want that for these caches, so that scanning does not interfere iwth the
> client modifying the cache?
>
> Right?

I've doen that now. It is right :-)



^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: MPS image cache
  2024-05-03 11:43     ` Gerd Möllmann
@ 2024-05-03 13:24       ` Gerd Möllmann
  2024-05-03 17:02         ` Gerd Möllmann
  0 siblings, 1 reply; 70+ messages in thread
From: Gerd Möllmann @ 2024-05-03 13:24 UTC (permalink / raw)
  To: Helmut Eller; +Cc: Eli Zaretskii, Emacs Devel

Gerd Möllmann <gerd.moellmann@gmail.com> writes:

> Gerd Möllmann <gerd.moellmann@gmail.com> writes:
>
>> Helmut Eller <eller.helmut@gmail.com> writes:
>>
>>> On Fri, May 03 2024, Gerd Möllmann wrote:
>>>
>>>> I think I have one: struct terminal's image_cache is not traced. AFAICS,
>>>> the cache is malloc'd and contains struct image which is an MPS object.
>>>>
>>>> WDYT?
>>>
>>> Two options come to mind:
>>>   1) trace it in fix_terminal
>>>   2) register terminal.c:terminal_list as root.
>>>
>>> It seems to me that creating a root is more "correct".
>>
>> I'm meanhile tending ta the third option: make iamge_cache an MPS object
>> like face_cache. For a reason that's proobably the reason why I made
>> fache_cache an MPS object:
>>
>> While we scan an object, MPS gives us exclusive access to it. I think we
>> want that for these caches, so that scanning does not interfere iwth the
>> client modifying the cache?
>>
>> Right?
>
> I've doen that now. It is right :-)

The next one I get is in nsterm.m

      NSWindow *parentWindow = [FRAME_NS_VIEW (parentFrame) window];

where parentFrame is a struct frame *. That can take some time...



^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: MPS image cache
  2024-05-03 11:22   ` Gerd Möllmann
  2024-05-03 11:43     ` Gerd Möllmann
@ 2024-05-03 14:59     ` Helmut Eller
  2024-05-03 15:11       ` Gerd Möllmann
  2024-05-03 15:02     ` Helmut Eller
  2 siblings, 1 reply; 70+ messages in thread
From: Helmut Eller @ 2024-05-03 14:59 UTC (permalink / raw)
  To: Gerd Möllmann; +Cc: Eli Zaretskii, Emacs Devel

On Fri, May 03 2024, Gerd Möllmann wrote:
> While we scan an object, MPS gives us exclusive access to it. I think we
> want that for these caches, so that scanning does not interfere iwth the
> client modifying the cache?

Access is exclusive to the image_cache struct, but not the buckets, I
think.



^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: MPS image cache
  2024-05-03 11:22   ` Gerd Möllmann
  2024-05-03 11:43     ` Gerd Möllmann
  2024-05-03 14:59     ` MPS image cache Helmut Eller
@ 2024-05-03 15:02     ` Helmut Eller
  2024-05-04 17:51       ` Gerd Möllmann
  2 siblings, 1 reply; 70+ messages in thread
From: Helmut Eller @ 2024-05-03 15:02 UTC (permalink / raw)
  To: Gerd Möllmann; +Cc: Eli Zaretskii, Emacs Devel

[-- Attachment #1: Type: text/plain, Size: 579 bytes --]

>> There is a bit of an issue with proper initialization of the structs
>> pointed to by those roots.  E.g. x_term_init uses xzalloc, puts pointers
>> into the struct, and only then stores the pointer to the struct in
>> x_display_list.  So what should be the root, the struct (registred
>> immediately after the call to xzalloc) or the global variable
>> x_display_list?
>
> Hm.

For my case, the troublesome field was xi_device_t.name.  I decided to
make x_display_info and xi_device_t amigous roots, because there is
usually only one x_display_info and dozen of xi_device_t.


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: 0001-Make-x_display_info-and-xi_device_t-amig-roots.patch --]
[-- Type: text/x-diff, Size: 4558 bytes --]

From 497b5c900e1a4746c214af7be6242d0bc456cdc7 Mon Sep 17 00:00:00 2001
From: Helmut Eller <eller.helmut@gmail.com>
Date: Fri, 3 May 2024 16:47:51 +0200
Subject: [PATCH] Make x_display_info and xi_device_t amig roots

* src/xterm.c (x_cache_xi_devices, xi_disable_devices): Use
  igc_xzalloc_ambig for xi_disable_t.
  (handle_one_xevent): For the XI_HierarchyChanged event
  igc_realloc_ambig if needed.
  (x_term_init): Use igc_xzalloc_ambig for dpyinfo.
* src/igc.h (igc_realloc_ambig): New.
* src/igc.c (igc_realloc_ambig): Not implemented yet;
  scetch of an implementation as comment.
---
 src/igc.c   | 24 ++++++++++++++++++++++--
 src/igc.h   |  1 +
 src/xterm.c | 29 +++++++++++++++++++++++++----
 3 files changed, 48 insertions(+), 6 deletions(-)

diff --git a/src/igc.c b/src/igc.c
index 648f2bbc44d..6d553bc316d 100644
--- a/src/igc.c
+++ b/src/igc.c
@@ -1389,10 +1389,10 @@ fix_frame (mps_ss_t ss, struct frame *f)
 	struct font **font_ptr = &FRAME_FONT (f);
 	if (*font_ptr)
 	  IGC_FIX12_RAW (ss, font_ptr);
-	Lisp_Object *nle = &FRAME_DISPLAY_INFO(f)->name_list_element;
+	Lisp_Object *nle = &FRAME_DISPLAY_INFO (f)->name_list_element;
 	IGC_FIX12_OBJ (ss, nle);
       }
-#endif
+#endif // HAVE_WINDOW_SYSTEM
   }
   MPS_SCAN_END (ss);
   return MPS_RES_OK;
@@ -2157,6 +2157,26 @@ igc_xzalloc_ambig (size_t size)
   return p;
 }
 
+void *
+igc_realloc_ambig (void *block, size_t size)
+{
+#if 0 // non tested code:
+  struct igc_root_list *r = root_find (block);
+  igc_assert (r != NULL);
+  destroy_root (&r);
+
+  /* Can't make a root that has zero length. Want one to be able to
+     detect calling igc_free on something not having a root. */
+  size_t new_size = (size == 0 ? IGC_ALIGN_DFLT : size);
+  void *p = xrealloc (block, new_size);
+  void *end = (char *)p + new_size;
+  root_create_ambig (global_igc, p, end);
+  return p;
+#endif
+  emacs_abort ();
+}
+
+
 void
 igc_xfree (void *p)
 {
diff --git a/src/igc.h b/src/igc.h
index 84e4ff8f13a..b1d09700a78 100644
--- a/src/igc.h
+++ b/src/igc.h
@@ -51,6 +51,7 @@ #define EMACS_IGC_H
 
 struct Lisp_Buffer_Local_Value *igc_alloc_blv (void);
 void *igc_xzalloc_ambig (size_t size);
+void *igc_realloc_ambig (void *block, size_t size);
 void igc_xfree (void *p);
 Lisp_Object *igc_xalloc_lisp_objs_exact (size_t n);
 void *igc_xpalloc_ambig (void *pa, ptrdiff_t *nitems, ptrdiff_t nitems_incr_min,
diff --git a/src/xterm.c b/src/xterm.c
index 36f83a33244..c47c7b0534d 100644
--- a/src/xterm.c
+++ b/src/xterm.c
@@ -787,6 +787,9 @@ #define XtNinitialState "initialState"
 #ifdef HAVE_XKB
 #include <X11/XKBlib.h>
 #endif
+#ifdef HAVE_MPS
+#include "igc.h"
+#endif
 
 /* Although X11/Xlib.h commonly defines the types XErrorHandler and
    XIOErrorHandler, they are not in the Xlib spec, so for portability
@@ -5744,7 +5747,11 @@ x_cache_xi_devices (struct x_display_info *dpyinfo)
       return;
     }
 
+#ifdef HAVE_MPS
+  dpyinfo->devices = igc_xzalloc_ambig (sizeof *dpyinfo->devices * ndevices);
+#else
   dpyinfo->devices = xzalloc (sizeof *dpyinfo->devices * ndevices);
+#endif
 
   for (i = 0; i < ndevices; ++i)
     {
@@ -13774,7 +13781,11 @@ xi_disable_devices (struct x_display_info *dpyinfo,
     return;
 
   ndevices = 0;
+#ifdef HAVE_MPS
+  devices = igc_xzalloc_ambig (sizeof *devices * dpyinfo->num_devices);
+#else
   devices = xzalloc (sizeof *devices * dpyinfo->num_devices);
+#endif
 
   /* Loop through every device currently in DPYINFO, and copy it to
      DEVICES if it is not in TO_DISABLE.  Note that this function
@@ -24600,10 +24611,15 @@ handle_one_xevent (struct x_display_info *dpyinfo,
 
 			  if (info && info->enabled)
 			    {
-			      dpyinfo->devices
-				= xrealloc (dpyinfo->devices,
-					    (sizeof *dpyinfo->devices
-					     * ++dpyinfo->num_devices));
+			      size_t new_size = (sizeof *dpyinfo->devices
+						 * ++dpyinfo->num_devices);
+#ifdef HAVE_MPS
+			      dpyinfo->devices =
+				igc_realloc_ambig (dpyinfo->devices, new_size);
+#else
+			      dpyinfo->devices =
+				xrealloc (dpyinfo->devices, new_size);
+#endif
 			      memset (dpyinfo->devices + dpyinfo->num_devices - 1,
 				      0, sizeof *dpyinfo->devices);
 			      device = &dpyinfo->devices[dpyinfo->num_devices - 1];
@@ -30676,7 +30692,12 @@ #define NUM_ARGV 10
 
   /* We have definitely succeeded.  Record the new connection.  */
 
+#ifdef HAVE_MPS
+  dpyinfo = igc_xzalloc_ambig (sizeof *dpyinfo);
+#else
   dpyinfo = xzalloc (sizeof *dpyinfo);
+#endif
+
   terminal = x_create_terminal (dpyinfo);
 
   if (!NILP (Vx_detect_server_trust))
-- 
2.39.2


^ permalink raw reply related	[flat|nested] 70+ messages in thread

* Re: MPS image cache
  2024-05-03 14:59     ` MPS image cache Helmut Eller
@ 2024-05-03 15:11       ` Gerd Möllmann
  2024-05-05  6:45         ` Gerd Möllmann
  0 siblings, 1 reply; 70+ messages in thread
From: Gerd Möllmann @ 2024-05-03 15:11 UTC (permalink / raw)
  To: Helmut Eller; +Cc: Eli Zaretskii, Emacs Devel

Helmut Eller <eller.helmut@gmail.com> writes:

> On Fri, May 03 2024, Gerd Möllmann wrote:
>> While we scan an object, MPS gives us exclusive access to it. I think we
>> want that for these caches, so that scanning does not interfere iwth the
>> client modifying the cache?
>
> Access is exclusive to the image_cache struct, but not the buckets, I
> think.

Right. Hm.



^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: MPS image cache
  2024-05-03 13:24       ` Gerd Möllmann
@ 2024-05-03 17:02         ` Gerd Möllmann
  2024-05-04  4:38           ` MPS: scroll-bars (was: MPS image cache) Helmut Eller
  0 siblings, 1 reply; 70+ messages in thread
From: Gerd Möllmann @ 2024-05-03 17:02 UTC (permalink / raw)
  To: Helmut Eller; +Cc: Eli Zaretskii, Emacs Devel

Gerd Möllmann <gerd.moellmann@gmail.com> writes:

> The next one I get is in nsterm.m
>
>       NSWindow *parentWindow = [FRAME_NS_VIEW (parentFrame) window];
>
> where parentFrame is a struct frame *. That can take some time...

So, did someting for NS in fix_frame, and this Emacs has survived for 10
minutes already...



^ permalink raw reply	[flat|nested] 70+ messages in thread

* MPS: scroll-bars (was: MPS image cache)
  2024-05-03 17:02         ` Gerd Möllmann
@ 2024-05-04  4:38           ` Helmut Eller
  2024-05-04  5:22             ` MPS: scroll-bars Gerd Möllmann
  2024-05-04  5:50             ` Po Lu
  0 siblings, 2 replies; 70+ messages in thread
From: Helmut Eller @ 2024-05-04  4:38 UTC (permalink / raw)
  To: Gerd Möllmann; +Cc: Eli Zaretskii, Emacs Devel

The function xterm.c:xg_finish_scroll_bar_creation hands a pointer to a
struct scroll_bar to GTK.  GTK simply passes this along to the
callback.  How could we trace this or how could we pin scroll bars?



^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: MPS: scroll-bars
  2024-05-04  4:38           ` MPS: scroll-bars (was: MPS image cache) Helmut Eller
@ 2024-05-04  5:22             ` Gerd Möllmann
  2024-05-04  5:29               ` Gerd Möllmann
  2024-05-04  5:50             ` Po Lu
  1 sibling, 1 reply; 70+ messages in thread
From: Gerd Möllmann @ 2024-05-04  5:22 UTC (permalink / raw)
  To: Helmut Eller; +Cc: Eli Zaretskii, Emacs Devel

Helmut Eller <eller.helmut@gmail.com> writes:

> The function xterm.c:xg_finish_scroll_bar_creation hands a pointer to a
> struct scroll_bar to GTK.  GTK simply passes this along to the
> callback.  How could we trace this or how could we pin scroll bars?

Moin Helmut.

With only having had one coffee, could we use an additional indirection
somehow? On the basis that every problem can be solved with an additional
indirection? 



^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: MPS: scroll-bars
  2024-05-04  5:22             ` MPS: scroll-bars Gerd Möllmann
@ 2024-05-04  5:29               ` Gerd Möllmann
  0 siblings, 0 replies; 70+ messages in thread
From: Gerd Möllmann @ 2024-05-04  5:29 UTC (permalink / raw)
  To: Helmut Eller; +Cc: Eli Zaretskii, Emacs Devel

Gerd Möllmann <gerd.moellmann@gmail.com> writes:

> Helmut Eller <eller.helmut@gmail.com> writes:
>
>> The function xterm.c:xg_finish_scroll_bar_creation hands a pointer to a
>> struct scroll_bar to GTK.  GTK simply passes this along to the
>> callback.  How could we trace this or how could we pin scroll bars?
>
> Moin Helmut.
>
> With only having had one coffee, could we use an additional indirection
> somehow? On the basis that every problem can be solved with an additional
> indirection?

That was too terse, sorry. I'm thinking of passing a scroll_bar **
through GTK to the callback. That would make it perhaps possible to put
the original scroll_bar * where it is better traceable, if that address
itself doesn't change... 



^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: MPS: scroll-bars
  2024-05-04  4:38           ` MPS: scroll-bars (was: MPS image cache) Helmut Eller
  2024-05-04  5:22             ` MPS: scroll-bars Gerd Möllmann
@ 2024-05-04  5:50             ` Po Lu
  2024-05-04  6:27               ` Helmut Eller
  1 sibling, 1 reply; 70+ messages in thread
From: Po Lu @ 2024-05-04  5:50 UTC (permalink / raw)
  To: Helmut Eller; +Cc: Gerd Möllmann, Eli Zaretskii, Emacs Devel

Helmut Eller <eller.helmut@gmail.com> writes:

> The function xterm.c:xg_finish_scroll_bar_creation hands a pointer to a
> struct scroll_bar to GTK.  GTK simply passes this along to the
> callback.  How could we trace this or how could we pin scroll bars?

Connect a callback that unpins the object's scroll bars to the "destroy"
signal of the object, as xg_gtk_scroll_destroy is immediately above.



^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: MPS: scroll-bars
  2024-05-04  5:50             ` Po Lu
@ 2024-05-04  6:27               ` Helmut Eller
  2024-05-04  6:45                 ` Gerd Möllmann
  2024-05-04  8:29                 ` MPS: scroll-bars Po Lu
  0 siblings, 2 replies; 70+ messages in thread
From: Helmut Eller @ 2024-05-04  6:27 UTC (permalink / raw)
  To: Po Lu; +Cc: Gerd Möllmann, Eli Zaretskii, Emacs Devel

On Sat, May 04 2024, Po Lu wrote:

> Helmut Eller <eller.helmut@gmail.com> writes:
>
>> The function xterm.c:xg_finish_scroll_bar_creation hands a pointer to a
>> struct scroll_bar to GTK.  GTK simply passes this along to the
>> callback.  How could we trace this or how could we pin scroll bars?
>
> Connect a callback that unpins the object's scroll bars to the "destroy"
> signal of the object, as xg_gtk_scroll_destroy is immediately above.

xg_gtk_scroll_destroy uses id_to_widget. That's a global variable.  I'd
rather avoid that.

I could allocate a single cell as ambiguous root to the scroll_bar.  That
would pin it.  Then pass that cell to a "destroy" callback to free the
cell.  Hmm.. a lot of work.

Could we perhaps use the mark-and-sweep pool for the widget-like
objects, like scroll_bar and window?  That would perhaps be easier,
because then widgets wouldn't move and tracing would be very similar to
what the old GC does.  And the widgets are hardly performance critical.



^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: MPS: scroll-bars
  2024-05-04  6:27               ` Helmut Eller
@ 2024-05-04  6:45                 ` Gerd Möllmann
  2024-05-04  7:05                   ` Helmut Eller
  2024-05-04  7:09                   ` Gerd Möllmann
  2024-05-04  8:29                 ` MPS: scroll-bars Po Lu
  1 sibling, 2 replies; 70+ messages in thread
From: Gerd Möllmann @ 2024-05-04  6:45 UTC (permalink / raw)
  To: Helmut Eller; +Cc: Po Lu, Eli Zaretskii, Emacs Devel

Helmut Eller <eller.helmut@gmail.com> writes:

> Could we perhaps use the mark-and-sweep pool for the widget-like
> objects, like scroll_bar and window?  That would perhaps be easier,
> because then widgets wouldn't move and tracing would be very similar to
> what the old GC does.  And the widgets are hardly performance critical.

We could try, certainly. They say

  AMS is not currently suitable for production use. However, it could be
  developed into a solid mark-and-sweep pool. If you have a use case
  that needs this, contact us.

so we are a bit on our own, I guess.

Would we then alloc struct scroll_bar in AMS? Or is it something else?

(BTW, this one got me today. I couldn't find a PVEC_SCROLL_BAR and then
this:

  #define XSCROLL_BAR(vec) ((struct scroll_bar *) XVECTOR (vec))

Nice, nice :-)



^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: MPS: scroll-bars
  2024-05-04  6:45                 ` Gerd Möllmann
@ 2024-05-04  7:05                   ` Helmut Eller
  2024-05-04  7:13                     ` Gerd Möllmann
  2024-05-04  7:09                   ` Gerd Möllmann
  1 sibling, 1 reply; 70+ messages in thread
From: Helmut Eller @ 2024-05-04  7:05 UTC (permalink / raw)
  To: Gerd Möllmann; +Cc: Po Lu, Eli Zaretskii, Emacs Devel

> Would we then alloc struct scroll_bar in AMS? Or is it something else?

Yes, that was the idea.  I hope that we can have references from blocks
in the AMC to blocks in AMS.

>
> (BTW, this one got me today. I couldn't find a PVEC_SCROLL_BAR and then
> this:
>
>   #define XSCROLL_BAR(vec) ((struct scroll_bar *) XVECTOR (vec))
>
> Nice, nice :-)

x_scroll_bar_create uses PVEC_OTHER.



^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: MPS: scroll-bars
  2024-05-04  6:45                 ` Gerd Möllmann
  2024-05-04  7:05                   ` Helmut Eller
@ 2024-05-04  7:09                   ` Gerd Möllmann
  2024-05-04  8:47                     ` Eli Zaretskii
  1 sibling, 1 reply; 70+ messages in thread
From: Gerd Möllmann @ 2024-05-04  7:09 UTC (permalink / raw)
  To: Helmut Eller; +Cc: Po Lu, Eli Zaretskii, Emacs Devel

Gerd Möllmann <gerd.moellmann@gmail.com> writes:

> Helmut Eller <eller.helmut@gmail.com> writes:
>
>> Could we perhaps use the mark-and-sweep pool for the widget-like
>> objects, like scroll_bar and window?  That would perhaps be easier,
>> because then widgets wouldn't move and tracing would be very similar to
>> what the old GC does.  And the widgets are hardly performance critical.
>
> We could try, certainly. They say
>
>   AMS is not currently suitable for production use. However, it could be
>   developed into a solid mark-and-sweep pool. If you have a use case
>   that needs this, contact us.
>
> so we are a bit on our own, I guess.
>
> Would we then alloc struct scroll_bar in AMS? Or is it something else?
>
> (BTW, this one got me today. I couldn't find a PVEC_SCROLL_BAR and then
> this:
>
>   #define XSCROLL_BAR(vec) ((struct scroll_bar *) XVECTOR (vec))
>
> Nice, nice :-)

So, maybe this is also interesting on other platforms, who knows...

struct window has members for scroll bars, e.g.

  Lisp_Object vertical_scroll_bar;

These Lisp_Objects are either fixnums or Lisp_Misc_Ptrs (see function
xmint_ptr in lisp.h). This is a C pointer, and points, on NS, to an
EmacsScroller, which is derived from some GUI widget class.
EmacsScroller then has references to window and frame.



^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: MPS: scroll-bars
  2024-05-04  7:05                   ` Helmut Eller
@ 2024-05-04  7:13                     ` Gerd Möllmann
  2024-05-04  7:48                       ` Gerd Möllmann
  0 siblings, 1 reply; 70+ messages in thread
From: Gerd Möllmann @ 2024-05-04  7:13 UTC (permalink / raw)
  To: Helmut Eller; +Cc: Po Lu, Eli Zaretskii, Emacs Devel

Helmut Eller <eller.helmut@gmail.com> writes:

>> Would we then alloc struct scroll_bar in AMS? Or is it something else?
>
> Yes, that was the idea.  I hope that we can have references from blocks
> in the AMC to blocks in AMS.
>
>>
>> (BTW, this one got me today. I couldn't find a PVEC_SCROLL_BAR and then
>> this:
>>
>>   #define XSCROLL_BAR(vec) ((struct scroll_bar *) XVECTOR (vec))
>>
>> Nice, nice :-)
>
> x_scroll_bar_create uses PVEC_OTHER.

Also nice :-)



^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: MPS: scroll-bars
  2024-05-04  7:13                     ` Gerd Möllmann
@ 2024-05-04  7:48                       ` Gerd Möllmann
  0 siblings, 0 replies; 70+ messages in thread
From: Gerd Möllmann @ 2024-05-04  7:48 UTC (permalink / raw)
  To: Helmut Eller; +Cc: Po Lu, Eli Zaretskii, Emacs Devel

AFAICT, I have scroll bars on NS handled now.

But I will deny any and all knowledge of what I did on NS in the future.




^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: MPS: scroll-bars
  2024-05-04  6:27               ` Helmut Eller
  2024-05-04  6:45                 ` Gerd Möllmann
@ 2024-05-04  8:29                 ` Po Lu
  2024-05-05  4:52                   ` Gerd Möllmann
  1 sibling, 1 reply; 70+ messages in thread
From: Po Lu @ 2024-05-04  8:29 UTC (permalink / raw)
  To: Helmut Eller; +Cc: Gerd Möllmann, Eli Zaretskii, Emacs Devel

Helmut Eller <eller.helmut@gmail.com> writes:

> xg_gtk_scroll_destroy uses id_to_widget. That's a global variable.  I'd
> rather avoid that.

xg_gtk_scroll_destroy does, but nothing forces the function that unpins
the widget to take the same approach.  The scroll bar pseudovector
structure can as easily be provided as callback data.



^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: MPS: scroll-bars
  2024-05-04  7:09                   ` Gerd Möllmann
@ 2024-05-04  8:47                     ` Eli Zaretskii
  2024-05-04  9:13                       ` Gerd Möllmann
  0 siblings, 1 reply; 70+ messages in thread
From: Eli Zaretskii @ 2024-05-04  8:47 UTC (permalink / raw)
  To: Gerd Möllmann; +Cc: eller.helmut, luangruo, emacs-devel

> From: Gerd Möllmann <gerd.moellmann@gmail.com>
> Cc: Po Lu <luangruo@yahoo.com>,  Eli Zaretskii <eliz@gnu.org>,  Emacs Devel
>  <emacs-devel@gnu.org>
> Date: Sat, 04 May 2024 09:09:00 +0200
> 
> >   #define XSCROLL_BAR(vec) ((struct scroll_bar *) XVECTOR (vec))
> >
> > Nice, nice :-)
> 
> So, maybe this is also interesting on other platforms, who knows...
> 
> struct window has members for scroll bars, e.g.
> 
>   Lisp_Object vertical_scroll_bar;
> 
> These Lisp_Objects are either fixnums or Lisp_Misc_Ptrs (see function
> xmint_ptr in lisp.h).

That's not what I see on w32.  Here's what I see:

  static void
  w32_set_vertical_scroll_bar (struct window *w,
			       int portion, int whole, int position)
  {
    Lisp_Object barobj;
    struct scroll_bar *bar;
    [...]
    /* Does the scroll bar exist yet?  */
    if (NILP (w->vertical_scroll_bar))
      {
	[...]
	bar = w32_scroll_bar_create (w, left, top, width, height, false);
      }
    [...]
    XSETVECTOR (barobj, bar);
    wset_vertical_scroll_bar (w, barobj);

And w32_scroll_bar_create does:

  static struct scroll_bar *
  w32_scroll_bar_create (struct window *w, int left, int top,
			 int width, int height, bool horizontal)
  {
    struct frame *f = XFRAME (WINDOW_FRAME (w));
    [...]
    struct scroll_bar *bar
      = ALLOCATE_PSEUDOVECTOR (struct scroll_bar, w32_widget_high, PVEC_OTHER);
    Lisp_Object barobj;

    block_input ();

    XSETWINDOW (bar->window, w);
    bar->top = top;
    bar->left = left;
    bar->width = width;
    bar->height = height;
    bar->start = 0;
    bar->end = 0;
    bar->dragging = 0;
    bar->horizontal = horizontal;

    /* Requires geometry to be set before call to create the real window */

    if (horizontal)
      hwnd = my_create_hscrollbar (f, bar);
    else
      hwnd = my_create_vscrollbar (f, bar);
    [...]
    /* Add bar to its frame's list of scroll bars.  */
    bar->next = FRAME_SCROLL_BARS (f);
    bar->prev = Qnil;
    XSETVECTOR (barobj, bar);
    fset_scroll_bars (f, barobj);
    if (! NILP (bar->next))
      XSETVECTOR (XSCROLL_BAR (bar->next)->prev, bar);

My conclusions:

  . scroll-bar Lisp object is a pseudovector
  . w->vertical_scroll_bar is set to the window's scroll-bar object
  . scroll-bar objects of a frame are stored in a doubly-linked list
    via the ->prev and ->next C pointers of 'struct scroll_bar'
  . frame's f->scroll_bars points to the last scroll-bar object
    created for the frame's windows, and thus effectively to the
    linked list of the frame's scroll bars
  . similarly, a frame has f->condemned_scroll_bars, which is a
    doubly-linked list of condemned scroll bars, the ones that could
    be deleted as result of redisplay (e.g., because their window were
    deleted)

Moreover (and this is w32-specific, I think), the Lisp thread sends a
GUI message to the UI thread with the pointer to 'struct scroll_bar',
via the call to my_create_hscrollbar:

    case WM_EMACS_CREATEVSCROLLBAR:
      return (LRESULT) w32_createvscrollbar ((struct frame *) wParam,
					     (struct scroll_bar *) lParam);

  static HWND
  my_create_vscrollbar (struct frame * f, struct scroll_bar * bar)
  {
    return (HWND) SendMessage (FRAME_W32_WINDOW (f),
			       WM_EMACS_CREATEVSCROLLBAR, (WPARAM) f,
			       (LPARAM) bar); <<<<<<<<<<<<<<<<<<<<<<<<
  }

the UI thread then uses the members of 'bar' like this:

  static HWND
  w32_createvscrollbar (struct frame *f, struct scroll_bar * bar)
  {
    HWND hwnd = CreateWindow ("SCROLLBAR", "",
			 /* Clip siblings so we don't draw over child
			    frames.  Apparently this is not always
			    sufficient so we also try to make bar windows
			    bottommost.  */
			 SBS_VERT | WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS,
			 /* Position and size of scroll bar.  */
			 bar->left, bar->top, bar->width, bar->height,
			 FRAME_W32_WINDOW (f), NULL, hinst, NULL);

So, what does this mean in the MPS build?  I guess we need to make
sure scroll bars don't move, for the reference across threads to work?

I see that allocate_pseudovector does:

  struct Lisp_Vector *
  igc_alloc_pseudovector (size_t nwords_mem, size_t nwords_lisp,
			  size_t nwords_zero, enum pvec_type tag)
  {
    struct Lisp_Vector *v
      = alloc (header_size + nwords_mem * word_size, IGC_OBJ_VECTOR, tag);
    XSETPVECTYPESIZE (v, tag, nwords_lisp, nwords_mem - nwords_lisp);
    maybe_finalize (v, tag);
    return v;
  }

But still for the life of me I don't really understand what that means
for us in this case.  What does it mean for the references to its C
'struct scroll_bar' when the scroll-bar object is moved?  If any of
these references are on some thread's stack, does it mean the object
will not move?  And what about those prev and next pointers in frame's
scroll_bars lists -- do we need to do anything with them?  Likewise
with the window's vertical_scroll_bar pointers.



^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: MPS: scroll-bars
  2024-05-04  8:47                     ` Eli Zaretskii
@ 2024-05-04  9:13                       ` Gerd Möllmann
  2024-05-04  9:29                         ` Eli Zaretskii
  0 siblings, 1 reply; 70+ messages in thread
From: Gerd Möllmann @ 2024-05-04  9:13 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: eller.helmut, luangruo, emacs-devel

Eli Zaretskii <eliz@gnu.org> writes:

> My conclusions:
>
>   . scroll-bar Lisp object is a pseudovector
>   . w->vertical_scroll_bar is set to the window's scroll-bar object
>   . scroll-bar objects of a frame are stored in a doubly-linked list
>     via the ->prev and ->next C pointers of 'struct scroll_bar'
>   . frame's f->scroll_bars points to the last scroll-bar object
>     created for the frame's windows, and thus effectively to the
>     linked list of the frame's scroll bars
>   . similarly, a frame has f->condemned_scroll_bars, which is a
>     doubly-linked list of condemned scroll bars, the ones that could
>     be deleted as result of redisplay (e.g., because their window were
>     deleted)

  /* List of scroll bars on this frame.
     Actually, we don't specify exactly what is stored here at all; the
     scroll bar implementation code can use it to store anything it likes.
     This field is marked by the garbage collector.  It is here
     instead of in the `device' structure so that the garbage
     collector doesn't need to look inside the window-system-dependent
     structure.  */
  Lisp_Object scroll_bars;
  Lisp_Object condemned_scroll_bars;

Oh shit :-(. I need a break.

> Moreover (and this is w32-specific, I think), the Lisp thread sends a
> GUI message to the UI thread with the pointer to 'struct scroll_bar',
> via the call to my_create_hscrollbar:
>
>     case WM_EMACS_CREATEVSCROLLBAR:
>       return (LRESULT) w32_createvscrollbar ((struct frame *) wParam,
> 					     (struct scroll_bar *) lParam);
>
>   static HWND
>   my_create_vscrollbar (struct frame * f, struct scroll_bar * bar)
>   {
>     return (HWND) SendMessage (FRAME_W32_WINDOW (f),
> 			       WM_EMACS_CREATEVSCROLLBAR, (WPARAM) f,
> 			       (LPARAM) bar); <<<<<<<<<<<<<<<<<<<<<<<<
>   }
>
> the UI thread then uses the members of 'bar' like this:
>
>   static HWND
>   w32_createvscrollbar (struct frame *f, struct scroll_bar * bar)
>   {
>     HWND hwnd = CreateWindow ("SCROLLBAR", "",
> 			 /* Clip siblings so we don't draw over child
> 			    frames.  Apparently this is not always
> 			    sufficient so we also try to make bar windows
> 			    bottommost.  */
> 			 SBS_VERT | WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS,
> 			 /* Position and size of scroll bar.  */
> 			 bar->left, bar->top, bar->width, bar->height,
> 			 FRAME_W32_WINDOW (f), NULL, hinst, NULL);
>
> So, what does this mean in the MPS build?  I guess we need to make
> sure scroll bars don't move, for the reference across threads to work?

That would be my guess as well.

> I see that allocate_pseudovector does:
>
>   struct Lisp_Vector *
>   igc_alloc_pseudovector (size_t nwords_mem, size_t nwords_lisp,
> 			  size_t nwords_zero, enum pvec_type tag)
>   {
>     struct Lisp_Vector *v
>       = alloc (header_size + nwords_mem * word_size, IGC_OBJ_VECTOR, tag);
>     XSETPVECTYPESIZE (v, tag, nwords_lisp, nwords_mem - nwords_lisp);
>     maybe_finalize (v, tag);
>     return v;
>   }
>
> But still for the life of me I don't really understand what that means
> for us in this case.  What does it mean for the references to its C
> 'struct scroll_bar' when the scroll-bar object is moved?  If any of
> these references are on some thread's stack, does it mean the object
> will not move?  And what about those prev and next pointers in frame's
> scroll_bars lists -- do we need to do anything with them?  Likewise
> with the window's vertical_scroll_bar pointers.

I assume that the GUI thread you mention is not one the Emacs threads,
but something else, so it's not main_thread and not one of the threads
made with make-thread.

Then I think we first of all must make sure that MPS knows about that
thread. The existing threads are added with thread_add

  static struct igc_thread_list *
  thread_add (struct thread_state *ts)
  {
    mps_thr_t thr;
    mps_res_t res = mps_thread_reg (&thr, global_igc->arena);
    IGC_CHECK_RES (res);
    struct igc_thread_list *t = register_thread (global_igc, thr, ts);

  That's the root for the control stack of the thread:

    root_create_thread (t);

  These are allocation points in case the thread allocates from MPS:

    create_thread_aps (&t->d);
    return t;
  }

Maybe we should start with this, and move forward when we have it.



^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: MPS: scroll-bars
  2024-05-04  9:13                       ` Gerd Möllmann
@ 2024-05-04  9:29                         ` Eli Zaretskii
  2024-05-04 10:04                           ` Gerd Möllmann
  0 siblings, 1 reply; 70+ messages in thread
From: Eli Zaretskii @ 2024-05-04  9:29 UTC (permalink / raw)
  To: Gerd Möllmann; +Cc: eller.helmut, luangruo, emacs-devel

> From: Gerd Möllmann <gerd.moellmann@gmail.com>
> Cc: eller.helmut@gmail.com,  luangruo@yahoo.com,  emacs-devel@gnu.org
> Date: Sat, 04 May 2024 11:13:40 +0200
> 
> > So, what does this mean in the MPS build?  I guess we need to make
> > sure scroll bars don't move, for the reference across threads to work?
> 
> That would be my guess as well.

How to go about that?

> > I see that allocate_pseudovector does:
> >
> >   struct Lisp_Vector *
> >   igc_alloc_pseudovector (size_t nwords_mem, size_t nwords_lisp,
> > 			  size_t nwords_zero, enum pvec_type tag)
> >   {
> >     struct Lisp_Vector *v
> >       = alloc (header_size + nwords_mem * word_size, IGC_OBJ_VECTOR, tag);
> >     XSETPVECTYPESIZE (v, tag, nwords_lisp, nwords_mem - nwords_lisp);
> >     maybe_finalize (v, tag);
> >     return v;
> >   }
> >
> > But still for the life of me I don't really understand what that means
> > for us in this case.  What does it mean for the references to its C
> > 'struct scroll_bar' when the scroll-bar object is moved?  If any of
> > these references are on some thread's stack, does it mean the object
> > will not move?  And what about those prev and next pointers in frame's
> > scroll_bars lists -- do we need to do anything with them?  Likewise
> > with the window's vertical_scroll_bar pointers.
> 
> I assume that the GUI thread you mention is not one the Emacs threads,
> but something else, so it's not main_thread and not one of the threads
> made with make-thread.

It isn't a Lisp thread, that's true.  But it's an "Emacs thread" in
the sense that in the w32 build it is an integral part of Emacs, and
without it the GUI features and GUI I/O would not work on MS-Windows.

(You can find the overview of the thread structure of the w32 build in
a large comment that starts at line 3365 of w32fns.c.)

> Then I think we first of all must make sure that MPS knows about that
> thread.

Why do we need MPS to know about that thread (or any other non-Lisp
thread used by Emacs on MS-Windows; there are more)?  is that for MPS
to scan their C stacks and registers?

> The existing threads are added with thread_add
> 
>   static struct igc_thread_list *
>   thread_add (struct thread_state *ts)
>   {
>     mps_thr_t thr;
>     mps_res_t res = mps_thread_reg (&thr, global_igc->arena);
>     IGC_CHECK_RES (res);
>     struct igc_thread_list *t = register_thread (global_igc, thr, ts);
> 
>   That's the root for the control stack of the thread:
> 
>     root_create_thread (t);
> 
>   These are allocation points in case the thread allocates from MPS:
> 
>     create_thread_aps (&t->d);
>     return t;
>   }
> 
> Maybe we should start with this, and move forward when we have it.

I'd first like to understand the need and the purpose of registering
non-Lisp threads with MPS.



^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: MPS: scroll-bars
  2024-05-04  9:29                         ` Eli Zaretskii
@ 2024-05-04 10:04                           ` Gerd Möllmann
  2024-05-04 13:59                             ` MPS: w32 threads Eli Zaretskii
  0 siblings, 1 reply; 70+ messages in thread
From: Gerd Möllmann @ 2024-05-04 10:04 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: eller.helmut, luangruo, emacs-devel

Eli Zaretskii <eliz@gnu.org> writes:

> How to go about that?

Please let's first do the thread stuff. That makes things easier for the
old man here.


>> I assume that the GUI thread you mention is not one the Emacs threads,
>> but something else, so it's not main_thread and not one of the threads
>> made with make-thread.
>
> It isn't a Lisp thread, that's true.  But it's an "Emacs thread" in
> the sense that in the w32 build it is an integral part of Emacs, and
> without it the GUI features and GUI I/O would not work on MS-Windows.

Does it have a struct thread_state associated with it? That's what
igc.c currently knows how to handle.

>
> (You can find the overview of the thread structure of the w32 build in
> a large comment that starts at line 3365 of w32fns.c.)
>
>> Then I think we first of all must make sure that MPS knows about that
>> thread.
>
> Why do we need MPS to know about that thread (or any other non-Lisp
> thread used by Emacs on MS-Windows; there are more)?  is that for MPS
> to scan their C stacks and registers?

9.2. Thread registration

In order to scan a thread’s registers for references (which happens at
each flip), the MPS needs to be able to suspend that thread, and in
order to gain exclusive atomic access to memory in order to scan it, the
MPS needs to be able to suspend all threads that might access that
memory. This means that threads must be registered with the MPS by
calling mps_thread_reg() (and thread roots created; see Thread roots).

A thread must be registered with an arena if:

its control stack and registers form a root (this is enforced by
mps_root_create_thread()); or it reads or writes from a location in an
automatically managed pool in the arena. However, some automatically
managed pool classes may be more liberal than this. See the
documentation for the pool class.





^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: MPS: w32 threads
  2024-05-04 10:04                           ` Gerd Möllmann
@ 2024-05-04 13:59                             ` Eli Zaretskii
  2024-05-04 14:20                               ` Gerd Möllmann
  0 siblings, 1 reply; 70+ messages in thread
From: Eli Zaretskii @ 2024-05-04 13:59 UTC (permalink / raw)
  To: Gerd Möllmann; +Cc: eller.helmut, luangruo, emacs-devel

> From: Gerd Möllmann <gerd.moellmann@gmail.com>
> Cc: eller.helmut@gmail.com,  luangruo@yahoo.com,  emacs-devel@gnu.org
> Date: Sat, 04 May 2024 12:04:50 +0200
> 
> Eli Zaretskii <eliz@gnu.org> writes:
> 
> > How to go about that?
> 
> Please let's first do the thread stuff. That makes things easier for the
> old man here.

OK.  I've started a new thread (pun intended) for this branch of the
discussion.

> >> I assume that the GUI thread you mention is not one the Emacs threads,
> >> but something else, so it's not main_thread and not one of the threads
> >> made with make-thread.
> >
> > It isn't a Lisp thread, that's true.  But it's an "Emacs thread" in
> > the sense that in the w32 build it is an integral part of Emacs, and
> > without it the GUI features and GUI I/O would not work on MS-Windows.
> 
> Does it have a struct thread_state associated with it? That's what
> igc.c currently knows how to handle.

No.  Only Lisp threads started with make-thread have thread_state.

> A thread must be registered with an arena if:
> 
> its control stack and registers form a root (this is enforced by
> mps_root_create_thread()); or it reads or writes from a location in an
> automatically managed pool in the arena. However, some automatically
> managed pool classes may be more liberal than this. See the
> documentation for the pool class.

Can you try translating this to Emacs-related terms, please?  What
activities in the thread should require the thread to be "registered
with an arena"?

Emacs on Windows starts separate threads for the following jobs:

  . processing Windows GUI-related messages
  . reading from sub-processes (part of pselect emulation)
  . emulation of itimers (for atimers and for M-x profiler)
  . file-change notifications

I need to understand what traits of a thread make it need to be
registered with MPS.  Each of the above will then need a separate
audit, I think.



^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: MPS: w32 threads
  2024-05-04 13:59                             ` MPS: w32 threads Eli Zaretskii
@ 2024-05-04 14:20                               ` Gerd Möllmann
  2024-05-05  8:27                                 ` Eli Zaretskii
  0 siblings, 1 reply; 70+ messages in thread
From: Gerd Möllmann @ 2024-05-04 14:20 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: eller.helmut, luangruo, emacs-devel

Eli Zaretskii <eliz@gnu.org> writes:

> No.  Only Lisp threads started with make-thread have thread_state.

OK.

(Plus main_thread, which is a thread_state in the data segment (!) for
the main thread. Just in case someone wonders why main_thread is a
root.)

>> A thread must be registered with an arena if:
>> 
>> its control stack and registers form a root (this is enforced by
>> mps_root_create_thread()); or it reads or writes from a location in an
>> automatically managed pool in the arena. However, some automatically
>> managed pool classes may be more liberal than this. See the
>> documentation for the pool class.
>
> Can you try translating this to Emacs-related terms, please?  What
> activities in the thread should require the thread to be "registered
> with an arena"?

It basically says that if a thread can have Lisp_Objects or pointers to
them on its control stack, register it with MPS.

An arena is basically an implementation of some low-level aspects of
memory managemnt in MPS. We have only one MPS arena, and it is one using
VM functions (mmap, ...).

The hint that some pool classes don't require this or that we can
ignore. AKAIK the mostly-copying pools we use require it.

> Emacs on Windows starts separate threads for the following jobs:
>
>   . processing Windows GUI-related messages
>   . reading from sub-processes (part of pselect emulation)
>   . emulation of itimers (for atimers and for M-x profiler)
>   . file-change notifications
>
> I need to understand what traits of a thread make it need to be
> registered with MPS.  Each of the above will then need a separate
> audit, I think.

Using any Lisp_Objects (or other objects allocated from MPS) -> register
it. AFAIU, the GUI thread gets such an objects posted in a message, so
that one must be registered.

The others are hard to say for me. It would not do harm to register
them, but might mean addtional work for nothing.



^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: MPS image cache
  2024-05-03 15:02     ` Helmut Eller
@ 2024-05-04 17:51       ` Gerd Möllmann
  0 siblings, 0 replies; 70+ messages in thread
From: Gerd Möllmann @ 2024-05-04 17:51 UTC (permalink / raw)
  To: Helmut Eller; +Cc: Eli Zaretskii, Emacs Devel

Helmut Eller <eller.helmut@gmail.com> writes:

>>> There is a bit of an issue with proper initialization of the structs
>>> pointed to by those roots.  E.g. x_term_init uses xzalloc, puts pointers
>>> into the struct, and only then stores the pointer to the struct in
>>> x_display_list.  So what should be the root, the struct (registred
>>> immediately after the call to xzalloc) or the global variable
>>> x_display_list?
>>
>> Hm.
>
> For my case, the troublesome field was xi_device_t.name.  I decided to
> make x_display_info and xi_device_t amigous roots, because there is
> usually only one x_display_info and dozen of xi_device_t.

Pushed. Sorry for the delay I somehow overlooked your patch.

(And the amigos are the reason I write "ambig" :-).)



^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: MPS: scroll-bars
  2024-05-04  8:29                 ` MPS: scroll-bars Po Lu
@ 2024-05-05  4:52                   ` Gerd Möllmann
  2024-05-05  7:53                     ` Helmut Eller
  0 siblings, 1 reply; 70+ messages in thread
From: Gerd Möllmann @ 2024-05-05  4:52 UTC (permalink / raw)
  To: Po Lu; +Cc: Helmut Eller, Eli Zaretskii, Emacs Devel

I believe the frame::condemned_scroll_bars is okay on NS as it is now.
With all caveats as usual.




^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: MPS image cache
  2024-05-03 15:11       ` Gerd Möllmann
@ 2024-05-05  6:45         ` Gerd Möllmann
  2024-05-05  7:02           ` Gerd Möllmann
  2024-05-05  8:16           ` Helmut Eller
  0 siblings, 2 replies; 70+ messages in thread
From: Gerd Möllmann @ 2024-05-05  6:45 UTC (permalink / raw)
  To: Helmut Eller; +Cc: Eli Zaretskii, Emacs Devel

Gerd Möllmann <gerd.moellmann@gmail.com> writes:

> Helmut Eller <eller.helmut@gmail.com> writes:
>
>> On Fri, May 03 2024, Gerd Möllmann wrote:
>>> While we scan an object, MPS gives us exclusive access to it. I think we
>>> want that for these caches, so that scanning does not interfere iwth the
>>> client modifying the cache?
>>
>> Access is exclusive to the image_cache struct, but not the buckets, I
>> think.
>
> Right. Hm.

I'm plannign to do the following if nobody stops me:

Both face an image cache are hash tables containing 2 arrays of pointers
to MPS objects (face, image).

I want to introduce a new MPS object type representing such an array of
pointers, IGC_OBJ_PTR_VEC. The igc_header gives us the size of the
array, and being an MPS object, we get exclusive access to its contents.

WDYT



^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: MPS image cache
  2024-05-05  6:45         ` Gerd Möllmann
@ 2024-05-05  7:02           ` Gerd Möllmann
  2024-05-05  9:00             ` Eli Zaretskii
  2024-05-05  8:16           ` Helmut Eller
  1 sibling, 1 reply; 70+ messages in thread
From: Gerd Möllmann @ 2024-05-05  7:02 UTC (permalink / raw)
  To: Helmut Eller; +Cc: Eli Zaretskii, Emacs Devel

Gerd Möllmann <gerd.moellmann@gmail.com> writes:

> Gerd Möllmann <gerd.moellmann@gmail.com> writes:
>
>> Helmut Eller <eller.helmut@gmail.com> writes:
>>
>>> On Fri, May 03 2024, Gerd Möllmann wrote:
>>>> While we scan an object, MPS gives us exclusive access to it. I think we
>>>> want that for these caches, so that scanning does not interfere iwth the
>>>> client modifying the cache?
>>>
>>> Access is exclusive to the image_cache struct, but not the buckets, I
>>> think.
>>
>> Right. Hm.
>
> I'm plannign to do the following if nobody stops me:
>
> Both face an image cache are hash tables containing 2 arrays of pointers
> to MPS objects (face, image).
>
> I want to introduce a new MPS object type representing such an array of
> pointers, IGC_OBJ_PTR_VEC. The igc_header gives us the size of the
> array, and being an MPS object, we get exclusive access to its contents.
>
> WDYT

Pushed that, but not yet using it. We can always remove that later...



^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: MPS: scroll-bars
  2024-05-05  4:52                   ` Gerd Möllmann
@ 2024-05-05  7:53                     ` Helmut Eller
  2024-05-05  8:01                       ` Gerd Möllmann
  2024-05-05 16:43                       ` Eli Zaretskii
  0 siblings, 2 replies; 70+ messages in thread
From: Helmut Eller @ 2024-05-05  7:53 UTC (permalink / raw)
  To: Gerd Möllmann; +Cc: Po Lu, Eli Zaretskii, Emacs Devel

[-- Attachment #1: Type: text/plain, Size: 729 bytes --]

On Sun, May 05 2024, Gerd Möllmann wrote:

> I believe the frame::condemned_scroll_bars is okay on NS as it is now.
> With all caveats as usual.

I have a hunch that those would need weak references to work as
intended.  But I'm happy to let them leak for now.

Below is my patch for the scroll-bars.  I went for the indirection layer
solution.  Though, the mark-and-sweep pool idea might be more broadly
usable; with so many different GUI toolkits it's hard to say.

I also had a problem with the tool-bar, triggered by this test:
(dotimes (i 40)
  (igc--collect)
  (message "%S" (make-list i nil))
  (redisplay))

The third patch stops allocating glyph matrices as ambiguous roots.
Seems to work for me.


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: 0001-Fix-scroll-bars-for-GTK.patch --]
[-- Type: text/x-diff, Size: 5363 bytes --]

From 0e0cc32798f6dc8947e411d0e58ae4b8ea2aaced Mon Sep 17 00:00:00 2001
From: Helmut Eller <eller.helmut@gmail.com>
Date: Sun, 5 May 2024 06:36:24 +0200
Subject: [PATCH] Fix scroll bars for GTK

Use a layer of indirection when struct scroll_bar pointers are
used in GTK callbacks.

* src/gtkutil.c (xg_finish_scroll_bar_creation): Create a cell
with a pointer to the scroll_bar and pass it to callbacks.  Also
Register a "destroy" callback to free it.
(xg_gtk_scroll_free_scroll_bar_cell): New.

* src/xterm.c (xg_scroll_callback, xg_end_scroll_callback): Load
the scroll_bar* out the cell.
(syms_of_xterm): Staticpro window_being_scrolled.
(x_unprotect_window_for_callback): Clear unused
elements in the protected_windows array to allow windows to be
collected.
(x_cache_xi_devices, xi_disable_devices, x_term_init): Add FIXMEs.
---
 src/gtkutil.c | 37 +++++++++++++++++++++++++++++++++++--
 src/xterm.c   | 21 +++++++++++++++++++++
 2 files changed, 56 insertions(+), 2 deletions(-)

diff --git a/src/gtkutil.c b/src/gtkutil.c
index a01b8a41d5d..342dd35da13 100644
--- a/src/gtkutil.c
+++ b/src/gtkutil.c
@@ -44,6 +44,9 @@ #define xp pgtk
 #include "termhooks.h"
 #include "keyboard.h"
 #include "coding.h"
+#ifdef HAVE_MPS
+#include "igc.h"
+#endif
 
 #include <gdk/gdkkeysyms.h>
 
@@ -4523,6 +4526,13 @@ xg_scroll_bar_size_allocate_cb (GtkWidget *widget,
 }
 #endif
 
+static void
+xg_gtk_scroll_free_scroll_bar_cell (GtkWidget *widget, gpointer data)
+{
+  struct scroll_bar **bar_cell = data;
+  igc_xfree (bar_cell);
+}
+
 static void
 xg_finish_scroll_bar_creation (struct frame *f,
                                GtkWidget *wscroll,
@@ -4558,14 +4568,37 @@ xg_finish_scroll_bar_creation (struct frame *f,
                     (gpointer) scroll_id);
 #endif
 
+#ifdef HAVE_MPS
+  // FIXME: can use exact reference
+  struct scroll_bar **bar_cell =
+    igc_xzalloc_ambig (sizeof (struct scroll_bar*));
+  bar_cell[0] = bar;
+#endif
   g_signal_connect (G_OBJECT (wscroll),
                     "change-value",
                     scroll_callback,
-                    (gpointer) bar);
+#ifdef HAVE_MPS
+                    (gpointer) bar_cell
+#else
+		    (gpointer) bar
+#endif
+		    );
   g_signal_connect (G_OBJECT (wscroll),
                     "button-release-event",
                     end_callback,
-                    (gpointer) bar);
+#ifdef HAVE_MPS
+                    (gpointer) bar_cell
+#else
+		    (gpointer) bar
+#endif
+		    );
+
+#ifdef HAVE_MPS
+    g_signal_connect (G_OBJECT (wscroll),
+		      "destroy",
+		      G_CALLBACK (xg_gtk_scroll_free_scroll_bar_cell),
+		      (gpointer) bar_cell);
+#endif
 
   /* The scroll bar widget does not draw on a window of its own.  Instead
      it draws on the parent window, in this case the edit widget.  So
diff --git a/src/xterm.c b/src/xterm.c
index c47c7b0534d..7acd7f9c2a5 100644
--- a/src/xterm.c
+++ b/src/xterm.c
@@ -5748,6 +5748,7 @@ x_cache_xi_devices (struct x_display_info *dpyinfo)
     }
 
 #ifdef HAVE_MPS
+  // FIXME: use exact references
   dpyinfo->devices = igc_xzalloc_ambig (sizeof *dpyinfo->devices * ndevices);
 #else
   dpyinfo->devices = xzalloc (sizeof *dpyinfo->devices * ndevices);
@@ -13782,6 +13783,7 @@ xi_disable_devices (struct x_display_info *dpyinfo,
 
   ndevices = 0;
 #ifdef HAVE_MPS
+  // FIXME: use exact references
   devices = igc_xzalloc_ambig (sizeof *devices * dpyinfo->num_devices);
 #else
   devices = xzalloc (sizeof *devices * dpyinfo->num_devices);
@@ -15480,6 +15482,10 @@ x_unprotect_window_for_callback (struct x_display_info *dpyinfo)
     memmove (dpyinfo->protected_windows, &dpyinfo->protected_windows[1],
 	     sizeof (Lisp_Object) * dpyinfo->n_protected_windows);
 
+#ifdef HAVE_MPS
+  dpyinfo->protected_windows[dpyinfo->n_protected_windows] = Qnil;
+#endif
+
   return window;
 }
 
@@ -15718,7 +15724,12 @@ xg_scroll_callback (GtkRange *range, GtkScrollType scroll,
 
   whole = 0;
   portion = 0;
+#ifdef HAVE_MPS
+  struct scroll_bar** bar_cell = user_data;
+  bar = *bar_cell;
+#else
   bar = user_data;
+#endif
   part = scroll_bar_nowhere;
   adj = GTK_ADJUSTMENT (gtk_range_get_adjustment (range));
   f = g_object_get_data (G_OBJECT (range), XG_FRAME_DATA);
@@ -15795,9 +15806,14 @@ xg_end_scroll_callback (GtkWidget *widget,
                         GdkEventButton *event,
                         gpointer user_data)
 {
+#ifdef HAVE_MPS
+  struct scroll_bar **bar_cell = user_data;
+  struct scroll_bar *bar = *bar_cell;
+#else
   struct scroll_bar *bar;
 
   bar = user_data;
+#endif
   bar->dragging = -1;
 
   if (WINDOWP (window_being_scrolled))
@@ -16936,6 +16952,7 @@ XTset_vertical_scroll_bar (struct window *w, int portion, int whole, int positio
 	 Redraw the scroll bar manually.  */
       x_scroll_bar_redraw (bar);
 #endif
+
     }
   else
     {
@@ -30693,6 +30710,7 @@ #define NUM_ARGV 10
   /* We have definitely succeeded.  Record the new connection.  */
 
 #ifdef HAVE_MPS
+  // FIXME: use exact references
   dpyinfo = igc_xzalloc_ambig (sizeof *dpyinfo);
 #else
   dpyinfo = xzalloc (sizeof *dpyinfo);
@@ -32498,6 +32516,9 @@ syms_of_xterm (void)
   x_dnd_unsupported_drop_data = Qnil;
   staticpro (&x_dnd_unsupported_drop_data);
 
+  window_being_scrolled = Qnil;
+  staticpro (&window_being_scrolled);
+
   /* Used by x_cr_export_frames.  */
   DEFSYM (Qconcat, "concat");
 
-- 
2.39.2


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #3: 0001-Make-xg_frame_tb_info-an-ambiguous-root.patch --]
[-- Type: text/x-diff, Size: 1357 bytes --]

From fd98e52e0efdb5e7bbf37919e3e95f8e440313b0 Mon Sep 17 00:00:00 2001
From: Helmut Eller <eller.helmut@gmail.com>
Date: Sun, 5 May 2024 09:01:06 +0200
Subject: [PATCH] Make xg_frame_tb_info an ambiguous root

We could use exact references in the future.

* src/gtkutil.c (xg_create_tool_bar): Use igc_xzalloc_ambig for
allocation.
(free_frame_tool_bar): Use igc_xfree to free it.
---
 src/gtkutil.c | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/src/gtkutil.c b/src/gtkutil.c
index 342dd35da13..31e0b915000 100644
--- a/src/gtkutil.c
+++ b/src/gtkutil.c
@@ -5496,7 +5496,12 @@ xg_create_tool_bar (struct frame *f)
                          TB_INFO_KEY);
   if (! tbinfo)
     {
+#ifdef HAVE_MPS
+      // FIXME: use exact references
+      tbinfo = igc_xzalloc_ambig (sizeof (*tbinfo));
+#else
       tbinfo = xmalloc (sizeof (*tbinfo));
+#endif
       tbinfo->last_tool_bar = Qnil;
       tbinfo->style = Qnil;
       tbinfo->hmargin = tbinfo->vmargin = 0;
@@ -6162,7 +6167,11 @@ free_frame_tool_bar (struct frame *f)
                                   TB_INFO_KEY);
       if (tbinfo)
         {
+#ifdef HAVE_MPS
+	  igc_xfree (tbinfo);
+#else
           xfree (tbinfo);
+#endif
           g_object_set_data (G_OBJECT (FRAME_GTK_OUTER_WIDGET (f)),
                              TB_INFO_KEY,
                              NULL);
-- 
2.39.2


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #4: 0001-Glyph-matrices-don-t-need-to-be-ambiguous-roots.patch --]
[-- Type: text/x-diff, Size: 3120 bytes --]

From 3d3187e5c55a770cd68b1144479a70032b3c3558 Mon Sep 17 00:00:00 2001
From: Helmut Eller <eller.helmut@gmail.com>
Date: Sun, 5 May 2024 09:38:48 +0200
Subject: [PATCH] Glyph matrices don't need to be ambiguous roots

We scan them with fix_glyph_matrix as part of fix_windows.  So avoid
scanning them twice.  save_current_matrix and
restore_current_matrix create temporary matrices that aren't
seen by fix_glyph_matrix; these are still ambiguous roots.

* src/dispnew.c (adjust_glyph_matrix, realloc_glyph_pool)
(free_glyph_matrix): Use plain malloc instead of igc_xzalloc_ambig.
(restore_current_matrix): Use igc_free where needed.
---
 src/dispnew.c | 22 ++--------------------
 1 file changed, 2 insertions(+), 20 deletions(-)

diff --git a/src/dispnew.c b/src/dispnew.c
index 7bb78c3b214..4d7586bdc1e 100644
--- a/src/dispnew.c
+++ b/src/dispnew.c
@@ -304,11 +304,7 @@ free_glyph_matrix (struct glyph_matrix *matrix)
       /* Free glyph memory if MATRIX owns it.  */
       if (matrix->pool == NULL)
 	for (i = 0; i < matrix->rows_allocated; ++i)
-#ifdef HAVE_MPS
-	  igc_xfree (matrix->rows[i].glyphs[LEFT_MARGIN_AREA]);
-#else
 	  xfree (matrix->rows[i].glyphs[LEFT_MARGIN_AREA]);
-#endif
       /* Free row structures and the matrix itself.  */
       xfree (matrix->rows);
       xfree (matrix);
@@ -512,13 +508,8 @@ adjust_glyph_matrix (struct window *w, struct glyph_matrix *matrix, int x, int y
 	  while (row < end)
 	    {
 	      row->glyphs[LEFT_MARGIN_AREA] =
-#ifdef HAVE_MPS
-		igc_xnrealloc_ambig (row->glyphs[LEFT_MARGIN_AREA],
-			       dim.width, sizeof (struct glyph));
-#else
 		xnrealloc (row->glyphs[LEFT_MARGIN_AREA],
 			   dim.width, sizeof (struct glyph));
-#endif
 	      /* The mode line, if displayed, never has marginal areas.  */
 	      if ((row == matrix->rows + dim.height - 1
 		   && !(w && window_wants_mode_line (w)))
@@ -1374,11 +1365,7 @@ free_glyph_pool (struct glyph_pool *pool)
       --glyph_pool_count;
       eassert (glyph_pool_count >= 0);
 #endif
-#ifdef HAVE_MPS
-      igc_xfree (pool->glyphs);
-#else
       xfree (pool->glyphs);
-#endif
       xfree (pool);
     }
 }
@@ -1409,15 +1396,9 @@ realloc_glyph_pool (struct glyph_pool *pool, struct dim matrix_dim)
   if (needed > pool->nglyphs)
     {
       ptrdiff_t old_nglyphs = pool->nglyphs;
-#ifdef HAVE_MPS
-      pool->glyphs
-	= igc_xpalloc_ambig (pool->glyphs, &pool->nglyphs, needed - old_nglyphs,
-		       -1, sizeof *pool->glyphs);
-#else
       pool->glyphs
 	= xpalloc (pool->glyphs, &pool->nglyphs, needed - old_nglyphs,
 		   -1, sizeof *pool->glyphs);
-#endif
 
       memclear (pool->glyphs + old_nglyphs,
 		(pool->nglyphs - old_nglyphs) * sizeof *pool->glyphs);
@@ -2055,8 +2036,9 @@ restore_current_matrix (struct frame *f, struct glyph_matrix *saved)
 	  memcpy (to->glyphs[RIGHT_MARGIN_AREA],
 		  from->glyphs[RIGHT_MARGIN_AREA], nbytes);
 	  to->used[RIGHT_MARGIN_AREA] = from->used[RIGHT_MARGIN_AREA];
+
 #ifdef HAVE_MPS
-	  xfree (from->glyphs[RIGHT_MARGIN_AREA]);
+	  igc_xfree (from->glyphs[RIGHT_MARGIN_AREA]);
 #else
 	  xfree (from->glyphs[RIGHT_MARGIN_AREA]);
 #endif
-- 
2.39.2


^ permalink raw reply related	[flat|nested] 70+ messages in thread

* Re: MPS: scroll-bars
  2024-05-05  7:53                     ` Helmut Eller
@ 2024-05-05  8:01                       ` Gerd Möllmann
  2024-05-05  8:08                         ` Helmut Eller
  2024-05-05 16:43                       ` Eli Zaretskii
  1 sibling, 1 reply; 70+ messages in thread
From: Gerd Möllmann @ 2024-05-05  8:01 UTC (permalink / raw)
  To: Helmut Eller; +Cc: Po Lu, Eli Zaretskii, Emacs Devel

Helmut Eller <eller.helmut@gmail.com> writes:

> On Sun, May 05 2024, Gerd Möllmann wrote:
>
>> I believe the frame::condemned_scroll_bars is okay on NS as it is now.
>> With all caveats as usual.
>
> I have a hunch that those would need weak references to work as
> intended.  But I'm happy to let them leak for now.
>
> Below is my patch for the scroll-bars.  I went for the indirection layer
> solution.  Though, the mark-and-sweep pool idea might be more broadly
> usable; with so many different GUI toolkits it's hard to say.
>
> I also had a problem with the tool-bar, triggered by this test:
> (dotimes (i 40)
>   (igc--collect)
>   (message "%S" (make-list i nil))
>   (redisplay))
>
> The third patch stops allocating glyph matrices as ambiguous roots.
> Seems to work for me.

Very cool!

I don't use tool bars with my init, so I've evaded that one :-).

And pushed. (I hope I haven't overlooked other patches you sent, like
yesterday?)



^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: MPS: scroll-bars
  2024-05-05  8:01                       ` Gerd Möllmann
@ 2024-05-05  8:08                         ` Helmut Eller
  0 siblings, 0 replies; 70+ messages in thread
From: Helmut Eller @ 2024-05-05  8:08 UTC (permalink / raw)
  To: Gerd Möllmann; +Cc: Po Lu, Eli Zaretskii, Emacs Devel

On Sun, May 05 2024, Gerd Möllmann wrote:

> And pushed.

Thanks!

> (I hope I haven't overlooked other patches you sent, like
> yesterday?)

No, you haven't; they're all there.



^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: MPS image cache
  2024-05-05  6:45         ` Gerd Möllmann
  2024-05-05  7:02           ` Gerd Möllmann
@ 2024-05-05  8:16           ` Helmut Eller
  2024-05-05  8:42             ` Gerd Möllmann
  1 sibling, 1 reply; 70+ messages in thread
From: Helmut Eller @ 2024-05-05  8:16 UTC (permalink / raw)
  To: Gerd Möllmann; +Cc: Eli Zaretskii, Emacs Devel

On Sun, May 05 2024, Gerd Möllmann wrote:

> I'm plannign to do the following if nobody stops me:
>
> Both face an image cache are hash tables containing 2 arrays of pointers
> to MPS objects (face, image).
>
> I want to introduce a new MPS object type representing such an array of
> pointers, IGC_OBJ_PTR_VEC. The igc_header gives us the size of the
> array, and being an MPS object, we get exclusive access to its contents.
>
> WDYT

Would something like this also be needed for glyph matrices?  Or in
general, can we scan anything other than the block that dflt_scan was
called with?  Is these related to "remote references" in the MPS manual,
which I don't quite understand what they mean.



^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: MPS: w32 threads
  2024-05-04 14:20                               ` Gerd Möllmann
@ 2024-05-05  8:27                                 ` Eli Zaretskii
  2024-05-05  9:16                                   ` Gerd Möllmann
  0 siblings, 1 reply; 70+ messages in thread
From: Eli Zaretskii @ 2024-05-05  8:27 UTC (permalink / raw)
  To: Gerd Möllmann; +Cc: eller.helmut, emacs-devel

> From: Gerd Möllmann <gerd.moellmann@gmail.com>
> Cc: eller.helmut@gmail.com,  luangruo@yahoo.com,  emacs-devel@gnu.org
> Date: Sat, 04 May 2024 16:20:19 +0200
> 
> >> A thread must be registered with an arena if:
> >> 
> >> its control stack and registers form a root (this is enforced by
> >> mps_root_create_thread()); or it reads or writes from a location in an
> >> automatically managed pool in the arena. However, some automatically
> >> managed pool classes may be more liberal than this. See the
> >> documentation for the pool class.
> >
> > Can you try translating this to Emacs-related terms, please?  What
> > activities in the thread should require the thread to be "registered
> > with an arena"?
> 
> It basically says that if a thread can have Lisp_Objects or pointers to
> them on its control stack, register it with MPS.
> 
> An arena is basically an implementation of some low-level aspects of
> memory managemnt in MPS. We have only one MPS arena, and it is one using
> VM functions (mmap, ...).
> 
> The hint that some pool classes don't require this or that we can
> ignore. AKAIK the mostly-copying pools we use require it.
> 
> > Emacs on Windows starts separate threads for the following jobs:
> >
> >   . processing Windows GUI-related messages
> >   . reading from sub-processes (part of pselect emulation)
> >   . emulation of itimers (for atimers and for M-x profiler)
> >   . file-change notifications
> >
> > I need to understand what traits of a thread make it need to be
> > registered with MPS.  Each of the above will then need a separate
> > audit, I think.
> 
> Using any Lisp_Objects (or other objects allocated from MPS) -> register
> it. AFAIU, the GUI thread gets such an objects posted in a message, so
> that one must be registered.
> 
> The others are hard to say for me. It would not do harm to register
> them, but might mean addtional work for nothing.

So how does one go about registering a thread?

I've just got up from a full hour reading the seemingly-related parts
of igc.c and the MPS documentation (the latter, I must say, is really
badly written and organized illogically), and I still have quite a few
questions about this.

First, the MPS manual says to call mps_thread_reg from the thread
itself, to register a thread.  That function accepts the ARENA
argument.  I see we have a single global arena, but should other
threads use the same arena, or should they create their own?  The
considerations for that are not clear (are they documented
somewhere?), I only see that you used the same arena for the Lisp
threads in thread_add.  Is that arena defined in a way that could
serve additional threads, perhaps many of them?  (The w32 build starts
a separate thread for any file-notification watch, up to 64 threads
for sub-process communications, and one thread per atimer, so in
principle we could have quite a few of them, if a session is a heavy
user of these features.)

While trying to think about the need for an additional arena, I took a
look at the relevant APIs, and became confused with what we do (or
don't do) in make_arena.  All the keywords we add  with MPS_ARGS_ADD
and the magic constants there -- what do they mean and what were the
considerations to choose them and not the others?  Can some commentary
be added there to explain what we need to know, and maybe even mention
optional features we might consider in the future?

Assuming we can do with the single global arena already defined, the
MPS documentation next says that every thread's registers and stack
should be registered using mps_root_create_thread.  But the code in
igc.c uses mps_root_create_thread_scanned instead, whose documentation
is obscure, and I cannot figure out whether to copycat or do something
else.

Next, mps_root_create_thread and mps_root_create_thread_scanned
require a COLD pointer, about which the MPS documentation says:

  The MPS’s stack scanner needs to know how to find the cold end of the
  part of the stack to scan.  The cold end of the relevant part of the
  stack can be found by taking the address of a local variable in the
  function that calls the main work function of your thread.  You should
  take care to ensure that the work function is not inlined so that the
  address is definitely in the stack frame below any potential roots.

But in our case, the thread function is run directly by the MS-Windows
CreateThread API, not via an intermediate function, so the worker
function is effectively "inlined".  So is it okay to have the cold end
marker be a local variable in the same thread-worker function?  In
another place of the MPS documentation there's an example which seems
to answer in the positive:

     void *marker = &marker;
     mps_root_t stack_root;
     res = mps_root_create_thread(&stack_root, arena, thread, marker);
     if (res != MPS_RES_OK) error("Couldn't create stack root");

Am I missing something, or could the above be at the very beginning of
a thread's worker function?  Or do we have to define intermediary
functions for each thread worker?

mps_root_create_thread_scanned also takes the CLOSURE argument, which
is a pointer, and we pass a NULL pointer as its value(??).  Is this
because our scan_area function, scan_ambig, simply ignores the CLOSURE
argument?

What else needs to be done for "registering a thread"?  igc_thread_add
does a few other things; some of them are Lisp-related (so not
relevant for non-Lisp threads), but others aren't, so I'm unsure about
these:

  . igc_thread_list_push (what is it? and where defined?)
  . igc_root_list_push (where is it defined and what does it do?)
  . create_thread_aps (what is it for?)

I think some minimal commentary to what these functions do is in
order, to make the code look less like some "black magic".

TIA



^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: MPS image cache
  2024-05-05  8:16           ` Helmut Eller
@ 2024-05-05  8:42             ` Gerd Möllmann
  2024-05-06 14:16               ` Helmut Eller
  0 siblings, 1 reply; 70+ messages in thread
From: Gerd Möllmann @ 2024-05-05  8:42 UTC (permalink / raw)
  To: Helmut Eller; +Cc: Eli Zaretskii, Emacs Devel

Helmut Eller <eller.helmut@gmail.com> writes:

> On Sun, May 05 2024, Gerd Möllmann wrote:
>
>> I'm plannign to do the following if nobody stops me:
>>
>> Both face an image cache are hash tables containing 2 arrays of pointers
>> to MPS objects (face, image).
>>
>> I want to introduce a new MPS object type representing such an array of
>> pointers, IGC_OBJ_PTR_VEC. The igc_header gives us the size of the
>> array, and being an MPS object, we get exclusive access to its contents.
>>
>> WDYT
>
> Would something like this also be needed for glyph matrices?  

Probably. Either we make the matrices roots, or objects, I guess. For
correctness. We can't easily realloc when they are objects, but I don't
think that's a big problem.

> Or in general, can we scan anything other than the block that
> dflt_scan was called with? 

Let's say we shouldn't :-). MPS lets us scan memory it doesn't manage,
but with multi-threading it's not really safe.

> Is these related to "remote references" in the MPS manual, which I
> don't quite understand what they mean.

That's this

  A reference that logically belongs to a formatted object and so must be
  fixed when the object is scanned, but which is not stored within the
  block containing the object. (For example, in an auxiliary table of some
  sort.)

  The MPS does not generally support remote references because those
  references may be protected and so if scan method attempts to fix them
  this will hit a barrier (1) and cause a re-entrant call to the MPS.

My interpretation of this is that we may only fix12 references withing
in an object that is currently scanned (is in the address range for
which MPS called us). We may not extend the scan to other MPS objects.

Let's say we are scanning a symbol S. The reference to S->name can/must
be scanned, but S->name->intervals or something is taboo because S->name
may be behind a barrier.

Made sense to me.



^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: MPS image cache
  2024-05-05  7:02           ` Gerd Möllmann
@ 2024-05-05  9:00             ` Eli Zaretskii
  2024-05-05  9:31               ` Gerd Möllmann
  0 siblings, 1 reply; 70+ messages in thread
From: Eli Zaretskii @ 2024-05-05  9:00 UTC (permalink / raw)
  To: Gerd Möllmann; +Cc: eller.helmut, emacs-devel

> From: Gerd Möllmann <gerd.moellmann@gmail.com>
> Cc: Eli Zaretskii <eliz@gnu.org>,  Emacs Devel <emacs-devel@gnu.org>
> Date: Sun, 05 May 2024 09:02:17 +0200
> 
> Gerd Möllmann <gerd.moellmann@gmail.com> writes:
> 
> > I'm plannign to do the following if nobody stops me:
> >
> > Both face an image cache are hash tables containing 2 arrays of pointers
> > to MPS objects (face, image).
> >
> > I want to introduce a new MPS object type representing such an array of
> > pointers, IGC_OBJ_PTR_VEC. The igc_header gives us the size of the
> > array, and being an MPS object, we get exclusive access to its contents.
> >
> > WDYT
> 
> Pushed that, but not yet using it. We can always remove that later...

It breaks the 32-bit build:

  In file included from lisp.h:42,
		   from igc.c:32:
  igc.c: In function 'fix_ptr_vec':
  ../lib/verify.h:213:41: error: static assertion failed: "verify (sizeof *h == sizeof *v)"
    213 | # define _GL_VERIFY(R, DIAGNOSTIC, ...) _Static_assert (R, DIAGNOSTIC)
	|                                         ^~~~~~~~~~~~~~
  ../lib/verify.h:330:20: note: in expansion of macro '_GL_VERIFY'
    330 | # define verify(R) _GL_VERIFY (R, "verify (" #R ")", -)
	|                    ^~~~~~~~~~
  igc.c:107:30: note: in expansion of macro 'verify'
    107 | #define igc_static_assert(x) verify (x)
	|                              ^~~~~~
  igc.c:1085:5: note: in expansion of macro 'igc_static_assert'
   1085 |     igc_static_assert (sizeof *h == sizeof *v);
	|     ^~~~~~~~~~~~~~~~~
  Makefile:453: recipe for target `igc.o' failed

And I truly don't understand how it was supposed to work:

  static mps_res_t
  fix_ptr_vec (mps_ss_t ss, void *client)
  {
    MPS_SCAN_BEGIN (ss)
    {
      struct igc_header *h = client_to_base (client);
      void **v = client;
      igc_static_assert (sizeof *h == sizeof *v);  <<<<<<<<<<<<<<<<<

Here '*v' is a pointer, whereas '*h' is 'struct igc_header', which is
a structure whose size is larger than 32 bits:

  enum
  {
    IGC_TYPE_BITS = 5,
    IGC_PVEC_BITS = 6,
    IGC_HASH_BITS = 21,
    IGC_SIZE_BITS = 32
  };

  struct igc_header
  {
    enum igc_obj_type obj_type : IGC_TYPE_BITS;
    enum pvec_type pvec_type : IGC_PVEC_BITS;
    mps_word_t hash : IGC_HASH_BITS;
    mps_word_t nwords : IGC_SIZE_BITS;
  };

So this can only work on a 64-bit architecture, and even then only if
the compiler packs the structure (which is entirely not guaranteed
AFAIK).  Or what am I missing here?

And wasn't it supposed to say

      void **v = &client;

instead?

IMNSHO, this kind of code really needs comments to explain what it
does and why.



^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: MPS: w32 threads
  2024-05-05  8:27                                 ` Eli Zaretskii
@ 2024-05-05  9:16                                   ` Gerd Möllmann
  2024-05-05 14:39                                     ` Eli Zaretskii
  0 siblings, 1 reply; 70+ messages in thread
From: Gerd Möllmann @ 2024-05-05  9:16 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: eller.helmut, emacs-devel

Eli Zaretskii <eliz@gnu.org> writes:

> First, the MPS manual says to call mps_thread_reg from the thread
> itself, to register a thread.  That function accepts the ARENA
> argument.  I see we have a single global arena, but should other
> threads use the same arena, or should they create their own?  The
> considerations for that are not clear (are they documented
> somewhere?), I only see that you used the same arena for the Lisp
> threads in thread_add.  Is that arena defined in a way that could
> serve additional threads, perhaps many of them?  (The w32 build starts
> a separate thread for any file-notification watch, up to 64 threads
> for sub-process communications, and one thread per atimer, so in
> principle we could have quite a few of them, if a session is a heavy
> user of these features.)

Let's say we made a thread_state for GUI thread. If we had that, you
could simply call this:

static struct igc_thread_list *
thread_add (struct thread_state *ts)
{
  mps_thr_t thr;
  mps_res_t res = mps_thread_reg (&thr, global_igc->arena);
  IGC_CHECK_RES (res);
  struct igc_thread_list *t = register_thread (global_igc, thr, ts);
  root_create_thread (t);
  create_thread_aps (&t->d);
  return t;
}

from the GUI thread. That does everything you could possibly need. The
igc_thread_add "API" does more because other threads have their own
specpdl and byte code stack.

> While trying to think about the need for an additional arena, I took a
> look at the relevant APIs, and became confused with what we do (or
> don't do) in make_arena.  All the keywords we add  with MPS_ARGS_ADD
> and the magic constants there -- what do they mean and what were the
> considerations to choose them and not the others?  Can some commentary
> be added there to explain what we need to know, and maybe even mention
> optional features we might consider in the future?

What's currently there is simply the result of me reading the docs, and
picking what I thought would be needed. I guess there are a lot of knobs
that could be tried... That is also the case for pools, generations....

> Assuming we can do with the single global arena already defined, 

There is no need for an additional arena.

> the MPS documentation next says that every thread's registers and
> stack should be registered using mps_root_create_thread. But the code
> in igc.c uses mps_root_create_thread_scanned instead, whose
> documentation is obscure, and I cannot figure out whether to copycat
> or do something else.

The _scanned variant allows us to use our own scan method, which is
necessary because how we represent symbols in Lisp_Objects (the NULL ==
nil thing.)

> Next, mps_root_create_thread and mps_root_create_thread_scanned
> require a COLD pointer, about which the MPS documentation says:
>
>   The MPS’s stack scanner needs to know how to find the cold end of the
>   part of the stack to scan.  The cold end of the relevant part of the
>   stack can be found by taking the address of a local variable in the
>   function that calls the main work function of your thread.  You should
>   take care to ensure that the work function is not inlined so that the
>   address is definitely in the stack frame below any potential roots.
>
> But in our case, the thread function is run directly by the MS-Windows
> CreateThread API, not via an intermediate function, so the worker
> function is effectively "inlined".  So is it okay to have the cold end
> marker be a local variable in the same thread-worker function?  In
> another place of the MPS documentation there's an example which seems
> to answer in the positive:
>
>      void *marker = &marker;
>      mps_root_t stack_root;
>      res = mps_root_create_thread(&stack_root, arena, thread, marker);
>      if (res != MPS_RES_OK) error("Couldn't create stack root");
>
> Am I missing something, or could the above be at the very beginning of
> a thread's worker function?  Or do we have to define intermediary
> functions for each thread worker?

I'm not sure I have understood how that works. Is it like in pthread
that you create a thread specifying a thread_main? And when you return
from thread_main the thread is over?

> mps_root_create_thread_scanned also takes the CLOSURE argument, which
> is a pointer, and we pass a NULL pointer as its value(??).  Is this
> because our scan_area function, scan_ambig, simply ignores the CLOSURE
> argument?

The closure arg is for use by us, as we want. An example is dflt_scanx
that is also used for walking over all objects. Kind of a visitor pattern.

> What else needs to be done for "registering a thread"?  igc_thread_add
> does a few other things; some of them are Lisp-related (so not
> relevant for non-Lisp threads), but others aren't, so I'm unsure about
> these:

I think igc_thread_add does too much for the GUI thread, see above.

>   . igc_thread_list_push (what is it? and where defined?)
>   . igc_root_list_push (where is it defined and what does it do?)

It's a very ppor man's alternative to C++ std::list, implemented with
abominable macros, see IGC_DEFINE_LIS.

>   . create_thread_aps (what is it for?)

These are allocation points for allocating from MPS. Each thread needs
its own aps. (It wouldn't hurt to have aps, even if they are not used.)

> I think some minimal commentary to what these functions do is in
> order, to make the code look less like some "black magic".

I know :-).

In summary, I would really recommend, if technically possible on Window,
to set up a thread_state and use what's there in igc.c.



^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: MPS image cache
  2024-05-05  9:00             ` Eli Zaretskii
@ 2024-05-05  9:31               ` Gerd Möllmann
  2024-05-05 10:24                 ` Eli Zaretskii
  0 siblings, 1 reply; 70+ messages in thread
From: Gerd Möllmann @ 2024-05-05  9:31 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: eller.helmut, emacs-devel

Eli Zaretskii <eliz@gnu.org> writes:

>> Pushed that, but not yet using it. We can always remove that later...
>
> It breaks the 32-bit build:
>
>   In file included from lisp.h:42,
> 		   from igc.c:32:
>   igc.c: In function 'fix_ptr_vec':
>   ../lib/verify.h:213:41: error: static assertion failed: "verify (sizeof *h == sizeof *v)"
>     213 | # define _GL_VERIFY(R, DIAGNOSTIC, ...) _Static_assert (R, DIAGNOSTIC)
> 	|                                         ^~~~~~~~~~~~~~
>   ../lib/verify.h:330:20: note: in expansion of macro '_GL_VERIFY'
>     330 | # define verify(R) _GL_VERIFY (R, "verify (" #R ")", -)
> 	|                    ^~~~~~~~~~
>   igc.c:107:30: note: in expansion of macro 'verify'
>     107 | #define igc_static_assert(x) verify (x)
> 	|                              ^~~~~~
>   igc.c:1085:5: note: in expansion of macro 'igc_static_assert'
>    1085 |     igc_static_assert (sizeof *h == sizeof *v);
> 	|     ^~~~~~~~~~~~~~~~~
>   Makefile:453: recipe for target `igc.o' failed
>
> And I truly don't understand how it was supposed to work:
>
>   static mps_res_t
>   fix_ptr_vec (mps_ss_t ss, void *client)
>   {
>     MPS_SCAN_BEGIN (ss)
>     {
>       struct igc_header *h = client_to_base (client);
>       void **v = client;
>       igc_static_assert (sizeof *h == sizeof *v);  <<<<<<<<<<<<<<<<<
>
> Here '*v' is a pointer, whereas '*h' is 'struct igc_header', which is
> a structure whose size is larger than 32 bits:

I guess this comes from igc_header being 1 word on 64 bit, and 2 on
32-bit. Thing is we need to know how large the vector is to scan it.
We have the info the igc_header::nwords.

>   enum
>   {
>     IGC_TYPE_BITS = 5,
>     IGC_PVEC_BITS = 6,
>     IGC_HASH_BITS = 21,
>     IGC_SIZE_BITS = 32
>   };
>
>   struct igc_header
>   {
>     enum igc_obj_type obj_type : IGC_TYPE_BITS;
>     enum pvec_type pvec_type : IGC_PVEC_BITS;
>     mps_word_t hash : IGC_HASH_BITS;
>     mps_word_t nwords : IGC_SIZE_BITS;
>   };
>
> So this can only work on a 64-bit architecture, and even then only if
> the compiler packs the structure (which is entirely not guaranteed
> AFAIK).  Or what am I missing here?

Apparently it only works as is on 64-bits and so on. What do you expect
me to do? A thing I promise not to do is to develop and check on any
platform except mine.

> And wasn't it supposed to say
>
>       void **v = &client;
>
> instead?

The address of a local variable? I think it's correct as is.



^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: MPS image cache
  2024-05-05  9:31               ` Gerd Möllmann
@ 2024-05-05 10:24                 ` Eli Zaretskii
  2024-05-05 10:36                   ` Gerd Möllmann
  0 siblings, 1 reply; 70+ messages in thread
From: Eli Zaretskii @ 2024-05-05 10:24 UTC (permalink / raw)
  To: Gerd Möllmann; +Cc: eller.helmut, emacs-devel

> From: Gerd Möllmann <gerd.moellmann@gmail.com>
> Cc: eller.helmut@gmail.com,  emacs-devel@gnu.org
> Date: Sun, 05 May 2024 11:31:23 +0200
> 
> Eli Zaretskii <eliz@gnu.org> writes:
> 
> >   static mps_res_t
> >   fix_ptr_vec (mps_ss_t ss, void *client)
> >   {
> >     MPS_SCAN_BEGIN (ss)
> >     {
> >       struct igc_header *h = client_to_base (client);
> >       void **v = client;
> >       igc_static_assert (sizeof *h == sizeof *v);  <<<<<<<<<<<<<<<<<
> >
> > Here '*v' is a pointer, whereas '*h' is 'struct igc_header', which is
> > a structure whose size is larger than 32 bits:
> 
> I guess this comes from igc_header being 1 word on 64 bit, and 2 on
> 32-bit. Thing is we need to know how large the vector is to scan it.
> We have the info the igc_header::nwords.
> 
> >   enum
> >   {
> >     IGC_TYPE_BITS = 5,
> >     IGC_PVEC_BITS = 6,
> >     IGC_HASH_BITS = 21,
> >     IGC_SIZE_BITS = 32
> >   };
> >
> >   struct igc_header
> >   {
> >     enum igc_obj_type obj_type : IGC_TYPE_BITS;
> >     enum pvec_type pvec_type : IGC_PVEC_BITS;
> >     mps_word_t hash : IGC_HASH_BITS;
> >     mps_word_t nwords : IGC_SIZE_BITS;
> >   };
> >
> > So this can only work on a 64-bit architecture, and even then only if
> > the compiler packs the structure (which is entirely not guaranteed
> > AFAIK).  Or what am I missing here?
> 
> Apparently it only works as is on 64-bits and so on.

How can you be sure the compiler packs the struct fields, even on a
64-bit platform?  If the fields are not packed, the struct could take
more than 1 word on a 64-bit platform as well.  Compilers are known to
align struct members for faster access.

> What do you expect me to do?

Can you explain what the code is supposed to do, and why you need that
assertion?  "we need to know how large the vector is to scan it"
didn't explain it enough for me to understand.

> A thing I promise not to do is to develop and check on any platform
> except mine.

I thought I was helping to test on a platform where you don't, but I
need help in understanding the code, so I could think about possible
ways of fixing it.  We are not abandoning 32-bit platforms any time
soon, so a solution for this will be needed.

TIA



^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: MPS image cache
  2024-05-05 10:24                 ` Eli Zaretskii
@ 2024-05-05 10:36                   ` Gerd Möllmann
  2024-05-05 11:01                     ` Eli Zaretskii
  0 siblings, 1 reply; 70+ messages in thread
From: Gerd Möllmann @ 2024-05-05 10:36 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: eller.helmut, emacs-devel

Eli Zaretskii <eliz@gnu.org> writes:

>> Apparently it only works as is on 64-bits and so on.
>
> How can you be sure the compiler packs the struct fields, even on a
> 64-bit platform?  If the fields are not packed, the struct could take
> more than 1 word on a 64-bit platform as well.  Compilers are known to
> align struct members for faster access.

It is on my platform.

>> What do you expect me to do?
>
> Can you explain what the code is supposed to do, and why you need that
> assertion?  

I made the compiler my check my assumption at compile time. I find that
pretty cool of me.

> "we need to know how large the vector is to scan it" didn't explain it
> enough for me to understand.

We allocate a vector of N pointers. The N is found in the header when we
scan it. It's the size of the MPS object we scan minus the header
divided by how large a pointer is.
>
>> A thing I promise not to do is to develop and check on any platform
>> except mine.
>
> I thought I was helping to test on a platform where you don't, but I
> need help in understanding the code, so I could think about possible
> ways of fixing it.  We are not abandoning 32-bit platforms any time
> soon, so a solution for this will be needed.

Yeah, I know, sorry. My sciatica is killing me, and I'm probably a bit
hard to handle these days :-(



^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: MPS image cache
  2024-05-05 10:36                   ` Gerd Möllmann
@ 2024-05-05 11:01                     ` Eli Zaretskii
  2024-05-05 12:55                       ` Gerd Möllmann
  0 siblings, 1 reply; 70+ messages in thread
From: Eli Zaretskii @ 2024-05-05 11:01 UTC (permalink / raw)
  To: Gerd Möllmann; +Cc: eller.helmut, emacs-devel

> From: Gerd Möllmann <gerd.moellmann@gmail.com>
> Cc: eller.helmut@gmail.com,  emacs-devel@gnu.org
> Date: Sun, 05 May 2024 12:36:21 +0200
> 
> Eli Zaretskii <eliz@gnu.org> writes:
> 
> >> Apparently it only works as is on 64-bits and so on.
> >
> > How can you be sure the compiler packs the struct fields, even on a
> > 64-bit platform?  If the fields are not packed, the struct could take
> > more than 1 word on a 64-bit platform as well.  Compilers are known to
> > align struct members for faster access.
> 
> It is on my platform.

IME, this cannot be relied upon, unless we explicitly tell the
compiler to pack (using some pragma or somesuch).

> >> What do you expect me to do?
> >
> > Can you explain what the code is supposed to do, and why you need that
> > assertion?  
> 
> I made the compiler my check my assumption at compile time. I find that
> pretty cool of me.

That's not what I meant.  I meant to ask why we need the struct to be
of the same size as a pointer?

> > "we need to know how large the vector is to scan it" didn't explain it
> > enough for me to understand.
> 
> We allocate a vector of N pointers. The N is found in the header when we
> scan it. It's the size of the MPS object we scan minus the header
> divided by how large a pointer is.

OK, but why does the struct have to fit in a single word?



^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: MPS image cache
  2024-05-05 11:01                     ` Eli Zaretskii
@ 2024-05-05 12:55                       ` Gerd Möllmann
  2024-05-05 14:07                         ` Eli Zaretskii
  0 siblings, 1 reply; 70+ messages in thread
From: Gerd Möllmann @ 2024-05-05 12:55 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: eller.helmut, emacs-devel

Eli Zaretskii <eliz@gnu.org> writes:

>> It is on my platform.
>
> IME, this cannot be relied upon, unless we explicitly tell the
> compiler to pack (using some pragma or somesuch).

And the static_assert will fire, right. You're telling me nothing new,
BTW. I'm pretty well acquainged with all this.

>
>> >> What do you expect me to do?
>> >
>> > Can you explain what the code is supposed to do, and why you need that
>> > assertion?  
>> 
>> I made the compiler my check my assumption at compile time. I find that
>> pretty cool of me.
>
> That's not what I meant.  I meant to ask why we need the struct to be
> of the same size as a pointer?
>
>> > "we need to know how large the vector is to scan it" didn't explain it
>> > enough for me to understand.
>> 
>> We allocate a vector of N pointers. The N is found in the header when we
>> scan it. It's the size of the MPS object we scan minus the header
>> divided by how large a pointer is.
>
> OK, but why does the struct have to fit in a single word?

It doesn't, it the other way around. I'm using nwords - 1 for the size
of the vector, and the static_assert is intended to fire if nwords - 1
is not right.



^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: MPS image cache
  2024-05-05 12:55                       ` Gerd Möllmann
@ 2024-05-05 14:07                         ` Eli Zaretskii
  2024-05-05 14:32                           ` Gerd Möllmann
  0 siblings, 1 reply; 70+ messages in thread
From: Eli Zaretskii @ 2024-05-05 14:07 UTC (permalink / raw)
  To: Gerd Möllmann; +Cc: eller.helmut, emacs-devel

> From: Gerd Möllmann <gerd.moellmann@gmail.com>
> Cc: eller.helmut@gmail.com,  emacs-devel@gnu.org
> Date: Sun, 05 May 2024 14:55:04 +0200
> 
> Eli Zaretskii <eliz@gnu.org> writes:
> 
> >> It is on my platform.
> >
> > IME, this cannot be relied upon, unless we explicitly tell the
> > compiler to pack (using some pragma or somesuch).
> 
> And the static_assert will fire, right. You're telling me nothing new,
> BTW. I'm pretty well acquainged with all this.

I imagined, it just took me by surprise that you would nonetheless
write code that could so easily fail to compile.

> >> We allocate a vector of N pointers. The N is found in the header when we
> >> scan it. It's the size of the MPS object we scan minus the header
> >> divided by how large a pointer is.
> >
> > OK, but why does the struct have to fit in a single word?
> 
> It doesn't, it the other way around. I'm using nwords - 1 for the size
> of the vector, and the static_assert is intended to fire if nwords - 1
> is not right.

OK, then my question now is "why does it have to be nwords-1?"



^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: MPS image cache
  2024-05-05 14:07                         ` Eli Zaretskii
@ 2024-05-05 14:32                           ` Gerd Möllmann
  2024-05-05 15:49                             ` Eli Zaretskii
  0 siblings, 1 reply; 70+ messages in thread
From: Gerd Möllmann @ 2024-05-05 14:32 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: eller.helmut, emacs-devel

Eli Zaretskii <eliz@gnu.org> writes:

>> From: Gerd Möllmann <gerd.moellmann@gmail.com>
>> Cc: eller.helmut@gmail.com,  emacs-devel@gnu.org
>> Date: Sun, 05 May 2024 14:55:04 +0200
>> 
>> Eli Zaretskii <eliz@gnu.org> writes:
>> 
>> >> It is on my platform.
>> >
>> > IME, this cannot be relied upon, unless we explicitly tell the
>> > compiler to pack (using some pragma or somesuch).
>> 
>> And the static_assert will fire, right. You're telling me nothing new,
>> BTW. I'm pretty well acquainged with all this.
>
> I imagined, it just took me by surprise that you would nonetheless
> write code that could so easily fail to compile.

I think it's a matter of personal priorities. It guess it can't hurt to
say explicity what these are.

1. Make progress fast, so that I can assess for myself if it's worth
continuing. With an Emacs up time of ca. 8h now, I tend to think so.
When it would reach say 5 days or so, we'd be in the realm of what
master survives for me on macOS.

2. Make it work for me in my personal fork (CL packages) which is macOS
only anyway, and is basically for me alone only.

3. GNU. And I'm neither a maintainer of anything, nor want to maintain
anything in the GNU sense.

>> >> We allocate a vector of N pointers. The N is found in the header when we
>> >> scan it. It's the size of the MPS object we scan minus the header
>> >> divided by how large a pointer is.
>> >
>> > OK, but why does the struct have to fit in a single word?
>> 
>> It doesn't, it the other way around. I'm using nwords - 1 for the size
>> of the vector, and the static_assert is intended to fire if nwords - 1
>> is not right.
>
> OK, then my question now is "why does it have to be nwords-1?"

I suspect that I'll answer something you don't ask again: We allocate a
vector of N elements. We don't store N directly somewhere, but we have
an igc_header from which we can compute N. So I compute it as nwords -
1. If that's not right, I static_assert, and leave it to the interested
party to do something.



^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: MPS: w32 threads
  2024-05-05  9:16                                   ` Gerd Möllmann
@ 2024-05-05 14:39                                     ` Eli Zaretskii
  2024-05-05 15:23                                       ` Gerd Möllmann
  0 siblings, 1 reply; 70+ messages in thread
From: Eli Zaretskii @ 2024-05-05 14:39 UTC (permalink / raw)
  To: Gerd Möllmann; +Cc: eller.helmut, emacs-devel

> From: Gerd Möllmann <gerd.moellmann@gmail.com>
> Cc: eller.helmut@gmail.com,  emacs-devel@gnu.org
> Date: Sun, 05 May 2024 11:16:04 +0200
> 
> Eli Zaretskii <eliz@gnu.org> writes:
> 
> Let's say we made a thread_state for GUI thread. If we had that, you
> could simply call this:
> 
> static struct igc_thread_list *
> thread_add (struct thread_state *ts)
> {
>   mps_thr_t thr;
>   mps_res_t res = mps_thread_reg (&thr, global_igc->arena);
>   IGC_CHECK_RES (res);
>   struct igc_thread_list *t = register_thread (global_igc, thr, ts);
>   root_create_thread (t);
>   create_thread_aps (&t->d);
>   return t;
> }

thread_state is HUGE!  Almost everything there is unneeded for the
other threads, which are not Lisp threads, they run straightforward
and quite simple C code.  So I'd like to avoid that if possible, which
is why I asked all those questions.

> > While trying to think about the need for an additional arena, I took a
> > look at the relevant APIs, and became confused with what we do (or
> > don't do) in make_arena.  All the keywords we add  with MPS_ARGS_ADD
> > and the magic constants there -- what do they mean and what were the
> > considerations to choose them and not the others?  Can some commentary
> > be added there to explain what we need to know, and maybe even mention
> > optional features we might consider in the future?
> 
> What's currently there is simply the result of me reading the docs, and
> picking what I thought would be needed. I guess there are a lot of knobs
> that could be tried... That is also the case for pools, generations....

I'd appreciate if you could add at least some comments about why you
thought this stuff and not the rest.

> > Assuming we can do with the single global arena already defined, 
> 
> There is no need for an additional arena.

OK, thanks.

> > the MPS documentation next says that every thread's registers and
> > stack should be registered using mps_root_create_thread. But the code
> > in igc.c uses mps_root_create_thread_scanned instead, whose
> > documentation is obscure, and I cannot figure out whether to copycat
> > or do something else.
> 
> The _scanned variant allows us to use our own scan method, which is
> necessary because how we represent symbols in Lisp_Objects (the NULL ==
> nil thing.)

Got it, thanks.

> >   The MPS’s stack scanner needs to know how to find the cold end of the
> >   part of the stack to scan.  The cold end of the relevant part of the
> >   stack can be found by taking the address of a local variable in the
> >   function that calls the main work function of your thread.  You should
> >   take care to ensure that the work function is not inlined so that the
> >   address is definitely in the stack frame below any potential roots.
> >
> > But in our case, the thread function is run directly by the MS-Windows
> > CreateThread API, not via an intermediate function, so the worker
> > function is effectively "inlined".  So is it okay to have the cold end
> > marker be a local variable in the same thread-worker function?  In
> > another place of the MPS documentation there's an example which seems
> > to answer in the positive:
> >
> >      void *marker = &marker;
> >      mps_root_t stack_root;
> >      res = mps_root_create_thread(&stack_root, arena, thread, marker);
> >      if (res != MPS_RES_OK) error("Couldn't create stack root");
> >
> > Am I missing something, or could the above be at the very beginning of
> > a thread's worker function?  Or do we have to define intermediary
> > functions for each thread worker?
> 
> I'm not sure I have understood how that works. Is it like in pthread
> that you create a thread specifying a thread_main? And when you return
> from thread_main the thread is over?

Yes.  Example:

	  cp->thrd = CreateThread (NULL, 64 * 1024, reader_thread, cp,
				   0x00010000, &id);

where reader_thread is the thread worker function.  When the thread's
work is done, that function exits, and the thread exits as well.

My question is whether I can make the mps_root_create_thread call from
inside reader_thread and other similar worker functions, or do I need
to go through an intermediary, like so:

  static int
  worker (...)
  {
    void *marker = &marker;
    mps_root_t stack_root;
    res = mps_root_create_thread(&stack_root, arena, thread, marker);
    if (res != MPS_RES_OK) error("Couldn't create stack root");
    return real_worker ();
  }

  CreateThread (..., worker, ...);

> >   . igc_thread_list_push (what is it? and where defined?)
> >   . igc_root_list_push (where is it defined and what does it do?)
> 
> It's a very ppor man's alternative to C++ std::list, implemented with
> abominable macros, see IGC_DEFINE_LIS.

I reckon we don't need to keep the threads I'm talking about on a
list, since they don't have any specpdl pointers?

> >   . create_thread_aps (what is it for?)
> 
> These are allocation points for allocating from MPS. Each thread needs
> its own aps. (It wouldn't hurt to have aps, even if they are not used.)

OK, but what is each of those 4 aps for? are all of them needed for a
thread that doesn't run Lisp?  I see these aps are stored in struct
igc_thread, which seems to be for Lisp threads?

> In summary, I would really recommend, if technically possible on Window,
> to set up a thread_state and use what's there in igc.c.

I'd like to avoid that, for reasons explained above.

Thanks.



^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: MPS: w32 threads
  2024-05-05 14:39                                     ` Eli Zaretskii
@ 2024-05-05 15:23                                       ` Gerd Möllmann
  2024-05-05 15:26                                         ` Gerd Möllmann
  0 siblings, 1 reply; 70+ messages in thread
From: Gerd Möllmann @ 2024-05-05 15:23 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: eller.helmut, emacs-devel

Eli Zaretskii <eliz@gnu.org> writes:

>> From: Gerd Möllmann <gerd.moellmann@gmail.com>
>> Cc: eller.helmut@gmail.com,  emacs-devel@gnu.org
>> Date: Sun, 05 May 2024 11:16:04 +0200
>> 
>> Eli Zaretskii <eliz@gnu.org> writes:
>> 
>> Let's say we made a thread_state for GUI thread. If we had that, you
>> could simply call this:
>> 
>> static struct igc_thread_list *
>> thread_add (struct thread_state *ts)
>> {
>>   mps_thr_t thr;
>>   mps_res_t res = mps_thread_reg (&thr, global_igc->arena);
>>   IGC_CHECK_RES (res);
>>   struct igc_thread_list *t = register_thread (global_igc, thr, ts);
>>   root_create_thread (t);
>>   create_thread_aps (&t->d);
>>   return t;
>> }
>
> thread_state is HUGE!  Almost everything there is unneeded for the
> other threads, which are not Lisp threads, they run straightforward
> and quite simple C code.  So I'd like to avoid that if possible, which
> is why I asked all those questions.

Understandable, but then we have more work to do in igc. main_thread
could also be an example

union aligned_thread_state main_thread
  = {{
      .header.size = PVECHEADERSIZE (PVEC_THREAD,
				     PSEUDOVECSIZE (struct thread_state,
						    event_object),
				     VECSIZE (struct thread_state)),
      .m_last_thing_searched = LISPSYM_INITIALLY (Qnil),
      .m_saved_last_thing_searched = LISPSYM_INITIALLY (Qnil),
      .name = LISPSYM_INITIALLY (Qnil),
      .function = LISPSYM_INITIALLY (Qnil),
      .result = LISPSYM_INITIALLY (Qnil),
      .error_symbol = LISPSYM_INITIALLY (Qnil),
      .error_data = LISPSYM_INITIALLY (Qnil),
      .event_object = LISPSYM_INITIALLY (Qnil),
    }};

Not sure what more we'd need except the stack start address. Plus
potentially 2 ifs that become necessary because so far all thread has a
byte code stack and specpdl.

>> > While trying to think about the need for an additional arena, I took a
>> > look at the relevant APIs, and became confused with what we do (or
>> > don't do) in make_arena.  All the keywords we add  with MPS_ARGS_ADD
>> > and the magic constants there -- what do they mean and what were the
>> > considerations to choose them and not the others?  Can some commentary
>> > be added there to explain what we need to know, and maybe even mention
>> > optional features we might consider in the future?
>> 
>> What's currently there is simply the result of me reading the docs, and
>> picking what I thought would be needed. I guess there are a lot of knobs
>> that could be tried... That is also the case for pools, generations....
>
> I'd appreciate if you could add at least some comments about why you
> thought this stuff and not the rest.

I'll see if I can remember.

>> >   The MPS’s stack scanner needs to know how to find the cold end of the
>> >   part of the stack to scan.  The cold end of the relevant part of the
>> >   stack can be found by taking the address of a local variable in the
>> >   function that calls the main work function of your thread.  You should
>> >   take care to ensure that the work function is not inlined so that the
>> >   address is definitely in the stack frame below any potential roots.
>> >
>> > But in our case, the thread function is run directly by the MS-Windows
>> > CreateThread API, not via an intermediate function, so the worker
>> > function is effectively "inlined".  So is it okay to have the cold end
>> > marker be a local variable in the same thread-worker function?  In
>> > another place of the MPS documentation there's an example which seems
>> > to answer in the positive:
>> >
>> >      void *marker = &marker;
>> >      mps_root_t stack_root;
>> >      res = mps_root_create_thread(&stack_root, arena, thread, marker);
>> >      if (res != MPS_RES_OK) error("Couldn't create stack root");
>> >
>> > Am I missing something, or could the above be at the very beginning of
>> > a thread's worker function?  Or do we have to define intermediary
>> > functions for each thread worker?
>> 
>> I'm not sure I have understood how that works. Is it like in pthread
>> that you create a thread specifying a thread_main? And when you return
>> from thread_main the thread is over?
>
> Yes.  Example:
>
> 	  cp->thrd = CreateThread (NULL, 64 * 1024, reader_thread, cp,
> 				   0x00010000, &id);
>
> where reader_thread is the thread worker function.  When the thread's
> work is done, that function exits, and the thread exits as well.

Ok, that's good.

> My question is whether I can make the mps_root_create_thread call from
> inside reader_thread and other similar worker functions, or do I need
> to go through an intermediary, like so:

No, directly. Like in thread.c run_thread which does in pseudo code

run_thread ():
  self->gc_info = igc_thread_add (self)
  run_lisp_funcion ()
  igc_thread_remove (self->gc_info)
  
where self here is a thread_state. 

>
>   static int
>   worker (...)
>   {
>     void *marker = &marker;
>     mps_root_t stack_root;
>     res = mps_root_create_thread(&stack_root, arena, thread, marker);
>     if (res != MPS_RES_OK) error("Couldn't create stack root");
>     return real_worker ();
>   }
>
>   CreateThread (..., worker, ...);
>
>> >   . igc_thread_list_push (what is it? and where defined?)
>> >   . igc_root_list_push (where is it defined and what does it do?)
>> 
>> It's a very ppor man's alternative to C++ std::list, implemented with
>> abominable macros, see IGC_DEFINE_LIS.
>
> I reckon we don't need to keep the threads I'm talking about on a
> list, since they don't have any specpdl pointers?

Igc theoretically uses the registry of MPS object sthat struct igc is
for freeing stuff when the program ends. So if the thread was registered
with MPS, then it's best if it is added to igc.

Since specpdl and bytecode stack were currently always required it
might be that we have to add some if (this-and-that != NULL).

>> >   . create_thread_aps (what is it for?)
>> 
>> These are allocation points for allocating from MPS. Each thread needs
>> its own aps. (It wouldn't hurt to have aps, even if they are not used.)
>
> OK, but what is each of those 4 aps for? are all of them needed for a
> thread that doesn't run Lisp?  I see these aps are stored in struct
> igc_thread, which seems to be for Lisp threads?

Currently igc_thread == Lisp thread because we did have others yet. Each
thread that wants to allocate from MPS needs 1 ap for each pool we are
using. Except for the weak pool, which needs 2 aps.

If a thread doesn't want to allocate, it strictly speacking doesn't need
aps but my intuition says that only complicates matters without saving
much.



^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: MPS: w32 threads
  2024-05-05 15:23                                       ` Gerd Möllmann
@ 2024-05-05 15:26                                         ` Gerd Möllmann
  0 siblings, 0 replies; 70+ messages in thread
From: Gerd Möllmann @ 2024-05-05 15:26 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: eller.helmut, emacs-devel

Gerd Möllmann <gerd.moellmann@gmail.com> writes:

> Not sure what more we'd need except the stack start address. Plus
> potentially 2 ifs that become necessary because so far all thread has a
> byte code stack and specpdl.

Oops, and of course if we make that a variable like main_thread it
woiuld need to be a root like main_thread is.



^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: MPS image cache
  2024-05-05 14:32                           ` Gerd Möllmann
@ 2024-05-05 15:49                             ` Eli Zaretskii
  2024-05-05 16:19                               ` Gerd Möllmann
  2024-05-05 17:45                               ` Gerd Möllmann
  0 siblings, 2 replies; 70+ messages in thread
From: Eli Zaretskii @ 2024-05-05 15:49 UTC (permalink / raw)
  To: Gerd Möllmann; +Cc: eller.helmut, emacs-devel

> From: Gerd Möllmann <gerd.moellmann@gmail.com>
> Cc: eller.helmut@gmail.com,  emacs-devel@gnu.org
> Date: Sun, 05 May 2024 16:32:02 +0200
> 
> I think it's a matter of personal priorities. It guess it can't hurt to
> say explicity what these are.
> 
> 1. Make progress fast, so that I can assess for myself if it's worth
> continuing. With an Emacs up time of ca. 8h now, I tend to think so.
> When it would reach say 5 days or so, we'd be in the realm of what
> master survives for me on macOS.
> 
> 2. Make it work for me in my personal fork (CL packages) which is macOS
> only anyway, and is basically for me alone only.
> 
> 3. GNU. And I'm neither a maintainer of anything, nor want to maintain
> anything in the GNU sense.

And my impression was that we are trying to advance on 3 most
important Emacs platforms in parallel, with the purpose of adding this
to Emacs at some point.  Apologies for my misunderstanding.

> >> >> We allocate a vector of N pointers. The N is found in the header when we
> >> >> scan it. It's the size of the MPS object we scan minus the header
> >> >> divided by how large a pointer is.
> >> >
> >> > OK, but why does the struct have to fit in a single word?
> >> 
> >> It doesn't, it the other way around. I'm using nwords - 1 for the size
> >> of the vector, and the static_assert is intended to fire if nwords - 1
> >> is not right.
> >
> > OK, then my question now is "why does it have to be nwords-1?"
> 
> I suspect that I'll answer something you don't ask again: We allocate a
> vector of N elements. We don't store N directly somewhere, but we have
> an igc_header from which we can compute N. So I compute it as nwords -
> 1. If that's not right, I static_assert, and leave it to the interested
> party to do something.

I fixed the code according to my understanding, please take a look and
tell if I missed something (since the new function does not seem to be
used yet for the two caches you mentioned, it is hard to know whether
I violated some assumptions).

Thanks.



^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: MPS image cache
  2024-05-05 15:49                             ` Eli Zaretskii
@ 2024-05-05 16:19                               ` Gerd Möllmann
  2024-05-05 17:45                               ` Gerd Möllmann
  1 sibling, 0 replies; 70+ messages in thread
From: Gerd Möllmann @ 2024-05-05 16:19 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: eller.helmut, emacs-devel

Eli Zaretskii <eliz@gnu.org> writes:

> And my impression was that we are trying to advance on 3 most
> important Emacs platforms in parallel, with the purpose of adding this
> to Emacs at some point.  Apologies for my misunderstanding.

My apologies for not helping with the advance!



^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: MPS: scroll-bars
  2024-05-05  7:53                     ` Helmut Eller
  2024-05-05  8:01                       ` Gerd Möllmann
@ 2024-05-05 16:43                       ` Eli Zaretskii
  2024-05-05 18:02                         ` Helmut Eller
  1 sibling, 1 reply; 70+ messages in thread
From: Eli Zaretskii @ 2024-05-05 16:43 UTC (permalink / raw)
  To: Helmut Eller; +Cc: gerd.moellmann, luangruo, emacs-devel

> From: Helmut Eller <eller.helmut@gmail.com>
> Cc: Po Lu <luangruo@yahoo.com>,  Eli Zaretskii <eliz@gnu.org>,  Emacs Devel
>  <emacs-devel@gnu.org>
> Date: Sun, 05 May 2024 09:53:33 +0200
> 
> Below is my patch for the scroll-bars.  I went for the indirection layer
> solution.  Though, the mark-and-sweep pool idea might be more broadly
> usable; with so many different GUI toolkits it's hard to say.

Can you tell, for my own education, what does a call to
igc_xzalloc_ambig give us, as opposed to just xzalloc?

TIA



^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: MPS image cache
  2024-05-05 15:49                             ` Eli Zaretskii
  2024-05-05 16:19                               ` Gerd Möllmann
@ 2024-05-05 17:45                               ` Gerd Möllmann
  2024-05-05 18:04                                 ` Eli Zaretskii
  1 sibling, 1 reply; 70+ messages in thread
From: Gerd Möllmann @ 2024-05-05 17:45 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: eller.helmut, emacs-devel

Eli Zaretskii <eliz@gnu.org> writes:

> I fixed the code according to my understanding, please take a look and
> tell if I missed something (since the new function does not seem to be
> used yet for the two caches you mentioned, it is hard to know whether
> I violated some assumptions).

This hunk is wrong:

@@ -2978,7 +2977,8 @@ igc_make_face_cache (void)
 void *
 igc_make_ptr_vec (size_t n)
 {
-  return alloc (n * sizeof (void *), IGC_OBJ_PTR_VEC, PVEC_FREE);
+  return alloc (sizeof (struct igc_header) + (n - 1) * sizeof (void *),
+		IGC_OBJ_PTR_VEC, PVEC_FREE);
 }
 
what you removed was correct because alloc takes the size in bytes to
allocate from the POV of the client.

Alloc computes the size needed from MPS

  size = obj_size (size);

which includes the header among other things.







^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: MPS: scroll-bars
  2024-05-05 16:43                       ` Eli Zaretskii
@ 2024-05-05 18:02                         ` Helmut Eller
  2024-05-05 18:09                           ` Eli Zaretskii
  0 siblings, 1 reply; 70+ messages in thread
From: Helmut Eller @ 2024-05-05 18:02 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: gerd.moellmann, luangruo, emacs-devel

On Sun, May 05 2024, Eli Zaretskii wrote:

> Can you tell, for my own education, what does a call to
> igc_xzalloc_ambig give us, as opposed to just xzalloc?

igc_xzalloc_ambig allocates memory like xzalloc but it addition
registers it as root.  When MPS starts scanning, it begins from the
roots.  That means, we are sure that the referenced objects stay alive.
In the case of ambiguous references, the objects are also pinned
(i.e. don't move).

That pinning part is not necessary for the scroll-bar case, but
igc_xzalloc_ambig is currently the easiest to use function available in
igc.h.



^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: MPS image cache
  2024-05-05 17:45                               ` Gerd Möllmann
@ 2024-05-05 18:04                                 ` Eli Zaretskii
  2024-05-05 18:13                                   ` Eli Zaretskii
  0 siblings, 1 reply; 70+ messages in thread
From: Eli Zaretskii @ 2024-05-05 18:04 UTC (permalink / raw)
  To: Gerd Möllmann; +Cc: eller.helmut, emacs-devel

> From: Gerd Möllmann <gerd.moellmann@gmail.com>
> Cc: eller.helmut@gmail.com,  emacs-devel@gnu.org
> Date: Sun, 05 May 2024 19:45:03 +0200
> 
> @@ -2978,7 +2977,8 @@ igc_make_face_cache (void)
>  void *
>  igc_make_ptr_vec (size_t n)
>  {
> -  return alloc (n * sizeof (void *), IGC_OBJ_PTR_VEC, PVEC_FREE);
> +  return alloc (sizeof (struct igc_header) + (n - 1) * sizeof (void *),
> +		IGC_OBJ_PTR_VEC, PVEC_FREE);
>  }
>  
> what you removed was correct because alloc takes the size in bytes to
> allocate from the POV of the client.
> 
> Alloc computes the size needed from MPS
> 
>   size = obj_size (size);
> 
> which includes the header among other things.

Thanks, I tried to fix that now.



^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: MPS: scroll-bars
  2024-05-05 18:02                         ` Helmut Eller
@ 2024-05-05 18:09                           ` Eli Zaretskii
  2024-05-06 15:05                             ` Eli Zaretskii
  0 siblings, 1 reply; 70+ messages in thread
From: Eli Zaretskii @ 2024-05-05 18:09 UTC (permalink / raw)
  To: Helmut Eller; +Cc: gerd.moellmann, luangruo, emacs-devel

> From: Helmut Eller <eller.helmut@gmail.com>
> Cc: gerd.moellmann@gmail.com,  luangruo@yahoo.com,  emacs-devel@gnu.org
> Date: Sun, 05 May 2024 20:02:13 +0200
> 
> On Sun, May 05 2024, Eli Zaretskii wrote:
> 
> > Can you tell, for my own education, what does a call to
> > igc_xzalloc_ambig give us, as opposed to just xzalloc?
> 
> igc_xzalloc_ambig allocates memory like xzalloc but it addition
> registers it as root.  When MPS starts scanning, it begins from the
> roots.  That means, we are sure that the referenced objects stay alive.
> In the case of ambiguous references, the objects are also pinned
> (i.e. don't move).
> 
> That pinning part is not necessary for the scroll-bar case, but
> igc_xzalloc_ambig is currently the easiest to use function available in
> igc.h.

Thanks, I think I get this.



^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: MPS image cache
  2024-05-05 18:04                                 ` Eli Zaretskii
@ 2024-05-05 18:13                                   ` Eli Zaretskii
  2024-05-05 18:35                                     ` Gerd Möllmann
  0 siblings, 1 reply; 70+ messages in thread
From: Eli Zaretskii @ 2024-05-05 18:13 UTC (permalink / raw)
  To: gerd.moellmann; +Cc: eller.helmut, emacs-devel

> > Alloc computes the size needed from MPS
> > 
> >   size = obj_size (size);
> > 
> > which includes the header among other things.
> 
> Thanks, I tried to fix that now.

Or maybe it's preferable to use

      size_t imax = h->nwords - to_words (sizeof (struct igc_header));

instead (assuming that mps_word_t and 'void *' must be of the same
size)?



^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: MPS image cache
  2024-05-05 18:13                                   ` Eli Zaretskii
@ 2024-05-05 18:35                                     ` Gerd Möllmann
  2024-05-05 19:18                                       ` Eli Zaretskii
  0 siblings, 1 reply; 70+ messages in thread
From: Gerd Möllmann @ 2024-05-05 18:35 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: eller.helmut, emacs-devel

Eli Zaretskii <eliz@gnu.org> writes:

>> > Alloc computes the size needed from MPS
>> > 
>> >   size = obj_size (size);
>> > 
>> > which includes the header among other things.
>> 
>> Thanks, I tried to fix that now.
>
> Or maybe it's preferable to use
>
>       size_t imax = h->nwords - to_words (sizeof (struct igc_header));
>
> instead (assuming that mps_word_t and 'void *' must be of the same
> size)?

Yes, I think that looks best.



^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: MPS image cache
  2024-05-05 18:35                                     ` Gerd Möllmann
@ 2024-05-05 19:18                                       ` Eli Zaretskii
  2024-05-05 19:57                                         ` Gerd Möllmann
  0 siblings, 1 reply; 70+ messages in thread
From: Eli Zaretskii @ 2024-05-05 19:18 UTC (permalink / raw)
  To: Gerd Möllmann; +Cc: eller.helmut, emacs-devel

> From: Gerd Möllmann <gerd.moellmann@gmail.com>
> Cc: eller.helmut@gmail.com,  emacs-devel@gnu.org
> Date: Sun, 05 May 2024 20:35:48 +0200
> 
> Eli Zaretskii <eliz@gnu.org> writes:
> 
> > Or maybe it's preferable to use
> >
> >       size_t imax = h->nwords - to_words (sizeof (struct igc_header));
> >
> > instead (assuming that mps_word_t and 'void *' must be of the same
> > size)?
> 
> Yes, I think that looks best.

Done.



^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: MPS image cache
  2024-05-05 19:18                                       ` Eli Zaretskii
@ 2024-05-05 19:57                                         ` Gerd Möllmann
  0 siblings, 0 replies; 70+ messages in thread
From: Gerd Möllmann @ 2024-05-05 19:57 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: eller.helmut, emacs-devel

Thanks
Sent from my iPhone

> On 5. May 2024, at 21:19, Eli Zaretskii <eliz@gnu.org> wrote:
> 
> 
>> 
>> From: Gerd Möllmann <gerd.moellmann@gmail.com>
>> Cc: eller.helmut@gmail.com,  emacs-devel@gnu.org
>> Date: Sun, 05 May 2024 20:35:48 +0200
>> 
>> Eli Zaretskii <eliz@gnu.org> writes:
>> 
>>> Or maybe it's preferable to use
>>> 
>>>      size_t imax = h->nwords - to_words (sizeof (struct igc_header));
>>> 
>>> instead (assuming that mps_word_t and 'void *' must be of the same
>>> size)?
>> 
>> Yes, I think that looks best.
> 
> Done.



^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: MPS image cache
  2024-05-05  8:42             ` Gerd Möllmann
@ 2024-05-06 14:16               ` Helmut Eller
  2024-05-06 14:28                 ` Gerd Möllmann
  0 siblings, 1 reply; 70+ messages in thread
From: Helmut Eller @ 2024-05-06 14:16 UTC (permalink / raw)
  To: Gerd Möllmann; +Cc: Eli Zaretskii, Emacs Devel

[-- Attachment #1: Type: text/plain, Size: 688 bytes --]

On Sun, May 05 2024, Gerd Möllmann wrote:

>> Would something like this also be needed for glyph matrices?  
>
> Probably. Either we make the matrices roots, or objects, I guess. For
> correctness. We can't easily realloc when they are objects, but I don't
> think that's a big problem.
>
>> Or in general, can we scan anything other than the block that
>> dflt_scan was called with? 
>
> Let's say we shouldn't :-). MPS lets us scan memory it doesn't manage,
> but with multi-threading it's not really safe.

So fix_glyph_matrix currently doesn't things exactly by the book.  Hm.

Anyway, I have a patch that prevents my Emacs from sporadically crashing
at startup.


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: 0001-Zero-out-terminal-keyboard_coding.patch --]
[-- Type: text/x-diff, Size: 1342 bytes --]

From eda36223e8062337cd40c97471749c519fcc7b9b Mon Sep 17 00:00:00 2001
From: Helmut Eller <eller.helmut@gmail.com>
Date: Mon, 6 May 2024 10:07:14 +0200
Subject: [PATCH] Zero out terminal->keyboard_coding

This avoids hard to reproduce crashes in fix_coding.

* src/terminal.c (create_terminal): Use xzalloc instead of
xmalloc.
---
 src/terminal.c | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/src/terminal.c b/src/terminal.c
index 23a5582d4d9..33f8623c214 100644
--- a/src/terminal.c
+++ b/src/terminal.c
@@ -24,6 +24,9 @@
 #include "termchar.h"
 #include "termhooks.h"
 #include "keyboard.h"
+#ifdef HAVE_MPS
+#include "igc.h"
+#endif
 
 #if HAVE_STRUCT_UNIPAIR_UNICODE
 # include <errno.h>
@@ -281,8 +284,13 @@ create_terminal (enum output_method type, struct redisplay_interface *rif)
   terminal->rif = rif;
   terminal->id = next_terminal_id++;
 
+#ifdef HAVE_MPS
+  terminal->keyboard_coding = xzalloc (sizeof (struct coding_system));
+  terminal->terminal_coding = xzalloc (sizeof (struct coding_system));
+#else
   terminal->keyboard_coding = xmalloc (sizeof (struct coding_system));
   terminal->terminal_coding = xmalloc (sizeof (struct coding_system));
+#endif
 
   /* If default coding systems for the terminal and the keyboard are
      already defined, use them in preference to the defaults.  This is
-- 
2.39.2


^ permalink raw reply related	[flat|nested] 70+ messages in thread

* Re: MPS image cache
  2024-05-06 14:16               ` Helmut Eller
@ 2024-05-06 14:28                 ` Gerd Möllmann
  0 siblings, 0 replies; 70+ messages in thread
From: Gerd Möllmann @ 2024-05-06 14:28 UTC (permalink / raw)
  To: Helmut Eller; +Cc: Eli Zaretskii, Emacs Devel

Helmut Eller <eller.helmut@gmail.com> writes:

> Anyway, I have a patch that prevents my Emacs from sporadically crashing
> at startup.

Pushed. Thanks Helmut!



^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: MPS: scroll-bars
  2024-05-05 18:09                           ` Eli Zaretskii
@ 2024-05-06 15:05                             ` Eli Zaretskii
  2024-05-06 15:53                               ` Gerd Möllmann
  0 siblings, 1 reply; 70+ messages in thread
From: Eli Zaretskii @ 2024-05-06 15:05 UTC (permalink / raw)
  To: eller.helmut, gerd.moellmann; +Cc: emacs-devel

> Date: Sun, 05 May 2024 21:09:53 +0300
> From: Eli Zaretskii <eliz@gnu.org>
> Cc: gerd.moellmann@gmail.com, luangruo@yahoo.com, emacs-devel@gnu.org
> 
> > From: Helmut Eller <eller.helmut@gmail.com>
> > Cc: gerd.moellmann@gmail.com,  luangruo@yahoo.com,  emacs-devel@gnu.org
> > Date: Sun, 05 May 2024 20:02:13 +0200
> > 
> > On Sun, May 05 2024, Eli Zaretskii wrote:
> > 
> > > Can you tell, for my own education, what does a call to
> > > igc_xzalloc_ambig give us, as opposed to just xzalloc?
> > 
> > igc_xzalloc_ambig allocates memory like xzalloc but it addition
> > registers it as root.  When MPS starts scanning, it begins from the
> > roots.  That means, we are sure that the referenced objects stay alive.
> > In the case of ambiguous references, the objects are also pinned
> > (i.e. don't move).
> > 
> > That pinning part is not necessary for the scroll-bar case, but
> > igc_xzalloc_ambig is currently the easiest to use function available in
> > igc.h.
> 
> Thanks, I think I get this.

Btw, did we decide what to do with these chains:

  struct frame
  {
  [...]
  /* List of scroll bars on this frame.
     Actually, we don't specify exactly what is stored here at all; the
     scroll bar implementation code can use it to store anything it likes.
     This field is marked by the garbage collector.  It is here
     instead of in the `device' structure so that the garbage
     collector doesn't need to look inside the window-system-dependent
     structure.  */
  Lisp_Object scroll_bars;
  Lisp_Object condemned_scroll_bars;

They are doubly-linked lists via the ->next and ->prev fields in the C
'struct scroll_bar', in X as well as w32, see XSCROLL_BAR.  The
Lisp_Object's above are the last scroll bar on the frame's windows,
and the rest are reachable via the ->next and ->prev pointers.  Do we
need to do anything about those ->next and ->prev pointers?



^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: MPS: scroll-bars
  2024-05-06 15:05                             ` Eli Zaretskii
@ 2024-05-06 15:53                               ` Gerd Möllmann
  2024-05-06 18:25                                 ` Eli Zaretskii
  0 siblings, 1 reply; 70+ messages in thread
From: Gerd Möllmann @ 2024-05-06 15:53 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: eller.helmut, emacs-devel

Eli Zaretskii <eliz@gnu.org> writes:

>> Date: Sun, 05 May 2024 21:09:53 +0300
>> From: Eli Zaretskii <eliz@gnu.org>
>> Cc: gerd.moellmann@gmail.com, luangruo@yahoo.com, emacs-devel@gnu.org
>> 
>> > From: Helmut Eller <eller.helmut@gmail.com>
>> > Cc: gerd.moellmann@gmail.com,  luangruo@yahoo.com,  emacs-devel@gnu.org
>> > Date: Sun, 05 May 2024 20:02:13 +0200
>> > 
>> > On Sun, May 05 2024, Eli Zaretskii wrote:
>> > 
>> > > Can you tell, for my own education, what does a call to
>> > > igc_xzalloc_ambig give us, as opposed to just xzalloc?
>> > 
>> > igc_xzalloc_ambig allocates memory like xzalloc but it addition
>> > registers it as root.  When MPS starts scanning, it begins from the
>> > roots.  That means, we are sure that the referenced objects stay alive.
>> > In the case of ambiguous references, the objects are also pinned
>> > (i.e. don't move).
>> > 
>> > That pinning part is not necessary for the scroll-bar case, but
>> > igc_xzalloc_ambig is currently the easiest to use function available in
>> > igc.h.
>> 
>> Thanks, I think I get this.
>
> Btw, did we decide what to do with these chains:
>
>   struct frame
>   {
>   [...]
>   /* List of scroll bars on this frame.
>      Actually, we don't specify exactly what is stored here at all; the
>      scroll bar implementation code can use it to store anything it likes.
>      This field is marked by the garbage collector.  It is here
>      instead of in the `device' structure so that the garbage
>      collector doesn't need to look inside the window-system-dependent
>      structure.  */
>   Lisp_Object scroll_bars;
>   Lisp_Object condemned_scroll_bars;
>
> They are doubly-linked lists via the ->next and ->prev fields in the C
> 'struct scroll_bar', in X as well as w32, see XSCROLL_BAR.  The
> Lisp_Object's above are the last scroll bar on the frame's windows,
> and the rest are reachable via the ->next and ->prev pointers.  Do we
> need to do anything about those ->next and ->prev pointers?

For NS, and I must always add that I don't know NS at all, the
condemned_scroll_bars are fine I think. NS sets a flag in an NS
EmacsScroller object to condemn/redeem it, and doesn't use the frame's
field, says clangd.

The scroll_bars field was something strange. It didn't contain struct
scroll_bars but someting like optimized Lisp_Misc_Ptrs (see
xmint_pointer in lisp.h) which point to EmacsScrollers.

In summary, I came for NS to the conclusion that we should be good with
what we currently have. Famous last words.



^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: MPS: scroll-bars
  2024-05-06 15:53                               ` Gerd Möllmann
@ 2024-05-06 18:25                                 ` Eli Zaretskii
  2024-05-07  6:07                                   ` Helmut Eller
  0 siblings, 1 reply; 70+ messages in thread
From: Eli Zaretskii @ 2024-05-06 18:25 UTC (permalink / raw)
  To: eller.helmut, Gerd Möllmann; +Cc: emacs-devel

> From: Gerd Möllmann <gerd.moellmann@gmail.com>
> Cc: eller.helmut@gmail.com,  emacs-devel@gnu.org
> Date: Mon, 06 May 2024 17:53:40 +0200
> 
> Eli Zaretskii <eliz@gnu.org> writes:
> 
> > Btw, did we decide what to do with these chains:
> >
> >   struct frame
> >   {
> >   [...]
> >   /* List of scroll bars on this frame.
> >      Actually, we don't specify exactly what is stored here at all; the
> >      scroll bar implementation code can use it to store anything it likes.
> >      This field is marked by the garbage collector.  It is here
> >      instead of in the `device' structure so that the garbage
> >      collector doesn't need to look inside the window-system-dependent
> >      structure.  */
> >   Lisp_Object scroll_bars;
> >   Lisp_Object condemned_scroll_bars;
> >
> > They are doubly-linked lists via the ->next and ->prev fields in the C
> > 'struct scroll_bar', in X as well as w32, see XSCROLL_BAR.  The
> > Lisp_Object's above are the last scroll bar on the frame's windows,
> > and the rest are reachable via the ->next and ->prev pointers.  Do we
> > need to do anything about those ->next and ->prev pointers?
> 
> For NS, and I must always add that I don't know NS at all, the
> condemned_scroll_bars are fine I think. NS sets a flag in an NS
> EmacsScroller object to condemn/redeem it, and doesn't use the frame's
> field, says clangd.
> 
> The scroll_bars field was something strange. It didn't contain struct
> scroll_bars but someting like optimized Lisp_Misc_Ptrs (see
> xmint_pointer in lisp.h) which point to EmacsScrollers.
> 
> In summary, I came for NS to the conclusion that we should be good with
> what we currently have. Famous last words.

Helmut, WDYT about the scroll bars on X (and by extension on w32)?



^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: MPS: scroll-bars
  2024-05-06 18:25                                 ` Eli Zaretskii
@ 2024-05-07  6:07                                   ` Helmut Eller
  2024-05-07 12:56                                     ` Eli Zaretskii
  0 siblings, 1 reply; 70+ messages in thread
From: Helmut Eller @ 2024-05-07  6:07 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: Gerd Möllmann, emacs-devel

On Mon, May 06 2024, Eli Zaretskii wrote:

>> > Btw, did we decide what to do with these chains:
>> >
>> >   struct frame
>> >   {
>> >   [...]
>> >   /* List of scroll bars on this frame.
>> >      Actually, we don't specify exactly what is stored here at all; the
>> >      scroll bar implementation code can use it to store anything it likes.
>> >      This field is marked by the garbage collector.  It is here
>> >      instead of in the `device' structure so that the garbage
>> >      collector doesn't need to look inside the window-system-dependent
>> >      structure.  */
>> >   Lisp_Object scroll_bars;
>> >   Lisp_Object condemned_scroll_bars;
>> >
>> > They are doubly-linked lists via the ->next and ->prev fields in the C
>> > 'struct scroll_bar', in X as well as w32, see XSCROLL_BAR.  The
>> > Lisp_Object's above are the last scroll bar on the frame's windows,
>> > and the rest are reachable via the ->next and ->prev pointers.  Do we
>> > need to do anything about those ->next and ->prev pointers?
[...]
> Helmut, WDYT about the scroll bars on X (and by extension on w32)?

On X, the struct scroll_bar is allocated as a PVEC_OTHER pseudovector.
And I think the next/prev links are traced because of that.
xterm.c:mark_xterm doesn't do anything special for scrollbars, so I
think it's all covered.  The only complication so far was that a struct
scroll_bar* was handed to GTK that was not traced; after I turned that
into a root with a pointer to the scroll_bar* it is traced.



^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: MPS: scroll-bars
  2024-05-07  6:07                                   ` Helmut Eller
@ 2024-05-07 12:56                                     ` Eli Zaretskii
  2024-05-07 16:27                                       ` Helmut Eller
  0 siblings, 1 reply; 70+ messages in thread
From: Eli Zaretskii @ 2024-05-07 12:56 UTC (permalink / raw)
  To: Helmut Eller; +Cc: gerd.moellmann, emacs-devel

> From: Helmut Eller <eller.helmut@gmail.com>
> Cc: Gerd Möllmann <gerd.moellmann@gmail.com>,
>   emacs-devel@gnu.org
> Date: Tue, 07 May 2024 08:07:04 +0200
> 
> On Mon, May 06 2024, Eli Zaretskii wrote:
> 
> >> > Btw, did we decide what to do with these chains:
> >> >
> >> >   struct frame
> >> >   {
> >> >   [...]
> >> >   /* List of scroll bars on this frame.
> >> >      Actually, we don't specify exactly what is stored here at all; the
> >> >      scroll bar implementation code can use it to store anything it likes.
> >> >      This field is marked by the garbage collector.  It is here
> >> >      instead of in the `device' structure so that the garbage
> >> >      collector doesn't need to look inside the window-system-dependent
> >> >      structure.  */
> >> >   Lisp_Object scroll_bars;
> >> >   Lisp_Object condemned_scroll_bars;
> >> >
> >> > They are doubly-linked lists via the ->next and ->prev fields in the C
> >> > 'struct scroll_bar', in X as well as w32, see XSCROLL_BAR.  The
> >> > Lisp_Object's above are the last scroll bar on the frame's windows,
> >> > and the rest are reachable via the ->next and ->prev pointers.  Do we
> >> > need to do anything about those ->next and ->prev pointers?
> [...]
> > Helmut, WDYT about the scroll bars on X (and by extension on w32)?
> 
> On X, the struct scroll_bar is allocated as a PVEC_OTHER pseudovector.

Likewise on w32.

> And I think the next/prev links are traced because of that.
> xterm.c:mark_xterm doesn't do anything special for scrollbars, so I
> think it's all covered.

So any C pointers within a Lisp object allocated via MPS are
automatically traced and fixed when the object is moved?

> The only complication so far was that a struct
> scroll_bar* was handed to GTK that was not traced; after I turned that
> into a root with a pointer to the scroll_bar* it is traced.

Is this the only/best way of making a structure pinned?  If there are
others, what are they?  I wonder if there's a more elegant technique
than to use indirection.  E.g., can't I tell MPS somehow that a Lisp
object allocated as PVEC_OTHER pseudovector is pinned?

See, on w32 the pointer to 'struct scroll_bar' is handed to the UI
thread (via a message with parameters), which uses it to tell the
MS-Windows GUI system how to create the scroll bar (which is just a
special kind of window, as far as MS-Windows is concerned).  So I
think the 'struct scroll_bar' must not be allowed to be moved on w32,
because if it does, the UI thread will dereference invalid pointers.



^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: MPS: scroll-bars
  2024-05-07 12:56                                     ` Eli Zaretskii
@ 2024-05-07 16:27                                       ` Helmut Eller
  0 siblings, 0 replies; 70+ messages in thread
From: Helmut Eller @ 2024-05-07 16:27 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: gerd.moellmann, emacs-devel

On Tue, May 07 2024, Eli Zaretskii wrote:

>> And I think the next/prev links are traced because of that.
>> xterm.c:mark_xterm doesn't do anything special for scrollbars, so I
>> think it's all covered.
>
> So any C pointers within a Lisp object allocated via MPS are
> automatically traced and fixed when the object is moved?

Automatically is perhaps an overstatement.  For pseudovectors, the
function fix_vectorlike does most of the work.

>> The only complication so far was that a struct
>> scroll_bar* was handed to GTK that was not traced; after I turned that
>> into a root with a pointer to the scroll_bar* it is traced.
>
> Is this the only/best way of making a structure pinned?  If there are
> others, what are they?  I wonder if there's a more elegant technique
> than to use indirection.  E.g., can't I tell MPS somehow that a Lisp
> object allocated as PVEC_OTHER pseudovector is pinned?

One other way would be to allocate objects in the mark-and-sweep pool.
But we haven't decided yet whether that's worth the trouble.

> See, on w32 the pointer to 'struct scroll_bar' is handed to the UI
> thread (via a message with parameters), which uses it to tell the
> MS-Windows GUI system how to create the scroll bar (which is just a
> special kind of window, as far as MS-Windows is concerned).  So I
> think the 'struct scroll_bar' must not be allowed to be moved on w32,
> because if it does, the UI thread will dereference invalid pointers.

This doesn't sound all that different from the situation I had with GTK.




^ permalink raw reply	[flat|nested] 70+ messages in thread

end of thread, other threads:[~2024-05-07 16:27 UTC | newest]

Thread overview: 70+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2024-05-03  8:53 MPS image cache Gerd Möllmann
2024-05-03 10:58 ` Helmut Eller
2024-05-03 11:05   ` Po Lu
2024-05-03 11:22   ` Gerd Möllmann
2024-05-03 11:43     ` Gerd Möllmann
2024-05-03 13:24       ` Gerd Möllmann
2024-05-03 17:02         ` Gerd Möllmann
2024-05-04  4:38           ` MPS: scroll-bars (was: MPS image cache) Helmut Eller
2024-05-04  5:22             ` MPS: scroll-bars Gerd Möllmann
2024-05-04  5:29               ` Gerd Möllmann
2024-05-04  5:50             ` Po Lu
2024-05-04  6:27               ` Helmut Eller
2024-05-04  6:45                 ` Gerd Möllmann
2024-05-04  7:05                   ` Helmut Eller
2024-05-04  7:13                     ` Gerd Möllmann
2024-05-04  7:48                       ` Gerd Möllmann
2024-05-04  7:09                   ` Gerd Möllmann
2024-05-04  8:47                     ` Eli Zaretskii
2024-05-04  9:13                       ` Gerd Möllmann
2024-05-04  9:29                         ` Eli Zaretskii
2024-05-04 10:04                           ` Gerd Möllmann
2024-05-04 13:59                             ` MPS: w32 threads Eli Zaretskii
2024-05-04 14:20                               ` Gerd Möllmann
2024-05-05  8:27                                 ` Eli Zaretskii
2024-05-05  9:16                                   ` Gerd Möllmann
2024-05-05 14:39                                     ` Eli Zaretskii
2024-05-05 15:23                                       ` Gerd Möllmann
2024-05-05 15:26                                         ` Gerd Möllmann
2024-05-04  8:29                 ` MPS: scroll-bars Po Lu
2024-05-05  4:52                   ` Gerd Möllmann
2024-05-05  7:53                     ` Helmut Eller
2024-05-05  8:01                       ` Gerd Möllmann
2024-05-05  8:08                         ` Helmut Eller
2024-05-05 16:43                       ` Eli Zaretskii
2024-05-05 18:02                         ` Helmut Eller
2024-05-05 18:09                           ` Eli Zaretskii
2024-05-06 15:05                             ` Eli Zaretskii
2024-05-06 15:53                               ` Gerd Möllmann
2024-05-06 18:25                                 ` Eli Zaretskii
2024-05-07  6:07                                   ` Helmut Eller
2024-05-07 12:56                                     ` Eli Zaretskii
2024-05-07 16:27                                       ` Helmut Eller
2024-05-03 14:59     ` MPS image cache Helmut Eller
2024-05-03 15:11       ` Gerd Möllmann
2024-05-05  6:45         ` Gerd Möllmann
2024-05-05  7:02           ` Gerd Möllmann
2024-05-05  9:00             ` Eli Zaretskii
2024-05-05  9:31               ` Gerd Möllmann
2024-05-05 10:24                 ` Eli Zaretskii
2024-05-05 10:36                   ` Gerd Möllmann
2024-05-05 11:01                     ` Eli Zaretskii
2024-05-05 12:55                       ` Gerd Möllmann
2024-05-05 14:07                         ` Eli Zaretskii
2024-05-05 14:32                           ` Gerd Möllmann
2024-05-05 15:49                             ` Eli Zaretskii
2024-05-05 16:19                               ` Gerd Möllmann
2024-05-05 17:45                               ` Gerd Möllmann
2024-05-05 18:04                                 ` Eli Zaretskii
2024-05-05 18:13                                   ` Eli Zaretskii
2024-05-05 18:35                                     ` Gerd Möllmann
2024-05-05 19:18                                       ` Eli Zaretskii
2024-05-05 19:57                                         ` Gerd Möllmann
2024-05-05  8:16           ` Helmut Eller
2024-05-05  8:42             ` Gerd Möllmann
2024-05-06 14:16               ` Helmut Eller
2024-05-06 14:28                 ` Gerd Möllmann
2024-05-03 15:02     ` Helmut Eller
2024-05-04 17:51       ` Gerd Möllmann
2024-05-03 11:04 ` Eli Zaretskii
2024-05-03 11:08   ` Gerd Möllmann

Code repositories for project(s) associated with this public inbox

	https://git.savannah.gnu.org/cgit/emacs.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).