求助 MacOS File watching not possible, no file descriptor left

我是从这里安装的 Emacs,master

各位有兴趣的可以执行二楼一段 elisp 代码简单测试一下在你的电脑上有没有问题

开启 lsp watch mode 后,文件超过 975 个之后会报错

Failed to create a watch for File watching not possible, no file descriptor left: 975: message

Emacs 中可能相关的源码在这里 emacs/kqueue.c at 3af9e84ff59811734dcbb5d55e04e1fdb7051e77 · emacs-mirror/emacs · GitHub

  /* Check available file descriptors.  */
#ifdef HAVE_GETRLIMIT
  if (! getrlimit (RLIMIT_NOFILE, &rlim))
    maxfd = rlim.rlim_cur;
  else
#endif /* HAVE_GETRLIMIT  */
    maxfd = 256;

  /* We assume 50 file descriptors are sufficient for the rest of Emacs.  */
  ptrdiff_t watch_list_len = list_length (watch_list);
  if (maxfd - 50 < watch_list_len)
    xsignal2
      (Qfile_notify_error,
       build_string ("File watching not possible, no file descriptor left"),
       make_fixnum (watch_list_len));

看起来是通过 getrlimit 来查询的,于是我尝试这样启动 emacs

ulimit -n 9999 && /usr/local/bin/emacs

然后在 emacs 中用这段代码测试

#include <sys/types.h>
#include <sys/resource.h>
#include <stdio.h>

int main( void )
{
  int maxfd;

  struct rlimit rlim;

  if (! getrlimit (RLIMIT_NOFILE, &rlim))
    maxfd = rlim.rlim_cur;
  else
    maxfd = -1;

  printf("test      %d", maxfd);

  getchar();
  return 0;
}

在 shell mode 里执行,得到结果

test    9999

此时启动 lsp mode,依然得到一样的错误

Failed to create a watch for File watching not possible, no file descriptor left: 975: message

请问我哪里做的不对?如何正确进行设置?或者是否需要在编译 emacs 的时候修改某些参数/源码?
感谢各位🙏🏻

各位有兴趣的可以执行下面这段代码测试一下

(defun test (temp-path)
  (unless (file-exists-p temp-path)
    (make-directory temp-path))
  (dotimes (i 1024)
    (let ((file-path (concat temp-path (number-to-string i))))
      (unless (file-exists-p file-path)
        (with-temp-buffer (write-file file-path)))
      (file-notify-add-watch file-path '(change) (lambda (event) nil)))))

(test "/tmp/emacs-file-watch-test/")

ulimit -n 9999 并没有用

我研究了下,应該是因为这一行代码的问題。

1024 也是 glibc 的默认值,但是不知道为啥这个限制在 Linux 上就不会起作用。

加上这行的原因: https://gnu.emacs.bug.narkive.com/rNcvPeTp/bug-40023-26-3-emacs-crashes-when-creating-process-if-many-file-handles-are-in-use-e-g-when-using

1 个赞

所以怎么在编译的时候增大 FD_SETSIZE 的值?

在这行后面加个 define 应該就行。

1 个赞

感谢,我去试试看

修改过后果然不再报错了,但是运行会不稳定,测试的时候有崩溃的现象,监听文件数量超过 1024 会非常不稳。

你改到多大了?一般 4000 以内还是没问题的。

FD_SETSIZE 改到了 2048,但是我这边实际监听超过大概 1024 就不稳定

Using ‘poll’ would help, but as far as I know nobody is working on converting emacs to use it.

那就得有人给 emacs 提交这个功能了

GNU/Linux 上也会起到作用,不过默认使用的是 GLib 提供的 file notifications,GLib 会在 xgselect.c 中用到 poll。

macOS 上用不了 glib,因为 NS 自己的事件循环不兼容 glib。

1 个赞