Subject: bug#25345: 26.0.50; crash on mac, just rebuilt from git tip

From: Alan Third <[email-masked]>
Date: Tue, 3 Jan 2017 17:54:49 +0000

On Tue, Jan 03, 2017 at 12:29:54PM -0500, Sam Steingold wrote:
> In GNU Emacs 26.0.50.3 (x86_64-apple-darwin16.3.0, NS appkit-1504.76 Version 10.12.2 (Build 16C67))
>  of 2017-01-03 built on clr-sds
> Repository revision: 134e86b360cab0d0a5cb634b71a4b06ec26c5f1f
> Windowing system distributor 'Apple', version 10.3.1504
> 
> rebuilt from git tip.
> now emacs is very slow: it takes up to a second for the character to
> appear on the screen as I type.

Sorry about this, we’re trying to rework the NS port so it can handle
the new concurrency code.

Can you please try applying the attached patch, and let us know
whether it improves things?

Thanks!
-- 
Alan Third
>From 9663d300d231242fc77f93a35219d56ba9c90601 Mon Sep 17 00:00:00 2001
From: Alan Third <[email-masked]>
Date: Tue, 3 Jan 2017 14:16:37 +0000
Subject: [PATCH] Improve NS event handling (bug#25265)

* src/nsterm.h: Remove reference to timeout_handler.
* src/nsterm.m (ns_select): Monitor fd changes using NSFileHandler.
---
 src/nsterm.h |  1 -
 src/nsterm.m | 62 +++++++++++++++++++++++++++++++++++++++++++-----------------
 2 files changed, 45 insertions(+), 18 deletions(-)

diff --git a/src/nsterm.h b/src/nsterm.h
index dc222a7..8b5b691 100644
--- a/src/nsterm.h
+++ b/src/nsterm.h
@@ -392,7 +392,6 @@ char const * nstrace_fullscreen_type_name (int);
 - (void)sendEvent: (NSEvent *)theEvent;
 - (void)showPreferencesWindow: (id)sender;
 - (BOOL) openFile: (NSString *)fileName;
-- (void)timeout_handler: (NSTimer *)timedEntry;
 - (BOOL)fulfillService: (NSString *)name withArg: (NSString *)arg;
 #ifdef NS_IMPL_GNUSTEP
 - (void)sendFromMainThread:(id)unused;
diff --git a/src/nsterm.m b/src/nsterm.m
index 98fd8ab..51cccd0 100644
--- a/src/nsterm.m
+++ b/src/nsterm.m
@@ -4098,28 +4098,55 @@ overwriting cursor (usually when cursor on a tab) */
     return pselect(nfds, readfds, writefds,
                    exceptfds, timeout, sigmask);
 
-  result = pselect(nfds, readfds, writefds, exceptfds,
-                   &(struct timespec){.tv_sec = 0, .tv_nsec = 100},
-                   sigmask);
-
   [outerpool release];
   outerpool = [[NSAutoreleasePool alloc] init];
 
+  /* Set up one NSFileHandle for each fd we want to monitor. */
+  for (int i = 0 ; i < nfds ; i++)
+    {
+      if ((readfds != NULL && FD_ISSET(i, readfds))
+          || (writefds != NULL && FD_ISSET(i, writefds))
+          || (exceptfds != NULL &&FD_ISSET(i, exceptfds)))
+        {
+          NSFileHandle *fh = [[NSFileHandle alloc] initWithFileDescriptor: i
+                                                           closeOnDealloc: NO];
+          /* Send a notification to EmacsApp:fileHandleDataAvailable,
+             which will raise an appDefined event. */
+          /* NOTE: I don't think this will pick up writes and
+             exceptions, so ns_select may not always behave correctly.
+             I've yet to see a problem, though. */
+          [fh waitForDataInBackgroundAndNotify];
+          [fh autorelease];
+        }
+    }
+
   if (timeout)
     {
       double time = timespectod (*timeout);
-      timeout_date = [NSDate dateWithTimeIntervalSinceNow:time];
+      timeout_date = [NSDate dateWithTimeIntervalSinceNow: time];
     }
 
   /* Listen for a new NSEvent. */
-  ns_event = [NSApp nextEventMatchingMask:NSEventMaskAny
-                                untilDate:timeout_date
-                                   inMode:NSDefaultRunLoopMode
-                                  dequeue:NO];
+  ns_event = [NSApp nextEventMatchingMask: NSEventMaskAny
+                                untilDate: timeout_date
+                                   inMode: NSDefaultRunLoopMode
+                                  dequeue: NO];
 
   if (ns_event != nil)
     {
-      raise (SIGIO);
+      if ([ns_event type] == NSEventTypeApplicationDefined
+          && [ns_event data1] == -3)
+        {
+          result = pselect(nfds, readfds, writefds, exceptfds,
+                           &(struct timespec){.tv_sec = 0, .tv_nsec = 0},
+                           sigmask);
+        }
+      else
+        {
+          raise (SIGIO);
+          errno = EINTR;
+          return -1;
+        }
     }
 
   return result;
@@ -5132,6 +5159,12 @@ - (void)applicationDidFinishLaunching: (NSNotification *)notification
 	 object:nil];
 #endif
 
+  [[NSNotificationCenter defaultCenter]
+      addObserver: self
+         selector: @selector (fileHandleDataAvailable:)
+             name: NSFileHandleDataAvailableNotification
+           object: nil];
+
   ns_send_appdefined (-2);
 }
 
@@ -5315,14 +5348,9 @@ - (void)applicationDidResignActive: (NSNotification *)notification
 
    ========================================================================== */
 
-
-- (void)timeout_handler: (NSTimer *)timedEntry
-/* --------------------------------------------------------------------------
-     The timeout specified to ns_select has passed.
-   -------------------------------------------------------------------------- */
+- (void)fileHandleDataAvailable: (NSNotification *)notification
 {
-  /*NSTRACE ("timeout_handler"); */
-  ns_send_appdefined (-2);
+  ns_send_appdefined (-3);
 }
 
 - (void)sendFromMainThread:(id)unused
-- 
2.10.2