4

I use emacs in the terminal, typically with many emacs instances running at once in different tabs. This is a perfect use case for emacsclient, but it has always had various glitches that have stopped me from using it. In particular, sometimes one client will "block" the other, preventing it from doing anything. It looks like things work better in emacs 24.4, but it still happens.

For instance, if I start two clients, and run M-g M-g in one, to get the "Goto line" entry, the other client will be completely locked down until I quit in the first one.

I am using emacs 24.4 compiled without windowed support in Mac OS X 10.10 (in iTerm 2). I can reproduce it by starting emacs --daemon -Q. If you want the exact emacs binary I am using, download Miniconda for OS X and run conda install -c asmeurer emacs.

0
5

No, you can't "prevent emacsclient from blocking other [emacsclient] instances", because that's not what's happening.

emacsclient isn't running any elisp at all, so it's not the cause of the blockage. The Emacs server is running the elisp code, and Emacs is single-threaded -- so if the server thread is blocked then none of the clients will be receiving any output. There's nothing that a client can do about that.

You can, as mentioned in the comments, run multiple independent servers side by side. The simplest way to do this is via the --daemon=NAME command line argument:

emacs --daemon=foo
emacs --daemon=bar
emacsclient --socket-name=foo
emacsclient --socket-name=bar

or short-cut it to:

emacsclient -a "" --socket-name=foo
emacsclient -a "" --socket-name=bar
9
  • I guess this is workable. I can add export TTY=$(basename `tty`) in my bash profile and use --socket-name=$TTY. – asmeurer Nov 7 '14 at 17:25
  • A disadvantage here is that I no longer get any shared state if I open the same file in different instances. I would still very much appreciate an actual solution to this problem. – asmeurer Nov 7 '14 at 17:31
  • Even with this solution, emacsclient (or the server, whatever) will still sometimes completely block all clients, forcing me to find the PID for the server process and kill -9 it. – asmeurer Nov 7 '14 at 20:54
  • And just now I've got a server that even when I kill it, every time it restarts it immediately blocks, making it unusable. – asmeurer Nov 7 '14 at 21:18
  • 1
    This is not quite correct. Yes, everything runs on the server, and yes, the server is single threaded, but there is no technical reason for the minibuffer to block the server loop. You can see this in action by switching from the mini buffer to a different buffer while leaving the mini buffer open (with a partial command in it). There's got to be some internal lock getting set which blocks other clients (or the server itself if using server-start) while a minibuffer is open (focused or not). I'll see if I can find it and defadvice my way around it. – Perkins Feb 20 '20 at 2:46
2

Got it! Good news is it works perfectly to have the minibuffer active in one window and type in another*. Bad news is it requires recompiling emacs, as it's the C-implementation of read_minibuf which forces single-kboard. It's probably possible to reimplement the minibuffer largely in elisp, intercepting most calls to it, but that would be somewhat complex...

Anyway, with emacs-26, the line to comment is src/minibuf.c:480,

temporarily_switch_to_single_kboard (XFRAME (mini_frame));

*I've tested it some, no promises it won't break things in subtle ways. Also note that the minibuffer uses a single, global input state, so opening the mini buffer closes any mini buffers opened in other frames. If you enable recursive-minibuffers, you do get your partial command back when the other person is done, but there's still likely to be some odd behaviour. Also, things like find-file use switch_to_single_kboard too.

I'll probably follow up on the mailing list to see if this can get turned into a proper customizable variable, possibly disabling all switch_to_single_kboard calls, as it's a must for sharing an emacs instance on a joint project.

If you want to disable single-keyboard mode everywhere, insert return; on a new line at src/keyboard.c:883.

As requested, a diff...

*** src/minibuf.c       2020-02-20 17:27:13.472345220 -0800
--- src.orig/minibuf.c  2020-02-20 17:26:20.164343599 -0800
***************
*** 478,482 ****
      Fraise_frame (mini_frame);

<   //temporarily_switch_to_single_kboard (XFRAME (mini_frame));

    /* We have to do this after saving the window configuration
--- 478,482 ----
      Fraise_frame (mini_frame);

>   temporarily_switch_to_single_kboard (XFRAME (mini_frame));

        /* We have to do this after saving the window configuration

And the other diff

*** src/keyboard.c      2020-02-20 17:27:01.452344855 -0800
--- src.orig/keyboard.c 2020-02-20 17:26:15.040343443 -0800
***************
*** 881,885 ****
  temporarily_switch_to_single_kboard (struct frame *f)
  {
<   return false;
    bool was_locked = single_kboard;
--- 881,884 ----
4
  • 1
    That sounds like something I won't be trying :) Could you please show actual diffs in your answer? Only showing line numbers isn't nearly as useful. – phils Feb 20 '20 at 5:38
  • Note that this produces poor results in emacs-27 (and probably later), since partial commands are stored (and completed) globally. Then again, that's an issue even without unlocking multi-keyboard mode in the minibuffer. – Perkins Feb 22 '20 at 18:02
  • A year later, I've found and patched the emacs-27+ bug that breaks multiple keyboards. IfI ever hear back from the FSF about my copyright assignment I'll even get that fix included... So far, crickets. – Perkins Jan 31 at 1:34
  • Awesome; cheers. They're normally fairly responsive, so if you haven't heard anything within a few days, definitely chase that up (either directly, or on the emacs-devel mailing list). I'm sure that someone will sort you out. – phils Jan 31 at 19:38

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.