Subject: bug#72496: 31.0.50; macOS: freezes without beach ball

From: Gerd Möllmann <[email-masked]>
Date: Thu, 08 Aug 2024 07:24:57 +0200

Gerd Möllmann <[email-masked]> writes:

> Eli Zaretskii <[email-masked]> writes:
>
>>> From: Gerd Möllmann <[email-masked]>
>>> Cc: [email-masked]
>>> Date: Tue, 06 Aug 2024 18:36:39 +0200
>>> 
>>> I've tried this
>>> 
>>>   (when (fboundp 'ns-app-stop)
>>>     (defun sigusr1-handler ()
>>>       (interactive)
>>>       (message "SIGUSR1 - stop event loop")
>>>       (ns-app-stop))
>>>     (keymap-set special-event-map "<sigusr1>" 'sigusr1-handler))
>>> 
>>> where ns-app-stop does such a ns_send_appdefined, but that didn't work
>>> for a reason unknown to me.
>>
>> Maybe the way SIGUSR1 is handled involves the same event queue that is
>> botched in this scenario?
>
> Yes, that's quite likely. I had a little hope that a signal would maybe
> handled in some special way, but apparently not.

I'm now running locally with the attached change. This removes the
global variable that can prevent sending app-defined events when set
wrong. Instead, I'm using [NSApplication nextEventMatchingMask] to check
if an app-defined event has already been posted. This is infinelty less
dangerous.

Let's see if that is the problem.

>From f48aafd73c7d2694bf2c9e980e9624bde9ab3b3e Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Gerd=20M=C3=B6llmann?= <[email-masked]>
Date: Thu, 8 Aug 2024 06:57:21 +0200
Subject: [PATCH] NS: Send application-defined event differently (bug#72496)

* src/nsterm.m (send_appdefined): Global variable removed, all uses
removed.
(ns_send_appdefined): Check if an application-defined event is already
queued with [NSApplicaton nextEventMatching]. Post an event if not.
---
 src/nsterm.m | 26 ++++++++++----------------
 1 file changed, 10 insertions(+), 16 deletions(-)

diff --git a/src/nsterm.m b/src/nsterm.m
index 5588425686b..594f7ba974b 100644
--- a/src/nsterm.m
+++ b/src/nsterm.m
@@ -309,7 +309,6 @@ - (unsigned long)unsignedLong
 #endif
 
 /* event loop */
-static BOOL send_appdefined = YES;
 #define NO_APPDEFINED_DATA (-8)
 static int last_appdefined_event_data = NO_APPDEFINED_DATA;
 static NSTimer *timed_entry = 0;
@@ -507,7 +506,6 @@ - (unsigned long)unsignedLong
   hold_event_q.q[hold_event_q.nr++] = *event;
   /* Make sure ns_read_socket is called, i.e. we have input.  */
   raise (SIGIO);
-  send_appdefined = YES;
 }
 
 static Lisp_Object
@@ -4689,13 +4687,17 @@ Function modeled after x_draw_glyph_string_box ().
   /* Only post this event if we haven't already posted one.  This will end
      the [NXApp run] main loop after having processed all events queued at
      this moment.  */
-  if (send_appdefined || value == -42)
+
+  NSEvent *app_defined_event =
+    [NSApp nextEventMatchingMask: NSEventMaskApplicationDefined
+		       untilDate: nil
+			  inMode: NSDefaultRunLoopMode
+			 dequeue: NO];
+
+  if (app_defined_event == nil)
     {
       NSEvent *nxev;
 
-      /* We only need one NX_APPDEFINED event to stop NXApp from running.  */
-      send_appdefined = NO;
-
       /* Don't need wakeup timer any more.  */
       if (timed_entry)
         {
@@ -4812,7 +4814,6 @@ Function modeled after x_draw_glyph_string_box ().
         {
           /* Run and wait for events.  We must always send one NX_APPDEFINED event
              to ourself, otherwise [NXApp run] will never exit.  */
-          send_appdefined = YES;
           ns_send_appdefined (-1);
 
           [NSApp run];
@@ -4907,7 +4908,6 @@ Function modeled after x_draw_glyph_string_box ().
   // outerpool = [[NSAutoreleasePool alloc] init];

-  send_appdefined = YES;
   if (nr > 0)
     {
       pthread_mutex_lock (&select_mutex);
@@ -4951,7 +4951,6 @@ Function modeled after x_draw_glyph_string_box ().
   else /* No timeout and no file descriptors, can this happen?  */
     {
       /* Send appdefined so we exit from the loop.  */
-      ns_send_appdefined (-1);
     }
 
   block_input ();
@@ -6051,10 +6050,6 @@ - (void)sendEvent: (NSEvent *)theEvent
           last_appdefined_event_data = [theEvent data1];
           [self stop: self];
         }
-      else
-        {
-          send_appdefined = YES;
-        }
     }

@@ -7727,7 +7722,7 @@ - (void)mouseMoved: (NSEvent *)e
                       help_echo_object, help_echo_pos);
     }
 
-  if ((*emacsframe)->mouse_moved && send_appdefined)
+  if ((*emacsframe)->mouse_moved)
     ns_send_appdefined (-1);
 }
 
@@ -8336,8 +8331,7 @@ - (void)windowDidExpose: sender
   SET_FRAME_VISIBLE (*emacsframe, 1);
   SET_FRAME_GARBAGED (*emacsframe);
 
-  if (send_appdefined)
-    ns_send_appdefined (-1);
+  ns_send_appdefined (-1);
 }

-- 
2.46.0