GNU Emacs as a LISP interpreter
After applying the following patch, you can run GNU Emacs as a standalone LISP interpreter for batch usage. It basically disables the command loop and non-essential symbols in batch mode.
temacs is Emacs sans any bootstrap elisp code. It is the first artifact generated during the Emacs build process. So you might not find it in your package installation. You can use the emacs binary too for the same effect - just understand that underneath they are not the same.
modified src/keyboard.c
@@ -1067,6 +1067,7 @@ command_loop (void)
while (1)
{
internal_catch (Qtop_level, top_level_1, Qnil);
+ if (!noninteractive)
internal_catch (Qtop_level, command_loop_2, Qnil);
executing_kbd_macro = Qnil;
@@ -2631,9 +2632,9 @@ read_char (int commandflag, Lisp_Object map,
if (minibuf_level == 0
&& !end_time
&& !current_kboard->immediate_echo
+ && ! noninteractive
&& (this_command_key_count > 0
|| !NILP (call0 (Qinternal_echo_keystrokes_prefix)))
- && ! noninteractive
&& echo_keystrokes_p ()
&& (/* No message. */
NILP (echo_area_buffer[0])
@@ -4166,6 +4167,7 @@ timer_start_idle (void)
timer_last_idleness_start_time = timer_idleness_start_time;
/* Mark all idle-time timers as once again candidates for running. */
+ if (INTERACTIVE)
call0 (intern ("internal-timer-start-idle"));
}
modified src/lread.c
@@ -1030,7 +1030,9 @@ load_error_handler (Lisp_Object data)
static void
load_warn_unescaped_character_literals (Lisp_Object file)
{
- Lisp_Object warning = call0 (Qbyte_run_unescaped_character_literals_warning);
+ Lisp_Object warning = Qnil;
+ if (INTERACTIVE)
+ call0 (Qbyte_run_unescaped_character_literals_warning);
if (!NILP (warning))
{
AUTO_STRING (format, "Loading `%s': %s");
@@ -1067,6 +1067,7 @@ command_loop (void)
while (1)
{
internal_catch (Qtop_level, top_level_1, Qnil);
+ if (!noninteractive)
internal_catch (Qtop_level, command_loop_2, Qnil);
executing_kbd_macro = Qnil;
@@ -2631,9 +2632,9 @@ read_char (int commandflag, Lisp_Object map,
if (minibuf_level == 0
&& !end_time
&& !current_kboard->immediate_echo
+ && ! noninteractive
&& (this_command_key_count > 0
|| !NILP (call0 (Qinternal_echo_keystrokes_prefix)))
- && ! noninteractive
&& echo_keystrokes_p ()
&& (/* No message. */
NILP (echo_area_buffer[0])
@@ -4166,6 +4167,7 @@ timer_start_idle (void)
timer_last_idleness_start_time = timer_idleness_start_time;
/* Mark all idle-time timers as once again candidates for running. */
+ if (INTERACTIVE)
call0 (intern ("internal-timer-start-idle"));
}
modified src/lread.c
@@ -1030,7 +1030,9 @@ load_error_handler (Lisp_Object data)
static void
load_warn_unescaped_character_literals (Lisp_Object file)
{
- Lisp_Object warning = call0 (Qbyte_run_unescaped_character_literals_warning);
+ Lisp_Object warning = Qnil;
+ if (INTERACTIVE)
+ call0 (Qbyte_run_unescaped_character_literals_warning);
if (!NILP (warning))
{
AUTO_STRING (format, "Loading `%s': %s");
Threads
Here's a thread example in lisp. Create a file a.el with following content. Some points to remember:
- Note that you need to use load and not require for loading a file.
- When the parent process exits, all children threads are killed. Hence you need to use thread-join at the end to avoid that.
- Emacs Lisp mutexes are of a type called recursive, which means that a thread can re-acquire a mutex it owns any number of times. A mutex keeps a count of how many times it has been acquired, and each acquisition of a mutex must be paired with a release.
- systhread.c (and not thread.c) has the wrapper implementation around pthreads.
;; For defun
(load "emacs-lisp/byte-run")
;; For with-mutex
(load "subr")
(load "emacs-lisp/byte-run")
;; For with-mutex
(load "subr")
;; Unset global-var
(setq global-var nil)
;; Create a mutex and an associated condition variable
(setq mutex (make-mutex "mutex"))
(setq cond-var (make-condition-variable mutex "cond-var"))
;; Read and set functions used by read and set threads
(defun read-global-var ()
(message "read: global-var = %s ... reading" global-var)
(with-mutex mutex
(while (not global-var)
;; condition-wait is a blocking function. The thread will block here.
(condition-wait cond-var))
(message "read: global-var = %-3s ... exiting" global-var)))
(defun set-global-var ()
(with-mutex mutex
(progn
(message "set: Sleeping for 5s before setting global-var")
(sleep-for 5)
(message "set: Setting global-var")
(setq global-var "1")
(condition-notify cond-var))))
;; Create and start set thread
(make-thread 'set-global-var)
;; Create, start and wait for read to finish
(thread-join (make-thread 'read-global-var))
When you execute the script you should see following output.
anand@PureBook:~/work/emacs/src$ ./temacs -batch -nl -l $PWD/a.el
Loading /home/anand/work/emacs/src/a.el (source)...
Loading emacs-lisp/byte-run...
Loading subr...
set: Sleeping for 5s before setting global-var
read: global-var = nil ... reading
set: Setting global-var
read: global-var = 1 ... exiting
Loading /home/anand/work/emacs/src/a.el (source)...
Loading emacs-lisp/byte-run...
Loading subr...
set: Sleeping for 5s before setting global-var
read: global-var = nil ... reading
set: Setting global-var
read: global-var = 1 ... exiting
Minix
For running this on Minix, following is one tested configuration of Emacs (fork of Emacs - minix branch).
configure --without-all --without-x --without-makeinfo --with-mailutils
References
- Threads API in Emacs
Comments
Post a Comment