From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.io!.POSTED.blaine.gmane.org!not-for-mail From: Eli Zaretskii Newsgroups: gmane.emacs.devel Subject: Re: MPS: w32 threads Date: Sun, 05 May 2024 11:27:42 +0300 Message-ID: <86le4oek8x.fsf@gnu.org> References: <875xvvp3fo.fsf@gmail.com> <87r0eicht1.fsf_-_@gmail.com> <87plu29lcc.fsf@yahoo.com> <87fruyccs8.fsf@gmail.com> <86h6fegdzk.fsf@gnu.org> <86bk5lhqlx.fsf@gnu.org> <86le4pfzjg.fsf@gnu.org> Mime-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit Injection-Info: ciao.gmane.io; posting-host="blaine.gmane.org:116.202.254.214"; logging-data="11156"; mail-complaints-to="usenet@ciao.gmane.io" Cc: eller.helmut@gmail.com, emacs-devel@gnu.org To: Gerd =?utf-8?Q?M=C3=B6llmann?= Original-X-From: emacs-devel-bounces+ged-emacs-devel=m.gmane-mx.org@gnu.org Sun May 05 10:28:21 2024 Return-path: Envelope-to: ged-emacs-devel@m.gmane-mx.org Original-Received: from lists.gnu.org ([209.51.188.17]) by ciao.gmane.io with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.92) (envelope-from ) id 1s3XEK-0002eT-Ol for ged-emacs-devel@m.gmane-mx.org; Sun, 05 May 2024 10:28:20 +0200 Original-Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1s3XDr-0003in-9X; Sun, 05 May 2024 04:27:51 -0400 Original-Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1s3XDp-0003hc-A9 for emacs-devel@gnu.org; Sun, 05 May 2024 04:27:49 -0400 Original-Received: from fencepost.gnu.org ([2001:470:142:3::e]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1s3XDo-0007QH-Q6; Sun, 05 May 2024 04:27:48 -0400 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=gnu.org; s=fencepost-gnu-org; h=MIME-version:References:Subject:In-Reply-To:To:From: Date; bh=FRbtJN2gBMSBJ+Prr5T8hAoemAQQ5+vIXTcVzLoMcCg=; b=jRVAJZwa2amrq+mQdA/w C+hicM+wTYZgIK71WvGYP1SDzXPsIMvvHXJbyaem53EYdRK9u7zpBjSGYD0XlZB11D6d/xzoQDZ98 eyYZ/BH6FenOmDLAtR80bbvYfZ4KmK2nW4WXTq9QLhP4kK0enU1p+GStM9zmwAwwlpFYRixRbh56O pxuTHK2dzr1AV1UG44CUJfFgSciojQ88U5ma9G9koGNDIp0hAr83ReNuC4egFLt2akALp8r+7AltA 0EPBGlvbuOoLdz1FbtzvqEvXuhbu/Yl0lMptnAKE5l94Q1IF7cIcw8uIUv6N9yAk3Wk31cKPjvK+d J3yiZo6pf0Wiww==; In-Reply-To: (message from Gerd =?utf-8?Q?M=C3=B6llmann?= on Sat, 04 May 2024 16:20:19 +0200) X-BeenThere: emacs-devel@gnu.org X-Mailman-Version: 2.1.29 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-mx.org@gnu.org Original-Sender: emacs-devel-bounces+ged-emacs-devel=m.gmane-mx.org@gnu.org Xref: news.gmane.io gmane.emacs.devel:318796 Archived-At: > From: Gerd Möllmann > Cc: eller.helmut@gmail.com, luangruo@yahoo.com, emacs-devel@gnu.org > Date: Sat, 04 May 2024 16:20:19 +0200 > > >> A thread must be registered with an arena if: > >> > >> its control stack and registers form a root (this is enforced by > >> mps_root_create_thread()); or it reads or writes from a location in an > >> automatically managed pool in the arena. However, some automatically > >> managed pool classes may be more liberal than this. See the > >> documentation for the pool class. > > > > Can you try translating this to Emacs-related terms, please? What > > activities in the thread should require the thread to be "registered > > with an arena"? > > It basically says that if a thread can have Lisp_Objects or pointers to > them on its control stack, register it with MPS. > > An arena is basically an implementation of some low-level aspects of > memory managemnt in MPS. We have only one MPS arena, and it is one using > VM functions (mmap, ...). > > The hint that some pool classes don't require this or that we can > ignore. AKAIK the mostly-copying pools we use require it. > > > Emacs on Windows starts separate threads for the following jobs: > > > > . processing Windows GUI-related messages > > . reading from sub-processes (part of pselect emulation) > > . emulation of itimers (for atimers and for M-x profiler) > > . file-change notifications > > > > I need to understand what traits of a thread make it need to be > > registered with MPS. Each of the above will then need a separate > > audit, I think. > > Using any Lisp_Objects (or other objects allocated from MPS) -> register > it. AFAIU, the GUI thread gets such an objects posted in a message, so > that one must be registered. > > The others are hard to say for me. It would not do harm to register > them, but might mean addtional work for nothing. So how does one go about registering a thread? I've just got up from a full hour reading the seemingly-related parts of igc.c and the MPS documentation (the latter, I must say, is really badly written and organized illogically), and I still have quite a few questions about this. First, the MPS manual says to call mps_thread_reg from the thread itself, to register a thread. That function accepts the ARENA argument. I see we have a single global arena, but should other threads use the same arena, or should they create their own? The considerations for that are not clear (are they documented somewhere?), I only see that you used the same arena for the Lisp threads in thread_add. Is that arena defined in a way that could serve additional threads, perhaps many of them? (The w32 build starts a separate thread for any file-notification watch, up to 64 threads for sub-process communications, and one thread per atimer, so in principle we could have quite a few of them, if a session is a heavy user of these features.) While trying to think about the need for an additional arena, I took a look at the relevant APIs, and became confused with what we do (or don't do) in make_arena. All the keywords we add with MPS_ARGS_ADD and the magic constants there -- what do they mean and what were the considerations to choose them and not the others? Can some commentary be added there to explain what we need to know, and maybe even mention optional features we might consider in the future? Assuming we can do with the single global arena already defined, the MPS documentation next says that every thread's registers and stack should be registered using mps_root_create_thread. But the code in igc.c uses mps_root_create_thread_scanned instead, whose documentation is obscure, and I cannot figure out whether to copycat or do something else. Next, mps_root_create_thread and mps_root_create_thread_scanned require a COLD pointer, about which the MPS documentation says: The MPS’s stack scanner needs to know how to find the cold end of the part of the stack to scan. The cold end of the relevant part of the stack can be found by taking the address of a local variable in the function that calls the main work function of your thread. You should take care to ensure that the work function is not inlined so that the address is definitely in the stack frame below any potential roots. But in our case, the thread function is run directly by the MS-Windows CreateThread API, not via an intermediate function, so the worker function is effectively "inlined". So is it okay to have the cold end marker be a local variable in the same thread-worker function? In another place of the MPS documentation there's an example which seems to answer in the positive: void *marker = ▮ mps_root_t stack_root; res = mps_root_create_thread(&stack_root, arena, thread, marker); if (res != MPS_RES_OK) error("Couldn't create stack root"); Am I missing something, or could the above be at the very beginning of a thread's worker function? Or do we have to define intermediary functions for each thread worker? mps_root_create_thread_scanned also takes the CLOSURE argument, which is a pointer, and we pass a NULL pointer as its value(??). Is this because our scan_area function, scan_ambig, simply ignores the CLOSURE argument? What else needs to be done for "registering a thread"? igc_thread_add does a few other things; some of them are Lisp-related (so not relevant for non-Lisp threads), but others aren't, so I'm unsure about these: . igc_thread_list_push (what is it? and where defined?) . igc_root_list_push (where is it defined and what does it do?) . create_thread_aps (what is it for?) I think some minimal commentary to what these functions do is in order, to make the code look less like some "black magic". TIA