From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.io!.POSTED.blaine.gmane.org!not-for-mail From: sbaugh@catern.com Newsgroups: gmane.emacs.devel Subject: Re: Releasing the thread global_lock from the module API Date: Sat, 02 Mar 2024 16:39:26 +0000 (UTC) Message-ID: <87plwck2q5.fsf@catern.com> References: <86cysdrja3.fsf@gnu.org> <86a5nhrdv0.fsf@gnu.org> <868r31rbxn.fsf@gnu.org> <865xy5r8e3.fsf@gnu.org> <864jdpr5zy.fsf@gnu.org> <8634t9qgl2.fsf@gnu.org> Mime-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Transfer-Encoding: 7bit Injection-Info: ciao.gmane.io; posting-host="blaine.gmane.org:116.202.254.214"; logging-data="20069"; mail-complaints-to="usenet@ciao.gmane.io" User-Agent: Gnus/5.13 (Gnus v5.13) Cc: Spencer Baugh , emacs-devel@gnu.org To: Eli Zaretskii Original-X-From: emacs-devel-bounces+ged-emacs-devel=m.gmane-mx.org@gnu.org Sat Mar 02 17:40:18 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 1rgSPJ-00051G-2o for ged-emacs-devel@m.gmane-mx.org; Sat, 02 Mar 2024 17:40:18 +0100 Original-Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1rgSOb-0002mu-JW; Sat, 02 Mar 2024 11:39:33 -0500 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 1rgSOZ-0002md-VA for emacs-devel@gnu.org; Sat, 02 Mar 2024 11:39:31 -0500 Original-Received: from s.wfbtzhsv.outbound-mail.sendgrid.net ([159.183.224.104]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1rgSOX-0001KM-Mq for emacs-devel@gnu.org; Sat, 02 Mar 2024 11:39:31 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=catern.com; h=from:subject:in-reply-to:references:mime-version:to:cc:content-type: content-transfer-encoding:cc:content-type:from:subject:to; s=s1; bh=1CkLe13aWvjwJZax1se8wSYTGnNGtryAHWAKpJb5VO4=; b=wK99B2Afz20bzsuVB2zj24adpgT+9/6fyX4guyMuIsmS5XI8FXrVAg6Po574uKkPx9Gc zm3VeEtblDW/GyYTUDlM09BbVOqu85Q2tARIaFMpVdvIKMLEj/Ye8+SseQKgW6Rf+5wdke SwvomGIGUpXt8eD/pL7NaHb3cK5GP6X1jFvy3VR/6N91qAaDMlEtvHQx1tqC3Hfo3azERT 2ZsWzAR/Vc1JF99hKL/Tu6kqXrA8PWja4tpUXcR8KcQze6W0uXJffDZFKCoUHPT4tzmcEk 16KLs3mI78IXoEzOFCYqXuq10qdajj3xQH3c04+kN2qyEe1aFt1C5auMUOLCi8cA== Original-Received: by filterdrecv-656b5b4c75-zckst with SMTP id filterdrecv-656b5b4c75-zckst-1-65E3563E-3 2024-03-02 16:39:26.402001981 +0000 UTC m=+2137100.746246263 Original-Received: from earth.catern.com (unknown) by geopod-ismtpd-25 (SG) with ESMTP id i7UEueyKSLSXlR7Uv2sR5w Sat, 02 Mar 2024 16:39:26.321 +0000 (UTC) Received-SPF: Pass (mailfrom) identity=mailfrom; client-ip=68.160.221.150; helo=localhost; envelope-from=sbaugh@catern.com; receiver=gnu.org Original-Received: from localhost (unknown [68.160.221.150]) by earth.catern.com (Postfix) with ESMTPSA id 003746007E; Sat, 2 Mar 2024 16:39:14 +0000 (UTC) In-Reply-To: <8634t9qgl2.fsf@gnu.org> (Eli Zaretskii's message of "Sat, 02 Mar 2024 08:43:21 +0200") X-SG-EID: =?us-ascii?Q?ZgbRq7gjGrt0q=2FPjvxk7wM0yQFRdOkTJAtEbkjCkHbJCPWyED=2FmRdYY2ZfvLKL?= =?us-ascii?Q?P=2FBp07TzF+JDv2fge6gtl91Dyzj1mh17Slu=2F6sR?= =?us-ascii?Q?qiRhu5S48ZsW8f9=2Fa0cQWY5RS6ePWctaSC8Vbi5?= =?us-ascii?Q?iI=2FSEjpPNKpU2+wJLLV8pRs2bDtxAPJJPhxbNmZ?= =?us-ascii?Q?fFMZBtTUTGq1eoUuQTrHuonsracjTgF7CIA=3D=3D?= X-Entity-ID: d/0VcHixlS0t7iB1YKCv4Q== Received-SPF: pass client-ip=159.183.224.104; envelope-from=bounces+21787432-489d-emacs-devel=gnu.org@em8926.catern.com; helo=s.wfbtzhsv.outbound-mail.sendgrid.net X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_MSPIKE_H2=-0.001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001, T_SCC_BODY_TEXT_LINE=-0.01, UNPARSEABLE_RELAY=0.001 autolearn=ham autolearn_force=no X-Spam_action: no action 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:316703 Archived-At: Eli Zaretskii writes: >> From: Spencer Baugh >> Cc: emacs-devel@gnu.org >> Date: Fri, 01 Mar 2024 16:56:55 -0500 >> >> Eli Zaretskii writes: >> >> >> Then I would release the lock and call into my library, which does some >> >> useful work which takes a while. >> > >> > How is this different from starting your own native thread, then >> > releasing the lock? >> >> They are completely different things. > > I think there's a misunderstanding here, because I cannot see how they > could be "completely different things." See below. Oh, yes, you are correct, I didn't understand what you were proposing. Thank you for your patience, your longer explanation has made your proposal clear to me now. >> > If a C library provides some blocking function which does some >> > complicated form of IO, a module providing bindings for that C library >> > can release global_lock before calling that function, and then >> > re-acquire the lock after the function returns. Then Lisp threads >> > calling this module function will not block the main Emacs thread. >> >> So, if I am running the following program in a Lisp thread: >> >> (while (do-emacs-things) >> (let ((input (do-emacs-things))) >> (let ((result (call-into-native-module input))) >> (do-emacs-things result)))) >> >> and call-into-native-module unlocks the global lock around the calls >> into my library, then during the part of call-into-native-module which >> calls into my library, the main Emacs thread will not be blocked and can >> run in parallel with call-into-native-module. > > I'm saying that your call-into-native-module method could do the > following: > > . start a native thread running the call into your library > . release the global lock by calling thread-yield or sleep-for or > any other API which yields to other Lisp threads > . wait for the native thread to finish > . return when it succeeds to acquire the global lock following the > completion of the native thread > > The _only_ difference between the above and what you described is that > portions of call-into-native-module are run in a separate native > thread, and the Lisp thread which runs the above snippet keeps > yielding until the native thread finishes its job. How is this > "completely different"? Oh, yes, that is similar to what I'm proposing. Just to summarize, if call_into_native_module looks like: emacs_value call_into_native_module(emacs_env *env, emacs_value input) { native_value native_input = convert_to_native(env, input); native_value native_output; [...some code...] return convert_to_emacs(env, native_output); } Then the current state of the world ("hold the lock" model): native_output = some_native_function(native_input); If I understand correctly, you are proposing (the "new thread" model): native_thread_handle handle = native_thread_create(some_native_function, native_input); while (!native_thread_done(handle)) { emacs_thread_yield(env); } native_output = native_thread_result(handle); And I am proposing (the "release lock" model): release_global_lock(env); native_output = some_native_function(native_input); acquire_global_lock(env); All three of these are used in the same way from Lisp programs. But the "new thread" and "release lock" models have the advantage over the "hold the lock" model that if called from a Lisp thread, that Lisp thread will run some_native_function in parallel with Lisp execution on other Lisp threads, including the main Emacs thread. To check my understanding: does this all seem correct so far, and match your proposal? So, the main difference between the "new thread" model and the "release lock" model is that creating a native thread takes a nontrivial amount of time; maybe around 0.1 milliseconds. If some_native_function would takes less time than that, the thread creation cost will slow down Emacs, especially because the native module creates the native thread while holding the Lisp global_lock. Reducing the thread creation cost is quite hard; a thread pool can help, but that is complex and still has substantial cost in communication and context switching. So, to avoid the thread creation overhead, a native module should only create a native thread to run some_native_function if the native module knows that some_native_function will take a long time. Unfortunately, most of the time a native module can't know how long some_native_function will take before calling it. For example, native functions which make network calls might return immediately when there's already data available from the network, but will have to send new network requests sometimes. Or, native functions which provide an in-memory database might be fast or slow depending on the database contents. Since the native module doesn't know if some_native_function will take a long time, the native module needs a way to allow some_native_function to run in parallel which is cheap, so the native module can do it for all calls to some_native_function. The "release lock" model fits this need. Releasing the lock is essentially free, and allows some_native_function to run in parallel with other Lisp threads. Re-acquiring the lock afterwards will take time if the operating system switched to other Lisp threads which acquired the lock, but that's OK: the other Lisp threads are doing useful work in Lisp in parallel with call_into_native_module waiting for them to release the lock.