linux-packaging-mono/external/bockbuild/packages/patches/gtk/0067-quartz-Make-event-loop-deal-with-recursive-poll-invo.patch
Xamarin Public Jenkins (auto-signing) 6bdd276d05 Imported Upstream version 5.0.0.42
Former-commit-id: fd56571888259555122d8a0f58c68838229cea2b
2017-04-10 11:41:01 +00:00

128 lines
4.6 KiB
Diff

From 5d0dfb203a4945eff28ad1696647b19dd0ef10e5 Mon Sep 17 00:00:00 2001
From: Kristian Rietveld <kris@lanedo.com>
Date: Mon, 8 Jul 2013 12:04:04 +0200
Subject: [PATCH 67/68] quartz: Make event loop deal with recursive poll
invocations
This patch addresses a number of problems with the recursion in
poll_func() that happens on OS X. Firstly, autorelease pool refreshes
are done from prepare and only if we are at the base level of *both*
main loops and not recursing in poll. This first part incorporates
suggestions from Daniel Sabo and John Ralls.
Secondly, a mechanism is implemented to detect if poll has been
called recursively. This is used to discard file descriptor state
at the base level, retrieved before possibly recursing (through the
NSApp get next event).
---
gdk/quartz/gdkeventloop-quartz.c | 106 ++++++++++++++++++++++++++++----------
1 file changed, 78 insertions(+), 28 deletions(-)
diff --git a/gdk/quartz/gdkeventloop-quartz.c b/gdk/quartz/gdkeventloop-quartz.c
index 224d84c..36c716a 100644
--- a/gdk/quartz/gdkeventloop-quartz.c
+++ b/gdk/quartz/gdkeventloop-quartz.c
@@ -168,6 +168,12 @@ static pthread_cond_t select_thread_cond = PTHREAD_COND_INITIALIZER;
static GPollFD *current_pollfds;
static guint current_n_pollfds;
+/* We maintain serial numbers for calls to the start function. Because we
+ * only test for equality of this number (and not smaller/greater than)
+ * no special handling is needed for wrap around.
+ */
+static guint select_thread_start_serial = 0;
+
/* These are the file descriptors that the select thread should pick
* up and start polling when it has a chance.
*/
@@ -399,6 +405,8 @@ select_thread_start_poll (GPollFD *ufds,
gint poll_fd_index = -1;
gint i;
+ select_thread_start_serial++;
+
for (i = 0; i < nfds; i++)
if (ufds[i].fd == -1)
{
@@ -703,15 +721,33 @@ poll_func (GPollFD *ufds,
NSEvent *event;
NSDate *limit_date;
gint n_ready;
+ guint current_select_thread_serial;
- static GPollFD *last_ufds;
+ /* Maintain current poll parameters as static parameters. On recursive
+ * calls to poll, we update the values. This way, if the poll array
+ * is updated in an recursive call, we can still access the new array
+ * when the recursion is wound down.
+ *
+ * The ufds value that is pushed in is allocated in g_main_context_iterate()
+ * and is only reallocated for enlargement of this array. The array thus
+ * never shrinks.
+ */
+ static GPollFD *current_ufds = NULL;
+ static int current_nfds = 0;
- last_ufds = ufds;
+ current_ufds = ufds;
+ current_nfds = nfds;
n_ready = select_thread_start_poll (ufds, nfds, timeout_);
if (n_ready > 0)
timeout_ = 0;
+ /* Using this serial number, we can check below whether the select
+ * thread was started/collected in a recursive invocation of this
+ * function.
+ */
+ current_select_thread_serial = select_thread_start_serial;
+
if (timeout_ == -1)
limit_date = [NSDate distantFuture];
else if (timeout_ == 0)
@@ -726,17 +762,31 @@ poll_func (GPollFD *ufds,
dequeue: YES];
getting_events--;
- /* We check if last_ufds did not change since the time this function was
- * called. It is possible that a recursive main loop (and thus recursive
- * invocation of this poll function) is triggered while in
- * nextEventMatchingMask:. If during that time new fds are added,
- * the cached fds array might be replaced in g_main_context_iterate().
- * So, we should avoid accessing the old fd array (still pointed at by
- * ufds) here in that case, since it might have been freed. We avoid this
- * by not calling the collect stage.
- */
- if (last_ufds == ufds && n_ready < 0)
- n_ready = select_thread_collect_poll (ufds, nfds);
+ /* Note that, from this point onwards, ufds might point to freed memory! */
+
+ if (current_select_thread_serial == select_thread_start_serial)
+ {
+ if (n_ready < 0)
+ n_ready = select_thread_collect_poll (current_ufds, nfds);
+
+ /* Nothing should be done in case no poll func recursion occurred
+ * and n_ready > 0.
+ */
+ }
+ else
+ {
+ /* In this case, a recursive invocation of the poll function has
+ * collected results from the select thread. We clear the ufds
+ * values so that stale poll results are not returned. In case
+ * we did not receive results from start poll above, we also
+ * set n_ready to zero.
+ */
+ int i;
+
+ n_ready = 0;
+ for (i = 0; i < nfds; i++)
+ current_ufds[i].revents = 0;
+ }
if (event &&
[event type] == NSApplicationDefined &&
--
1.7.10.2 (Apple Git-33)