all messages for Emacs-related lists mirrored at yhetil.org
 help / color / mirror / code / Atom feed
* bug#72496: 31.0.50; macOS: freezes without beach ball
@ 2024-08-06 13:39 Gerd Möllmann
  2024-08-06 14:53 ` Eli Zaretskii
  0 siblings, 1 reply; 7+ messages in thread
From: Gerd Möllmann @ 2024-08-06 13:39 UTC (permalink / raw)
  To: 72496

In GNU Emacs 31.0.50 (build 1, aarch64-apple-darwin23.6.0, NS
 appkit-2487.70 Version 14.6 (Build 23G80)) of 2024-08-05 built on
 pro2.fritz.box
Repository revision: c7d9cd722e5a7042a52c92f8497f903bfe9870b8

This is one of the problems on macOS that I'm experiencing quite
often. I have no idea what is causing this, and I haven't found a way
to make it reproducible. I guess I should file a bug report anyway.

Let me first try to describe briefly how NS GUI event handling works
in Emacs.

The whole story starts with get_input_pending which calls gobble_input
which calls a terminal's read_socket_hook, which is ns_read_socket in
macOS. ns_read_socket calls [NSApplication run] to process macOS GUI
events.

The problem starts with [NSApplication run] being an endless loop that
gets the next event, and dispatches it by calling the application's
sendEvent method. The only way to make the run loop terminate is by
calling [NSApplication stop]. This sets a flag that [NSApplicatoin
run] is supposed to check and then return, so that we eventually
return to ns_read_socket.

We call [NSApplicaton stop] in our [EmacsApp sendEvent] method. To get
there, we post special application-defined events to the application
which [NSApplication run] processes and dispatches via sendEvent which
calls stop and makes [NSApplication run] return to its caller. Note
that stop only sets a flag, so we need to process another event to
make run terminate. That's at least my understanding.

We are posting these events all over the place, not only before
ns_read_socket calls [NSApplication run]. And, to complicate matters,
whether or not ns_send_appdefined actually posts an event depends on a
global boolean variable. IOW, it's impenetrable.

(I'm also leaving out the generation of input_events for Emacs here,
which is another can of worms.)

Problem is that this not always works. More specifically, this code in
ns_read_socket_1

          /* 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];

gets stuck in the GUI event loop, and the last line never returns. The
effect being that Emacs freezes without a beach ball of death. It
processes Cocoa events but Emacs never sees any input_events.





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

* bug#72496: 31.0.50; macOS: freezes without beach ball
  2024-08-06 13:39 bug#72496: 31.0.50; macOS: freezes without beach ball Gerd Möllmann
@ 2024-08-06 14:53 ` Eli Zaretskii
  2024-08-06 16:36   ` Gerd Möllmann
  0 siblings, 1 reply; 7+ messages in thread
From: Eli Zaretskii @ 2024-08-06 14:53 UTC (permalink / raw)
  To: Gerd Möllmann; +Cc: 72496

> From: Gerd Möllmann <gerd.moellmann@gmail.com>
> Date: Tue, 06 Aug 2024 15:39:43 +0200
> 
> We call [NSApplicaton stop] in our [EmacsApp sendEvent] method. To get
> there, we post special application-defined events to the application
> which [NSApplication run] processes and dispatches via sendEvent which
> calls stop and makes [NSApplication run] return to its caller.

Is there any way to initiate posting that "special application-defined
event" when Emacs is stuck thusly?  For example, from some system
signal-like event, or from a debugger?  Then you at least would have a
fire escape.





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

* bug#72496: 31.0.50; macOS: freezes without beach ball
  2024-08-06 14:53 ` Eli Zaretskii
@ 2024-08-06 16:36   ` Gerd Möllmann
  2024-08-06 18:04     ` Eli Zaretskii
  0 siblings, 1 reply; 7+ messages in thread
From: Gerd Möllmann @ 2024-08-06 16:36 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: 72496

Eli Zaretskii <eliz@gnu.org> writes:

>> From: Gerd Möllmann <gerd.moellmann@gmail.com>
>> Date: Tue, 06 Aug 2024 15:39:43 +0200
>> 
>> We call [NSApplicaton stop] in our [EmacsApp sendEvent] method. To get
>> there, we post special application-defined events to the application
>> which [NSApplication run] processes and dispatches via sendEvent which
>> calls stop and makes [NSApplication run] return to its caller.
>
> Is there any way to initiate posting that "special application-defined
> event" when Emacs is stuck thusly?  For example, from some system
> signal-like event, or from a debugger?  Then you at least would have a
> fire escape.

