diff options
author | Pip Cet <pipcet@gmail.com> | 2020-08-21 14:56:06 +0200 |
---|---|---|
committer | Lars Ingebrigtsen <larsi@gnus.org> | 2020-08-21 14:56:06 +0200 |
commit | 9c62ffb08262c82b7e38e6eb5767f2087424aa47 (patch) | |
tree | ea2a18eabffded063b40af0623b2485b10ad44dc /src/xgselect.c | |
parent | 19ee08f1e8599ce0e0465f6ffbd4a76791d791b4 (diff) | |
download | emacs-9c62ffb08262c82b7e38e6eb5767f2087424aa47.tar.gz emacs-9c62ffb08262c82b7e38e6eb5767f2087424aa47.tar.bz2 emacs-9c62ffb08262c82b7e38e6eb5767f2087424aa47.zip |
Fix lock failures in xg_select
* src/xgselect.c (release_select_lock, acquire_select_lock):
Introduce.
(xg_select): Use `acquire_select_lock', `release_select_lock'.
* src/thread.c (release_select_lock): Introduce for non-GLib builds.
(really_call_select): Call `release_select_lock'. Simplify by
ensuring acquisition of the lock always succeeds (bug#36609).
Diffstat (limited to 'src/xgselect.c')
-rw-r--r-- | src/xgselect.c | 42 |
1 files changed, 28 insertions, 14 deletions
diff --git a/src/xgselect.c b/src/xgselect.c index f8d0bac7fac..be70107b756 100644 --- a/src/xgselect.c +++ b/src/xgselect.c @@ -29,6 +29,27 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */ #include "blockinput.h" #include "systime.h" +static ptrdiff_t threads_holding_glib_lock; +static GMainContext *glib_main_context; + +void release_select_lock (void) +{ + if (--threads_holding_glib_lock == 0) + g_main_context_release (glib_main_context); +} + +static void acquire_select_lock (GMainContext *context) +{ + if (threads_holding_glib_lock++ == 0) + { + glib_main_context = context; + while (!g_main_context_acquire (context)) + { + /* Spin. */ + } + } +} + /* `xg_select' is a `pselect' replacement. Why do we need a separate function? 1. Timeouts. Glib and Gtk rely on timer events. If we did pselect with a greater timeout then the one scheduled by Glib, we would @@ -54,26 +75,19 @@ xg_select (int fds_lim, fd_set *rfds, fd_set *wfds, fd_set *efds, GPollFD *gfds = gfds_buf; int gfds_size = ARRAYELTS (gfds_buf); int n_gfds, retval = 0, our_fds = 0, max_fds = fds_lim - 1; - bool context_acquired = false; int i, nfds, tmo_in_millisec, must_free = 0; bool need_to_dispatch; context = g_main_context_default (); - context_acquired = g_main_context_acquire (context); - /* FIXME: If we couldn't acquire the context, we just silently proceed - because this function handles more than just glib file descriptors. - Note that, as implemented, this failure is completely silent: there is - no feedback to the caller. */ + acquire_select_lock (context); if (rfds) all_rfds = *rfds; else FD_ZERO (&all_rfds); if (wfds) all_wfds = *wfds; else FD_ZERO (&all_wfds); - n_gfds = (context_acquired - ? g_main_context_query (context, G_PRIORITY_LOW, &tmo_in_millisec, - gfds, gfds_size) - : -1); + n_gfds = g_main_context_query (context, G_PRIORITY_LOW, &tmo_in_millisec, + gfds, gfds_size); if (gfds_size < n_gfds) { @@ -151,8 +165,10 @@ xg_select (int fds_lim, fd_set *rfds, fd_set *wfds, fd_set *efds, #else need_to_dispatch = true; #endif - if (need_to_dispatch && context_acquired) + if (need_to_dispatch) { + acquire_select_lock (context); + int pselect_errno = errno; /* Prevent g_main_dispatch recursion, that would occur without block_input wrapper, because event handlers call @@ -162,11 +178,9 @@ xg_select (int fds_lim, fd_set *rfds, fd_set *wfds, fd_set *efds, g_main_context_dispatch (context); unblock_input (); errno = pselect_errno; + release_select_lock (); } - if (context_acquired) - g_main_context_release (context); - /* To not have to recalculate timeout, return like this. */ if ((our_fds > 0 || (nfds == 0 && tmop == &tmo)) && (retval == 0)) { |