From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.org!.POSTED!not-for-mail From: Eli Zaretskii Newsgroups: gmane.emacs.devel Subject: Re: The event handling thread (was: Threading IO-bound functions) Date: Tue, 20 Dec 2016 18:08:25 +0200 Message-ID: <83wpeu37nq.fsf@gnu.org> References: <8360mj99oe.fsf@gnu.org> <83fulk610j.fsf@gnu.org> Reply-To: Eli Zaretskii NNTP-Posting-Host: blaine.gmane.org X-Trace: blaine.gmane.org 1482250122 26247 195.159.176.226 (20 Dec 2016 16:08:42 GMT) X-Complaints-To: usenet@blaine.gmane.org NNTP-Posting-Date: Tue, 20 Dec 2016 16:08:42 +0000 (UTC) Cc: lokedhs@gmail.com, emacs-devel@gnu.org To: John Wiegley Original-X-From: emacs-devel-bounces+ged-emacs-devel=m.gmane.org@gnu.org Tue Dec 20 17:08:38 2016 Return-path: Envelope-to: ged-emacs-devel@m.gmane.org Original-Received: from lists.gnu.org ([208.118.235.17]) by blaine.gmane.org with esmtp (Exim 4.84_2) (envelope-from ) id 1cJMxw-0005hx-TQ for ged-emacs-devel@m.gmane.org; Tue, 20 Dec 2016 17:08:37 +0100 Original-Received: from localhost ([::1]:52030 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1cJMy1-0007Qw-5N for ged-emacs-devel@m.gmane.org; Tue, 20 Dec 2016 11:08:41 -0500 Original-Received: from eggs.gnu.org ([2001:4830:134:3::10]:35194) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1cJMxu-0007Qp-49 for emacs-devel@gnu.org; Tue, 20 Dec 2016 11:08:35 -0500 Original-Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1cJMxq-0005hd-4a for emacs-devel@gnu.org; Tue, 20 Dec 2016 11:08:34 -0500 Original-Received: from fencepost.gnu.org ([2001:4830:134:3::e]:33552) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1cJMxq-0005hX-0y; Tue, 20 Dec 2016 11:08:30 -0500 Original-Received: from 84.94.185.246.cable.012.net.il ([84.94.185.246]:2973 helo=home-c4e4a596f7) by fencepost.gnu.org with esmtpsa (TLS1.2:RSA_AES_256_CBC_SHA1:256) (Exim 4.82) (envelope-from ) id 1cJMxp-0001AS-Ag; Tue, 20 Dec 2016 11:08:29 -0500 In-reply-to: (message from John Wiegley on Mon, 19 Dec 2016 09:43:30 -0800) X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] X-Received-From: 2001:4830:134:3::e X-BeenThere: emacs-devel@gnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: "Emacs development discussions." List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: emacs-devel-bounces+ged-emacs-devel=m.gmane.org@gnu.org Original-Sender: "Emacs-devel" Xref: news.gmane.org gmane.emacs.devel:210663 Archived-At: > From: John Wiegley > Date: Mon, 19 Dec 2016 09:43:30 -0800 > Cc: Eli Zaretskii , emacs-devel > > EM> Now, my thoughts on this is that keyboard entry is an inherently > EM> single-threaded operation *from the user's point of view* and that the > EM> Emacs platform should enforce this. Thus, keyboard input should only be > EM> allowed from the main thread. > > I too had thought keyboard events would be managed by an IO queueing thread, > and dispatched to other threads when relevant (i.e., when the receipt of IO > preempted another thread that was "awaiting input"). As I explained here, the de-facto "IO queueing thread" is the "primary thread", the one started when Emacs starts. This is by virtue of the current design, whereby only one thread is ever allowed to wait on each handle through which Emacs communicates with the external world; that includes the keyboard handle. This works by marking each handle with the thread that waits for it. When a thread calls one of the APIs that need input from external sources, such as accept-process-output, or when it is about to become idle, the code in wait_reading_process_output generates the descriptor sets to be passed to 'pselect', and excludes from the set any descriptors that are already marked with some other thread waiting on them. Since the primary thread is the only one at session genesis, it finds the descriptor for the keyboard input free and "up for grabs", so it marks the keyboard descriptor with its thread ID when it calls 'pselect'. Other threads can only run when the primary thread calls 'pselect', so they all find the keyboard descriptor already "owned" by the primary thread. That "ownership" will only be lifted when the primary thread exits 'pselect', acquires the global lock, and starts running again, at which time all the other threads are either in their 'pselect' call or wait for the global lock to become unlocked. The primary thread will run until it again enters wait_reading_process_output, at which time it will find the keyboard descriptor either owned by itself or unowned, and will mark it as owned by itself. So the other threads will again see it as owned by the primary thread. This pattern will repeat itself forever, so I see no way for any non-primary thread to grab the keyboard descriptor and wait on it, unless we add something that would provide a means for them to do so, or until the primary thread runs some Lisp that calls thread-yield or some other synchronization primitive. To see the above machinery in action, try this: (defun infloop () (with-temp-buffer (while t (insert "foo")))) (make-thread #'infloop "thread-loop") As soon as you start the looping thread, any keyboard input, like M-x or cursor motion commands, doesn't have any effect, until you type C-g (which causes the looping thread to exit), because the looping thread never yields. > That is, I never thought event handling would be entirely cooperative, since > the user invoking a command should suspend what Emacs is doing, unless what > Emacs was doing was awaiting input. I'm not sure I understand what you are saying here. Remember: only one thread runs Lisp at any given time, so all the other threads are already "suspended" when the user input arrives at whatever thread is waiting on the keyboard descriptor. If the current thread that runs when the user types is not waiting on the keyboard descriptor, it will never know the user typed something, and will continue running until it yields or calls one of the "yielding" APIs, which end up in wait_reading_process_output. The thread that did wait on the keyboard descriptor will exit its 'pselect' call, try to acquire the global lock, and wait there for the running thread to yield. > Since there's some confusion on this point -- and maybe what I've stated above > doesn't make sense, since it could impose concurrency in places we've not > thought about yet -- I'd like us to discuss this a bit more. Well, let's discuss ;-)