From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.io!.POSTED.blaine.gmane.org!not-for-mail From: Stefan Monnier via "Bug reports for GNU Emacs, the Swiss army knife of text editors" Newsgroups: gmane.emacs.bugs Subject: bug#70221: [PATCH] New function `funcall-later` Date: Fri, 05 Apr 2024 15:56:40 -0400 Message-ID: Reply-To: Stefan Monnier Mime-Version: 1.0 Content-Type: multipart/mixed; boundary="=-=-=" Injection-Info: ciao.gmane.io; posting-host="blaine.gmane.org:116.202.254.214"; logging-data="34397"; mail-complaints-to="usenet@ciao.gmane.io" To: 70221@debbugs.gnu.org Original-X-From: bug-gnu-emacs-bounces+geb-bug-gnu-emacs=m.gmane-mx.org@gnu.org Fri Apr 05 22:00:29 2024 Return-path: Envelope-to: geb-bug-gnu-emacs@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 1rspjg-0008fC-1k for geb-bug-gnu-emacs@m.gmane-mx.org; Fri, 05 Apr 2024 22:00:28 +0200 Original-Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1rspjF-000711-5E; Fri, 05 Apr 2024 16:00:01 -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 1rspjB-0006zG-Jb for bug-gnu-emacs@gnu.org; Fri, 05 Apr 2024 15:59:57 -0400 Original-Received: from debbugs.gnu.org ([2001:470:142:5::43]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1rspjB-0001Ro-BR for bug-gnu-emacs@gnu.org; Fri, 05 Apr 2024 15:59:57 -0400 Original-Received: from Debian-debbugs by debbugs.gnu.org with local (Exim 4.84_2) (envelope-from ) id 1rspjG-0003cg-OG for bug-gnu-emacs@gnu.org; Fri, 05 Apr 2024 16:00:02 -0400 X-Loop: help-debbugs@gnu.org Resent-From: Stefan Monnier Original-Sender: "Debbugs-submit" Resent-CC: bug-gnu-emacs@gnu.org Resent-Date: Fri, 05 Apr 2024 20:00:02 +0000 Resent-Message-ID: Resent-Sender: help-debbugs@gnu.org X-GNU-PR-Message: report 70221 X-GNU-PR-Package: emacs X-GNU-PR-Keywords: patch X-Debbugs-Original-To: bug-gnu-emacs@gnu.org Original-Received: via spool by submit@debbugs.gnu.org id=B.171234719413845 (code B ref -1); Fri, 05 Apr 2024 20:00:02 +0000 Original-Received: (at submit) by debbugs.gnu.org; 5 Apr 2024 19:59:54 +0000 Original-Received: from localhost ([127.0.0.1]:37538 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1rspj6-0003ao-3q for submit@debbugs.gnu.org; Fri, 05 Apr 2024 15:59:54 -0400 Original-Received: from lists.gnu.org ([2001:470:142::17]:55600) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1rspj3-0003Zw-24 for submit@debbugs.gnu.org; Fri, 05 Apr 2024 15:59:50 -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 1rspir-0006uG-Js for bug-gnu-emacs@gnu.org; Fri, 05 Apr 2024 15:59:37 -0400 Original-Received: from mailscanner.iro.umontreal.ca ([132.204.25.50]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1rspio-0001Ot-SH for bug-gnu-emacs@gnu.org; Fri, 05 Apr 2024 15:59:37 -0400 Original-Received: from pmg2.iro.umontreal.ca (localhost.localdomain [127.0.0.1]) by pmg2.iro.umontreal.ca (Proxmox) with ESMTP id 5D76A80C41 for ; Fri, 5 Apr 2024 15:59:33 -0400 (EDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=iro.umontreal.ca; s=mail; t=1712347170; bh=UqfkEngsOSumEQTMBGp3gsRNzj0p3/2RHUDIExdn7/U=; h=From:To:Subject:Date:From; b=oOs/Bqg98e05LDW2hjSTH9+DqQLo6oE53IfOi5RY2CI+840QKDD8r0ezd2lpEWAJv COhkdEaS3oq9dKTfmjjSk2tx4kPr5fD/lyuIkl3GmDwE2RjZoJ9ficCM0YDvRvrrA7 wvpuIbWin/HL2RudumsSEwMAEC8YvZ+z0G31eD2raOtSxGrSEJqVTZ8QM82WGVYO/i JilBrHfGnhl+GQs8/I1+1Q947hHJZYEWsKPWjPzNeRG3YByaLQCHc6dI4ZGsGtiB+4 RHu8uKopOvBFRdXQOdc1PLhakoTsFchB7RYUwk0iKyv4rXNw+iRDMm7Wu8Uy1v/4kE KHBb12gIXrDpA== Original-Received: from mail01.iro.umontreal.ca (unknown [172.31.2.1]) by pmg2.iro.umontreal.ca (Proxmox) with ESMTP id 7848D8009D for ; Fri, 5 Apr 2024 15:59:30 -0400 (EDT) Original-Received: from lechazo (lechon.iro.umontreal.ca [132.204.27.242]) by mail01.iro.umontreal.ca (Postfix) with ESMTPSA id 6B321120193 for ; Fri, 5 Apr 2024 15:59:30 -0400 (EDT) Received-SPF: pass client-ip=132.204.25.50; envelope-from=monnier@iro.umontreal.ca; helo=mailscanner.iro.umontreal.ca X-Spam_score_int: -42 X-Spam_score: -4.3 X-Spam_bar: ---- X-Spam_report: (-4.3 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, RCVD_IN_DNSWL_MED=-2.3, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list X-BeenThere: bug-gnu-emacs@gnu.org List-Id: "Bug reports for GNU Emacs, the Swiss army knife of text editors" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: bug-gnu-emacs-bounces+geb-bug-gnu-emacs=m.gmane-mx.org@gnu.org Original-Sender: bug-gnu-emacs-bounces+geb-bug-gnu-emacs=m.gmane-mx.org@gnu.org Xref: news.gmane.io gmane.emacs.bugs:282722 Archived-At: --=-=-= Content-Type: text/plain Tags: patch In the patch(es) below I suggest the addition of a new function `funcall-later` which exposes the already existing `pending_funcalls` mechanism to ELisp and fixes it so those are processed in the correct order and so they're not just thrown away when used in batch mode. `run-with-timer` does largely the same thing when passed a 0 timeout and no repetition, but it is a bit more costly and relies on the timers, which don't work as well in batch mode. Stefan In GNU Emacs 30.0.50 (build 1, i686-pc-linux-gnu, GTK+ Version 3.24.41, cairo version 1.18.0) of 2024-03-27 built on lechazo Repository revision: a13cfe9bb17448e104dc86b7a33761ca60297871 Repository branch: work Windowing system distributor 'The X.Org Foundation', version 11.0.12101011 System Description: Debian GNU/Linux trixie/sid Configured using: 'configure -C --enable-checking --enable-check-lisp-object-type --with-modules --with-cairo --with-tiff=ifavailable 'CFLAGS=-Wall -g3 -Og -Wno-pointer-sign' --without-native-compilation PKG_CONFIG_PATH=/home/monnier/lib/pkgconfig' --=-=-= Content-Type: text/patch Content-Disposition: attachment; filename=0001-Ffuncall_later-New-function-to-expose-pending_funcal.patch >From 0041d6272d91baceada67aec04a0bca66a64919b Mon Sep 17 00:00:00 2001 From: Stefan Monnier Date: Fri, 5 Apr 2024 14:58:53 -0400 Subject: [PATCH 1/2] (Ffuncall_later): New function to expose 'pending_funcalls' to ELisp * src/keyboard.c (pending_funcalls): Make static. (pending_funcalls_r): New var. (Ffuncall_later): New Lisp function. (Frun_pending_funcalls): New function, extracted from 'timer_check_2'. Improve the code to preserve the order in which functions were added. (timer_check_2): Use it. (syms_of_keyboard): Initialize and staticpro 'pending_funcalls_r', and defsubr 'Sfuncall_later' and 'Srun_pending_funcalls'. (syms_of_keyboard_for_pdumper): Reset 'pending_funcalls_r'. * lisp/startup.el (command-line): Run pending funcalls before exiting, in batch mode. * src/lisp.h (pending_funcalls): Remove declaration. * src/frame.c (delete_frame): * src/terminal.c (Fdelete_terminal): * src/comp.c (maybe_defer_native_compilation): Use 'Ffuncall_later'. --- etc/NEWS | 4 ++++ lisp/startup.el | 2 +- src/comp.c | 4 +--- src/frame.c | 10 ++++------ src/keyboard.c | 47 +++++++++++++++++++++++++++++++++++++---------- src/lisp.h | 1 - src/terminal.c | 6 ++---- 7 files changed, 49 insertions(+), 25 deletions(-) diff --git a/etc/NEWS b/etc/NEWS index 32cec82f970..8e8cbcdeb5d 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -1761,6 +1761,10 @@ correctly UTF-8 encoded. * Lisp Changes in Emacs 30.1 +** New function 'funcall-later', to run code at the next convenient time. +This is very similar to 'run-with-timer' with a 0 time argument, but cheaper +and it also works in batch mode. + ** New function 'help-fns-function-name'. For named functions, it just returns the name and otherwise it returns a short "unique" string that identifies the function. diff --git a/lisp/startup.el b/lisp/startup.el index 357a4154e4c..c105886908c 100644 --- a/lisp/startup.el +++ b/lisp/startup.el @@ -1630,7 +1630,7 @@ command-line :warning)))) ;; If -batch, terminate after processing the command options. - (if noninteractive (kill-emacs t)) + (when noninteractive (internal--run-pending-funcalls) (kill-emacs t)) ;; In daemon mode, start the server to allow clients to connect. ;; This is done after loading the user's init file and after diff --git a/src/comp.c b/src/comp.c index 99f51e07048..f59881a1b84 100644 --- a/src/comp.c +++ b/src/comp.c @@ -5217,9 +5217,7 @@ maybe_defer_native_compilation (Lisp_Object function_name, Fputhash (function_name, definition, Vcomp_deferred_pending_h); - pending_funcalls - = Fcons (list (Qnative__compile_async, src, Qnil, Qlate), - pending_funcalls); + CALLN (Ffuncall_later, Qnative__compile_async, src, Qnil, Qlate); } diff --git a/src/frame.c b/src/frame.c index abd6ef00901..f2ed55046d6 100644 --- a/src/frame.c +++ b/src/frame.c @@ -2138,9 +2138,8 @@ delete_frame (Lisp_Object frame, Lisp_Object force) if (NILP (Vrun_hooks) || is_tooltip_frame) ; else if (EQ (force, Qnoelisp)) - pending_funcalls - = Fcons (list3 (Qrun_hook_with_args, Qdelete_frame_functions, frame), - pending_funcalls); + CALLN (Ffuncall_later, Qrun_hook_with_args, + Qdelete_frame_functions, frame); else { #ifdef HAVE_X_WINDOWS @@ -2456,9 +2455,8 @@ delete_frame (Lisp_Object frame, Lisp_Object force) if (NILP (Vrun_hooks) || is_tooltip_frame) ; else if (EQ (force, Qnoelisp)) - pending_funcalls - = Fcons (list3 (Qrun_hook_with_args, Qafter_delete_frame_functions, frame), - pending_funcalls); + CALLN (Ffuncall_later, Qrun_hook_with_args, + Qafter_delete_frame_functions, frame); else safe_calln (Qrun_hook_with_args, Qafter_delete_frame_functions, frame); diff --git a/src/keyboard.c b/src/keyboard.c index 91faf4582fa..45f7295d5d1 100644 --- a/src/keyboard.c +++ b/src/keyboard.c @@ -4624,10 +4624,38 @@ timer_resume_idle (void) timer_idleness_start_time = timer_last_idleness_start_time; } -/* List of elisp functions to call, delayed because they were generated in - a context where Elisp could not be safely run (e.g. redisplay, signal, +/* List of elisp functions to call, delayed e.g. because they were generated in + a context where that code could not be safely run (e.g. redisplay, signal, ...). Each element has the form (FUN . ARGS). */ -Lisp_Object pending_funcalls; +static Lisp_Object pending_funcalls, pending_funcalls_r; + +DEFUN ("funcall-later", Ffuncall_later, Sfuncall_later, 1, MANY, 0, + doc: /* Schedule FUNCTION for later execution. +It will be called a soon as possible with ARGS, but not now. */) + (ptrdiff_t nargs, Lisp_Object *args) +{ + pending_funcalls_r = Fcons (Flist (nargs, args), pending_funcalls_r); + return Qnil; +} + +DEFUN ("internal--run-pending-funcalls", Frun_pending_funcalls, Srun_pending_funcalls, 0, 0, 0, + doc: /* Run the still pending `funcall-later'. */) + (void) +{ + while (CONSP (pending_funcalls) || CONSP (pending_funcalls_r)) + if (CONSP (pending_funcalls)) + { + Lisp_Object funcall = XCAR (pending_funcalls); + pending_funcalls = XCDR (pending_funcalls); + CALLN (Fapply, funcall); + } + else + { + pending_funcalls = Fnreverse (pending_funcalls_r); + pending_funcalls_r = Qnil; + } + return Qnil; +} /* Return true if TIMER is a valid timer, placing its value into *RESULT. */ static bool @@ -4671,12 +4699,7 @@ timer_check_2 (Lisp_Object timers, Lisp_Object idle_timers) chosen_timer = Qnil; /* First run the code that was delayed. */ - while (CONSP (pending_funcalls)) - { - Lisp_Object funcall = XCAR (pending_funcalls); - pending_funcalls = XCDR (pending_funcalls); - safe_calln (Qapply, XCAR (funcall), XCDR (funcall)); - } + Frun_pending_funcalls (); if (CONSP (timers) || CONSP (idle_timers)) { @@ -12783,8 +12806,9 @@ is_ignored_event (union buffered_input_event *event) void syms_of_keyboard (void) { - pending_funcalls = Qnil; + pending_funcalls = pending_funcalls_r = Qnil; staticpro (&pending_funcalls); + staticpro (&pending_funcalls_r); Vlispy_mouse_stem = build_pure_c_string ("mouse"); staticpro (&Vlispy_mouse_stem); @@ -13084,6 +13108,8 @@ syms_of_keyboard (void) defsubr (&Scurrent_idle_time); defsubr (&Sevent_symbol_parse_modifiers); defsubr (&Sevent_convert_list); + defsubr (&Sfuncall_later); + defsubr (&Srun_pending_funcalls); defsubr (&Sinternal_handle_focus_in); defsubr (&Sread_key_sequence); defsubr (&Sread_key_sequence_vector); @@ -13855,6 +13881,7 @@ syms_of_keyboard_for_pdumper (void) early init functions see the environment they expect. */ PDUMPER_RESET_LV (pending_funcalls, Qnil); + PDUMPER_RESET_LV (pending_funcalls_r, Qnil); PDUMPER_RESET_LV (unread_switch_frame, Qnil); PDUMPER_RESET_LV (internal_last_event_frame, Qnil); PDUMPER_RESET_LV (last_command_event, Qnil); diff --git a/src/lisp.h b/src/lisp.h index 3cb4361e75e..d9308cbc6dd 100644 --- a/src/lisp.h +++ b/src/lisp.h @@ -5106,7 +5106,6 @@ fast_c_string_match_ignore_case (Lisp_Object regexp, #if defined (USABLE_SIGIO) || defined (USABLE_SIGPOLL) void handle_input_available_signal (int); #endif -extern Lisp_Object pending_funcalls; extern bool detect_input_pending (void); extern bool detect_input_pending_ignore_squeezables (void); extern bool detect_input_pending_run_timers (bool); diff --git a/src/terminal.c b/src/terminal.c index 23a5582d4d9..fd13ba90792 100644 --- a/src/terminal.c +++ b/src/terminal.c @@ -384,10 +384,8 @@ DEFUN ("delete-terminal", Fdelete_terminal, Sdelete_terminal, 0, 2, 0, if (NILP (Vrun_hooks)) ; else if (EQ (force, Qnoelisp)) - pending_funcalls - = Fcons (list3 (Qrun_hook_with_args, - Qdelete_terminal_functions, terminal), - pending_funcalls); + CALLN (Ffuncall_later, Qrun_hook_with_args, + Qdelete_terminal_functions, terminal); else safe_calln (Qrun_hook_with_args, Qdelete_terminal_functions, terminal); -- 2.43.0 --=-=-= Content-Type: text/patch Content-Disposition: inline; filename=0002-lisp-Prefer-funcall-later-over-run-with-timer.patch >From 24d444a272bd4b42739a1883c4d5f0545dfce58a Mon Sep 17 00:00:00 2001 From: Stefan Monnier Date: Fri, 5 Apr 2024 15:49:34 -0400 Subject: [PATCH 2/2] lisp: Prefer 'funcall-later' over 'run-with-timer' * lisp/subr.el (do-after-load-evaluation): * lisp/server.el (server-goto-toplevel): * lisp/progmodes/compile.el (compilation-error-properties): * lisp/menu-bar.el (menu-bar-mode): * lisp/jit-lock.el (jit-lock-fontify-now): * lisp/emacs-lisp/edebug.el (edebug-kill-buffer) (edebug-unload-function): Use 'funcall-later' i.s.o 'run-with-timer'. --- lisp/emacs-lisp/edebug.el | 4 ++-- lisp/jit-lock.el | 6 +++--- lisp/menu-bar.el | 6 +++--- lisp/progmodes/compile.el | 4 ++-- lisp/server.el | 2 +- lisp/subr.el | 3 +-- 6 files changed, 12 insertions(+), 13 deletions(-) diff --git a/lisp/emacs-lisp/edebug.el b/lisp/emacs-lisp/edebug.el index b27ffbca908..fc76552312f 100644 --- a/lisp/emacs-lisp/edebug.el +++ b/lisp/emacs-lisp/edebug.el @@ -4023,7 +4023,7 @@ edebug-mode (defun edebug-kill-buffer () "Used on `kill-buffer-hook' when Edebug is operating in a buffer of Lisp code." - (run-with-timer 0 nil #'top-level)) + (funcall-later #'top-level)) ;;; edebug eval list mode @@ -4597,7 +4597,7 @@ edebug-unload-function (unwind-protect (abort-recursive-edit) ;; We still want to run unload-feature to completion - (run-with-idle-timer 0 nil #'(lambda () (unload-feature 'edebug))))) + (funcall-later #'unload-feature 'edebug))) (remove-hook 'called-interactively-p-functions #'edebug--called-interactively-skip) (edebug-uninstall-read-eval-functions) diff --git a/lisp/jit-lock.el b/lisp/jit-lock.el index 05c0bd847b3..14c172c1e6a 100644 --- a/lisp/jit-lock.el +++ b/lisp/jit-lock.el @@ -478,9 +478,9 @@ jit-lock-fontify-now ;; eagerly extend the refontified region with ;; jit-lock-after-change-extend-region-functions. (when (< loose-beg orig-start) - (run-with-timer 0 nil #'jit-lock-force-redisplay - (copy-marker loose-beg) - (copy-marker orig-start))) + (funcall-later #'jit-lock-force-redisplay + (copy-marker loose-beg) + (copy-marker orig-start))) ;; Skip to the end of the fully refontified part. (setq start tight-end))) diff --git a/lisp/menu-bar.el b/lisp/menu-bar.el index 320fabb54cf..7a4de133b74 100644 --- a/lisp/menu-bar.el +++ b/lisp/menu-bar.el @@ -2632,9 +2632,9 @@ menu-bar-mode ;; directly. The minor-mode message "Menu Bar mode disabled" comes ;; after this function returns, overwriting any message we do here. (when (and (called-interactively-p 'interactive) (not menu-bar-mode)) - (run-with-idle-timer 0 nil 'message - (substitute-command-keys - "Menu Bar mode disabled. \ + (funcall-later #'message + (substitute-command-keys + "Menu Bar mode disabled. \ Use \\[menu-bar-mode] to make the menu bar appear.")))) ;;;###autoload diff --git a/lisp/progmodes/compile.el b/lisp/progmodes/compile.el index 11d400e145a..952f03d3155 100644 --- a/lisp/progmodes/compile.el +++ b/lisp/progmodes/compile.el @@ -1402,8 +1402,8 @@ compilation-error-properties (when (and compilation-auto-jump-to-next (>= type compilation-skip-threshold)) (kill-local-variable 'compilation-auto-jump-to-next) - (run-with-timer 0 nil 'compilation-auto-jump - (current-buffer) (match-beginning 0))) + (funcall-later #'compilation-auto-jump + (current-buffer) (match-beginning 0))) (compilation-internal-error-properties file line end-line col end-col type fmt rule)))) diff --git a/lisp/server.el b/lisp/server.el index b65053267a6..8e3c1d0a467 100644 --- a/lisp/server.el +++ b/lisp/server.el @@ -1031,7 +1031,7 @@ server-goto-toplevel ;; to open a frame on a new display, we might end up with an unusable ;; frame because input from that display will be blocked (until exiting ;; the minibuffer). Better exit this minibuffer right away. - (run-with-timer 0 nil (lambda () (server-execute-continuation proc))) + (funcall-later #'server-execute-continuation proc) (top-level))) ;; We use various special properties on process objects: diff --git a/lisp/subr.el b/lisp/subr.el index fba70342154..20fdf8deded 100644 --- a/lisp/subr.el +++ b/lisp/subr.el @@ -5981,8 +5981,7 @@ do-after-load-evaluation byte-compile-current-file byte-compile-root-dir))) (byte-compile-warn "%s" msg))) - (noninteractive (funcall fun msg)) ;; No timer will be run! - (t (run-with-idle-timer 0 nil fun msg)))))) + (t (funcall-later fun msg)))))) ;; Finally, run any other hook. (run-hook-with-args 'after-load-functions abs-file)) -- 2.43.0 --=-=-=--