Running under LLDB I can do something, with a little code change in
ns_send_appdefined.

  (lldb) expr ns_send_appdefined(-42)

where I let -42 force posting an event, ignoring the global variable I
mentioned, send_appdefined, that prevents the posting. Sometimes I have
to do that twice before Emacs receives key strokes again. And it seems
something is also broken afterwards, for example the cursor stops
blinking, tooltips don't work and such things. But at least one can save
buffers and exit.

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. I also tried to do that in the signal
handler directly, but couldn't make it work either.

BTW, there are also freezes with beach ball, where the situation seems
to be reversed, i.e. for some reason [NSApplication run] seems to no
longer processing events, hence the beach ball. I haven't event a theory
what that could oossibly be caused by.





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

* bug#72496: 31.0.50; macOS: freezes without beach ball
  2024-08-06 16:36   ` Gerd Möllmann
@ 2024-08-06 18:04     ` Eli Zaretskii
  2024-08-06 18:37       ` Gerd Möllmann
  0 siblings, 1 reply; 7+ messages in thread
From: Eli Zaretskii @ 2024-08-06 18:04 UTC (permalink / raw)
  To: Gerd Möllmann; +Cc: 72496

> From: Gerd Möllmann <gerd.moellmann@gmail.com>
> Cc: 72496@debbugs.gnu.org
> 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?





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

* bug#72496: 31.0.50; macOS: freezes without beach ball
  2024-08-06 18:04     ` Eli Zaretskii
@ 2024-08-06 18:37       ` Gerd Möllmann
  2024-08-08  5:24         ` Gerd Möllmann
  0 siblings, 1 reply; 7+ messages in thread
From: Gerd Möllmann @ 2024-08-06 18:37 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: 72496

Eli Zaretskii <eliz@gnu.org> writes:

>> From: Gerd Möllmann <gerd.moellmann@gmail.com>
>> Cc: 72496@debbugs.gnu.org
>> 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.





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

* bug#72496: 31.0.50; macOS: freezes without beach ball
  2024-08-06 18:37       ` Gerd Möllmann
@ 2024-08-08  5:24         ` Gerd Möllmann
  2024-08-10  9:18           ` Gerd Möllmann
  0 siblings, 1 reply; 7+ messages in thread
From: Gerd Möllmann @ 2024-08-08  5:24 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: 72496

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

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

> Eli Zaretskii <eliz@gnu.org> writes:
>
>>> From: Gerd Möllmann <gerd.moellmann@gmail.com>
>>> Cc: 72496@debbugs.gnu.org
>>> 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.


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: nsterm.m patch --]
[-- Type: text/x-patch, Size: 3410 bytes --]

From f48aafd73c7d2694bf2c9e980e9624bde9ab3b3e Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Gerd=20M=C3=B6llmann?= <gerd@gnu.org>
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


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

* bug#72496: 31.0.50; macOS: freezes without beach ball
  2024-08-08  5:24         ` Gerd Möllmann
@ 2024-08-10  9:18           ` Gerd Möllmann
  0 siblings, 0 replies; 7+ messages in thread
From: Gerd Möllmann @ 2024-08-10  9:18 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: 72496

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

> Gerd Möllmann <gerd.moellmann@gmail.com> writes:
>
>> Eli Zaretskii <eliz@gnu.org> writes:
>>
>>>> From: Gerd Möllmann <gerd.moellmann@gmail.com>
>>>> Cc: 72496@debbugs.gnu.org
>>>> 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.

I don't even know if this is related to my change to ns_send_appdefined, but
I got a freeze today while using child frames (vertico + posframe) that
I haven't seen before. Event the mouse behaved strangely on the whole
macOS until I killed the process. That was without beach ball.

So, whatever that was, my patch at least didn't help, if it wasn't
causing it.

I give up. I'll switch to using tty Emacs.





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

end of thread, other threads:[~2024-08-10  9:18 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2024-08-06 13:39 bug#72496: 31.0.50; macOS: freezes without beach ball Gerd Möllmann
2024-08-06 14:53 ` Eli Zaretskii
2024-08-06 16:36   ` Gerd Möllmann
2024-08-06 18:04     ` Eli Zaretskii
2024-08-06 18:37       ` Gerd Möllmann
2024-08-08  5:24         ` Gerd Möllmann
2024-08-10  9:18           ` Gerd Möllmann

Code repositories for project(s) associated with this external index

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

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.