[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Emacs-diffs] /srv/bzr/emacs/trunk r109635: Improve event loop on NS so
From: |
Jan D. |
Subject: |
[Emacs-diffs] /srv/bzr/emacs/trunk r109635: Improve event loop on NS so that no polling is used. |
Date: |
Wed, 15 Aug 2012 20:58:19 +0200 |
User-agent: |
Bazaar (2.5.0) |
------------------------------------------------------------
revno: 109635
committer: Jan D. <address@hidden>
branch nick: trunk
timestamp: Wed 2012-08-15 20:58:19 +0200
message:
Improve event loop on NS so that no polling is used.
* nsmenu.m (popupSession): Remove.
(pop_down_menu): Remove endModalSession.
(timeout_handler:): New method.
(runDialogAt:): Get next timeout. Start a NSTimer with that timeout.
Call runModalForWindow. Check timer_fired when it returns.
If not set, cancel timer and break out of loop.
Otherwise loop again, with a new timeout.
* nsterm.h (EmacsApp): fd_handler takes id argument.
(EmacsDialogPanel): Add timer_fired and timeout_handler.
* nsterm.m: Include fcntl.h if present.
(fd_entry, t_readfds, inNsSelect): Remove.
(select_writefds, select_valid, select_timeout, selfds)
(select_mutex, apploopnr): Add.
(EV_TRAILER): Call kbd_buffer_store_event_hold only if q_event_ptr.
Otherwise call kbd_buffer_store_event.
(ns_send_appdefined): Remove release of fd_entry.
(ns_read_socket): Always send appdefined. Remove inNsSelect check.
Increment and decrement apploopnr.
(ns_select): If no file descriptors, just do a NSTimer.
Otherwise copy read/write masks and start select thread (fd_handler).
Start main loop and wait for application defined event.
Inform select thread to stop selecting after main loop is exited.
(ns_term_init): Create selfds pipe and set non-blocking.
Initialize select_mutex. Start the select thread (fd_handler).
(fd_handler:): Loop forever, wait for info from the main thread
to either start or stop selecting. When select returns, send
and appdefined event.
(sendScrollEventAtLoc:fromEvent:): Check if q_event_ptr is set.
If not call kbd_buffer_store_event.
modified:
src/ChangeLog
src/nsmenu.m
src/nsterm.h
src/nsterm.m
=== modified file 'src/ChangeLog'
--- a/src/ChangeLog 2012-08-15 18:34:46 +0000
+++ b/src/ChangeLog 2012-08-15 18:58:19 +0000
@@ -1,5 +1,37 @@
2012-08-15 Jan Djärv <address@hidden>
+ * nsmenu.m (popupSession): Remove.
+ (pop_down_menu): Remove endModalSession.
+ (timeout_handler:): New method.
+ (runDialogAt:): Get next timeout. Start a NSTimer with that timeout.
+ Call runModalForWindow. Check timer_fired when it returns.
+ If not set, cancel timer and break out of loop.
+ Otherwise loop again, with a new timeout.
+
+ * nsterm.m: Include fcntl.h if present.
+ (fd_entry, t_readfds, inNsSelect): Remove.
+ (select_writefds, select_valid, select_timeout, selfds)
+ (select_mutex, apploopnr): Add.
+ (EV_TRAILER): Call kbd_buffer_store_event_hold only if q_event_ptr.
+ Otherwise call kbd_buffer_store_event.
+ (ns_send_appdefined): Remove release of fd_entry.
+ (ns_read_socket): Always send appdefined. Remove inNsSelect check.
+ Increment and decrement apploopnr.
+ (ns_select): If no file descriptors, just do a NSTimer.
+ Otherwise copy read/write masks and start select thread (fd_handler).
+ Start main loop and wait for application defined event.
+ Inform select thread to stop selecting after main loop is exited.
+ (ns_term_init): Create selfds pipe and set non-blocking.
+ Initialize select_mutex. Start the select thread (fd_handler).
+ (fd_handler:): Loop forever, wait for info from the main thread
+ to either start or stop selecting. When select returns, send
+ and appdefined event.
+ (sendScrollEventAtLoc:fromEvent:): Check if q_event_ptr is set.
+ If not call kbd_buffer_store_event.
+
+ * nsterm.h (EmacsApp): fd_handler takes id argument.
+ (EmacsDialogPanel): Add timer_fired and timeout_handler.
+
* gtkutil.c (xg_mark_data): Use FRAME_X_P.
2012-08-15 Eli Zaretskii <address@hidden>
=== modified file 'src/nsmenu.m'
--- a/src/nsmenu.m 2012-08-07 07:33:18 +0000
+++ b/src/nsmenu.m 2012-08-15 18:58:19 +0000
@@ -73,7 +73,6 @@
/* Nonzero means a menu is currently active. */
static int popup_activated_flag;
-static NSModalSession popupSession;
/* Nonzero means we are tracking and updating menus. */
static int trackingMenu;
@@ -1365,8 +1364,6 @@
{
EmacsDialogPanel *panel = unwind_data->dialog;
popup_activated_flag = 0;
- [NSApp endModalSession: popupSession];
-
[panel close];
[unwind_data->pool release];
[[FRAME_NS_VIEW (SELECTED_FRAME ()) window] makeKeyWindow];
@@ -1756,20 +1753,40 @@
}
+
+- (void)timeout_handler: (NSTimer *)timedEntry
+{
+ timer_fired = 1;
+ [NSApp abortModal];
+}
+
- (Lisp_Object)runDialogAt: (NSPoint)p
{
- NSInteger ret;
+ NSInteger ret = 0;
- /* initiate a session that will be ended by pop_down_menu */
- popupSession = [NSApp beginModalSessionForWindow: self];
- while (popup_activated_flag
- && (ret = [NSApp runModalSession: popupSession])
- == NSRunContinuesResponse)
+ while (popup_activated_flag)
{
- /* Run this for timers.el, indep of atimers; might not return.
- TODO: use return value to avoid calling every iteration. */
- timer_check ();
- [NSThread sleepUntilDate: [NSDate dateWithTimeIntervalSinceNow: 0.1]];
+ NSTimer *tmo = nil;
+ EMACS_TIME next_time = timer_check ();
+
+ if (EMACS_TIME_VALID_P (next_time))
+ {
+ double time = EMACS_TIME_TO_DOUBLE (next_time);
+ tmo = [NSTimer timerWithTimeInterval: time
+ target: self
+ selector: @selector (timeout_handler:)
+ userInfo: 0
+ repeats: NO];
+ [[NSRunLoop currentRunLoop] addTimer: tmo
+ forMode: NSModalPanelRunLoopMode];
+ }
+ timer_fired = 0;
+ ret = [NSApp runModalForWindow: self];
+ if (! timer_fired)
+ {
+ if (tmo != nil) [tmo invalidate]; /* Cancels timer */
+ break;
+ }
}
{ /* FIXME: BIG UGLY HACK!!! */
=== modified file 'src/nsterm.h'
--- a/src/nsterm.h 2012-08-10 09:24:03 +0000
+++ b/src/nsterm.h 2012-08-15 18:58:19 +0000
@@ -56,7 +56,7 @@
- (void)sendEvent: (NSEvent *)theEvent;
- (void)showPreferencesWindow: (id)sender;
- (BOOL) openFile: (NSString *)fileName;
-- (void)fd_handler: (NSTimer *) fdEntry;
+- (void)fd_handler: (id)unused;
- (void)timeout_handler: (NSTimer *)timedEntry;
- (BOOL)fulfillService: (NSString *)name withArg: (NSString *)arg;
@end
@@ -195,12 +195,14 @@
NSTextField *title;
NSMatrix *matrix;
int rows, cols;
+ int timer_fired;
}
- initFromContents: (Lisp_Object)menu isQuestion: (BOOL)isQ;
- addButton: (char *)str value: (Lisp_Object)val row: (int)row;
- addString: (char *)str row: (int)row;
- addSplit;
- (Lisp_Object)runDialogAt: (NSPoint)p;
+- (void)timeout_handler: (NSTimer *)timedEntry;
@end
#if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED >=
MAC_OS_X_VERSION_10_6
=== modified file 'src/nsterm.m'
--- a/src/nsterm.m 2012-08-13 03:44:27 +0000
+++ b/src/nsterm.m 2012-08-15 18:58:19 +0000
@@ -39,6 +39,10 @@
#include <c-strcase.h>
#include <ftoastr.h>
+#ifdef HAVE_FCNTL_H
+#include <fcntl.h>
+#endif
+
#include "lisp.h"
#include "blockinput.h"
#include "sysselect.h"
@@ -184,17 +188,20 @@
static BOOL send_appdefined = YES;
static NSEvent *last_appdefined_event = 0;
static NSTimer *timed_entry = 0;
-static NSTimer *fd_entry = nil;
static NSTimer *scroll_repeat_entry = nil;
-static fd_set select_readfds, t_readfds;
-static int select_nfds;
+static fd_set select_readfds, select_writefds;
+enum { SELECT_HAVE_READ = 1, SELECT_HAVE_WRITE = 2, SELECT_HAVE_TMO = 4 };
+static int select_nfds = 0, select_valid = 0;
+static EMACS_TIME select_timeout = { 0, 0 };
+static int selfds[2] = { -1, -1 };
+static pthread_mutex_t select_mutex;
+static int apploopnr = 0;
static NSAutoreleasePool *outerpool;
static struct input_event *emacs_event = NULL;
static struct input_event *q_event_ptr = NULL;
static int n_emacs_events_pending = 0;
static NSMutableArray *ns_pending_files, *ns_pending_service_names,
*ns_pending_service_args;
-static BOOL inNsSelect = 0;
static BOOL ns_do_open_file = NO;
/* Convert modifiers in a NeXTstep event to emacs style modifiers. */
@@ -252,15 +259,20 @@
/* This is a piece of code which is common to all the event handling
methods. Maybe it should even be a function. */
-#define EV_TRAILER(e) \
- { \
- XSETFRAME (emacs_event->frame_or_window, emacsframe); \
- if (e) emacs_event->timestamp = EV_TIMESTAMP (e); \
- n_emacs_events_pending++; \
- kbd_buffer_store_event_hold (emacs_event, q_event_ptr); \
- EVENT_INIT (*emacs_event); \
- ns_send_appdefined (-1); \
- }
+#define EV_TRAILER(e) \
+ { \
+ XSETFRAME (emacs_event->frame_or_window, emacsframe); \
+ if (e) emacs_event->timestamp = EV_TIMESTAMP (e); \
+ if (q_event_ptr) \
+ { \
+ n_emacs_events_pending++; \
+ kbd_buffer_store_event_hold (emacs_event, q_event_ptr); \
+ } \
+ else \
+ kbd_buffer_store_event (emacs_event); \
+ EVENT_INIT (*emacs_event); \
+ ns_send_appdefined (-1); \
+ }
void x_set_cursor_type (struct frame *, Lisp_Object, Lisp_Object);
@@ -3377,14 +3389,6 @@
timed_entry = nil;
}
- /* Ditto for file descriptor poller */
- if (fd_entry)
- {
- [fd_entry invalidate];
- [fd_entry release];
- fd_entry = nil;
- }
-
nxev = [NSEvent otherEventWithType: NSApplicationDefined
location: NSMakePoint (0, 0)
modifierFlags: 0
@@ -3402,7 +3406,6 @@
}
}
-
static int
ns_read_socket (struct terminal *terminal, int expected,
struct input_event *hold_quit)
@@ -3466,24 +3469,14 @@
/* 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);
- /* If called via ns_select, this is called once with expected=1,
- because we expect either the timeout or file descriptor activity.
- In this case the first event through will either be real input or
- one of these. read_avail_input() then calls once more with expected=0
- and in that case we need to return quickly if there is nothing.
- If we're being called outside of that, it's also OK to return quickly
- after one iteration through the event loop, since other terms do
- this and emacs expects it. */
- if (!(inNsSelect && expected))
+ if (++apploopnr != 1)
{
- /* Post an application defined event on the event queue. When this
is
- received the [NXApp run] will return, thus having processed all
- events which are currently queued, if any. */
- ns_send_appdefined (-1);
+ abort ();
}
-
[NSApp run];
+ --apploopnr;
}
nevents = n_emacs_events_pending;
@@ -3503,65 +3496,89 @@
--------------------------------------------------------------------------
*/
{
int result;
- double time;
NSEvent *ev;
- struct timespec select_timeout;
+ int k, nr = 0;
+ struct input_event event;
+ char c;
/* NSTRACE (ns_select); */
- if (NSApp == nil || inNsSelect == 1 /* || ([NSApp isActive] == NO &&
- [NSApp nextEventMatchingMask:NSAnyEventMask untilDate:nil
- inMode:NSDefaultRunLoopMode dequeue:NO] == nil) */)
+ for (k = 0; readfds && k < nfds+1; k++)
+ if (FD_ISSET(k, readfds)) ++nr;
+
+ if (NSApp == nil
+ || (timeout && timeout->tv_sec == 0 && timeout->tv_nsec == 0))
return pselect (nfds, readfds, writefds, exceptfds, timeout, sigmask);
- /* Save file descriptor set, which gets overwritten in calls to select ()
- Note, this is called from process.c, and only readfds is ever set */
- if (readfds)
+ [outerpool release];
+ outerpool = [[NSAutoreleasePool alloc] init];
+
+
+ send_appdefined = YES;
+ if (nr > 0)
{
- memcpy (&select_readfds, readfds, sizeof (fd_set));
+ pthread_mutex_lock (&select_mutex);
select_nfds = nfds;
- }
- else
- select_nfds = 0;
-
- /* Try an initial select for pending data on input files */
- select_timeout.tv_sec = select_timeout.tv_nsec = 0;
- result = pselect (nfds, readfds, writefds, exceptfds,
- &select_timeout, sigmask);
- if (result)
- return result;
-
- /* if (!timeout || timed_entry || fd_entry)
- fprintf (stderr, "assertion failed: timeout null or
timed_entry/fd_entry non-null in ns_select\n"); */
-
- /* set a timeout and run the main AppKit event loop while continuing
- to monitor the files */
- time = EMACS_TIME_TO_DOUBLE (*timeout);
- timed_entry = [[NSTimer scheduledTimerWithTimeInterval: time
- target: NSApp
- selector: @selector (timeout_handler:)
- userInfo: 0
- repeats: YES] /* for safe removal */
- retain];
-
- /* set a periodic task to try the pselect () again */
- fd_entry = [[NSTimer scheduledTimerWithTimeInterval: 0.1
- target: NSApp
- selector: @selector (fd_handler:)
- userInfo: 0
- repeats: YES]
- retain];
-
- /* Let Application dispatch events until it receives an event of the type
- NX_APPDEFINED, which should only be sent by timeout_handler.
- We tell read_avail_input() that input is "expected" because we do expect
- either the timeout or fd handler to fire, and if they don't, the original
- call from process.c that got us here expects us to wait until some input
- comes. */
- inNsSelect = 1;
- gobble_input (1);
+ select_valid = 0;
+ if (readfds)
+ {
+ select_readfds = *readfds;
+ select_valid += SELECT_HAVE_READ;
+ }
+ if (writefds)
+ {
+ select_writefds = *writefds;
+ select_valid += SELECT_HAVE_WRITE;
+ }
+
+ if (timeout)
+ {
+ select_timeout = *timeout;
+ select_valid += SELECT_HAVE_TMO;
+ }
+
+ pthread_mutex_unlock (&select_mutex);
+
+ /* Inform fd_handler that select should be called */
+ c = 'g';
+ write (selfds[1], &c, 1);
+ }
+ else if (nr == 0 && timeout)
+ {
+ /* No file descriptor, just a timeout, no need to wake fd_handler */
+ double time = EMACS_TIME_TO_DOUBLE (*timeout);
+ timed_entry = [[NSTimer scheduledTimerWithTimeInterval: time
+ target: NSApp
+ selector:
+ @selector (timeout_handler:)
+ userInfo: 0
+ repeats: NO]
+ retain];
+ }
+ else /* No timeout and no file descriptors, can this happen? */
+ {
+ /* Send appdefined so we exit from the loop */
+ ns_send_appdefined (-1);
+ }
+
+ EVENT_INIT (event);
+ BLOCK_INPUT;
+ emacs_event = &event;
+ if (++apploopnr != 1)
+ {
+ abort();
+ }
+ [NSApp run];
+ --apploopnr;
+ emacs_event = NULL;
+ if (nr > 0 && readfds)
+ {
+ c = 's';
+ write (selfds[1], &c, 1);
+ }
+ UNBLOCK_INPUT;
+
ev = last_appdefined_event;
- inNsSelect = 0;
if (ev)
{
@@ -3575,25 +3592,28 @@
if (t == -2)
{
/* The NX_APPDEFINED event we received was a timeout. */
- return 0;
+ result = 0;
}
else if (t == -1)
{
/* The NX_APPDEFINED event we received was the result of
at least one real input event arriving. */
errno = EINTR;
- return -1;
+ result = -1;
}
else
{
- /* Received back from pselect () in fd_handler; copy the results */
- if (readfds)
- memcpy (readfds, &select_readfds, sizeof (fd_set));
- return t;
+ /* Received back from select () in fd_handler; copy the results */
+ pthread_mutex_lock (&select_mutex);
+ if (readfds) *readfds = select_readfds;
+ if (writefds) *writefds = select_writefds;
+ if (timeout) *timeout = select_timeout;
+ pthread_mutex_unlock (&select_mutex);
+ result = t;
}
}
- /* never reached, shut compiler up */
- return 0;
+
+ return result;
}
@@ -4024,6 +4044,21 @@
{
baud_rate = 38400;
Fset_input_interrupt_mode (Qnil);
+
+ if (selfds[0] == -1)
+ {
+ if (pipe (selfds) == -1)
+ {
+ fprintf (stderr, "Failed to create pipe: %s\n",
+ emacs_strerror (errno));
+ abort ();
+ }
+
+ fcntl (selfds[0], F_SETFL, O_NONBLOCK|fcntl (selfds[0], F_GETFL));
+ FD_ZERO (&select_readfds);
+ FD_ZERO (&select_writefds);
+ pthread_mutex_init (&select_mutex, NULL);
+ }
ns_initialized = 1;
}
@@ -4039,6 +4074,11 @@
return NULL;
[NSApp setDelegate: NSApp];
+ /* Start the select thread. */
+ [NSThread detachNewThreadSelector:@selector (fd_handler:)
+ toTarget:NSApp
+ withObject:nil];
+
/* debugging: log all notifications */
/* [[NSNotificationCenter defaultCenter] addObserver: NSApp
selector: @selector (logNotification:)
@@ -4547,26 +4587,91 @@
ns_send_appdefined (-2);
}
-- (void)fd_handler: (NSTimer *) fdEntry
+- (void)fd_handler:(id)unused
/* --------------------------------------------------------------------------
Check data waiting on file descriptors and terminate if so
--------------------------------------------------------------------------
*/
{
int result;
- struct timespec select_timeout;
+ int waiting = 1, nfds;
+ char c;
+
+ SELECT_TYPE readfds, writefds, *wfds;
+ EMACS_TIME timeout, *tmo;
+
/* NSTRACE (fd_handler); */
- if (select_nfds == 0)
- return;
-
- memcpy (&t_readfds, &select_readfds, sizeof (fd_set));
-
- select_timeout.tv_sec = select_timeout.tv_nsec = 0;
- result = pselect (select_nfds, &t_readfds, NULL, NULL, &select_timeout,
NULL);
- if (result)
+ for (;;)
{
- memcpy (&select_readfds, &t_readfds, sizeof (fd_set));
- ns_send_appdefined (result);
+ if (waiting)
+ {
+ SELECT_TYPE fds;
+
+ FD_SET (selfds[0], &fds);
+ result = select (selfds[0]+1, &fds, NULL, NULL, NULL);
+ if (result > 0)
+ {
+ read (selfds[0], &c, 1);
+ if (c == 'g') waiting = 0;
+ }
+ }
+ else
+ {
+ pthread_mutex_lock (&select_mutex);
+ nfds = select_nfds;
+
+ if (select_valid & SELECT_HAVE_READ)
+ readfds = select_readfds;
+ else
+ FD_ZERO (&readfds);
+
+ if (select_valid & SELECT_HAVE_WRITE)
+ {
+ writefds = select_writefds;
+ wfds = &writefds;
+ }
+ else
+ wfds = NULL;
+ if (select_valid & SELECT_HAVE_TMO)
+ {
+ timeout = select_timeout;
+ tmo = &timeout;
+ }
+ else
+ tmo = NULL;
+
+ pthread_mutex_unlock (&select_mutex);
+
+ FD_SET (selfds[0], &readfds);
+ if (selfds[0] >= nfds) nfds = selfds[0]+1;
+
+ result = pselect (nfds, &readfds, wfds, NULL, tmo, NULL);
+
+ if (result == 0)
+ ns_send_appdefined (-2);
+ else if (result > 0)
+ {
+ if (FD_ISSET (selfds[0], &readfds))
+ {
+ read (selfds[0], &c, 1);
+ if (c == 's') waiting = 1;
+ }
+ else
+ {
+ pthread_mutex_lock (&select_mutex);
+ if (select_valid & SELECT_HAVE_READ)
+ select_readfds = readfds;
+ if (select_valid & SELECT_HAVE_WRITE)
+ select_writefds = writefds;
+ if (select_valid & SELECT_HAVE_TMO)
+ select_timeout = timeout;
+ pthread_mutex_unlock (&select_mutex);
+
+ ns_send_appdefined (result);
+ }
+ }
+ waiting = 1;
+ }
}
}
@@ -6404,8 +6509,13 @@
XSETINT (emacs_event->x, loc * pixel_height);
XSETINT (emacs_event->y, pixel_height-20);
- n_emacs_events_pending++;
- kbd_buffer_store_event_hold (emacs_event, q_event_ptr);
+ if (q_event_ptr)
+ {
+ n_emacs_events_pending++;
+ kbd_buffer_store_event_hold (emacs_event, q_event_ptr);
+ }
+ else
+ kbd_buffer_store_event (emacs_event);
EVENT_INIT (*emacs_event);
ns_send_appdefined (-1);
}
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- [Emacs-diffs] /srv/bzr/emacs/trunk r109635: Improve event loop on NS so that no polling is used.,
Jan D. <=