diff options
author | Jean Boussier <byroot@ruby-lang.org> | 2023-02-16 19:36:31 +0100 |
---|---|---|
committer | Jean Boussier <jean.boussier@gmail.com> | 2023-03-20 08:21:23 +0000 |
commit | 1db8951d3a8be6a756c9d3d3b87231997b301985 (patch) | |
tree | 450ed624fb3b8afc145ef2fd3e85258f64b08bf3 /process.c | |
parent | 70ea58bd5ba42b26ff39f51079af0efa422ac036 (diff) | |
download | ruby-1db8951d3a8be6a756c9d3d3b87231997b301985.tar.gz |
Cache `Process.pid`
[Feature #19443]
It's not uncommon for database client and similar network libraries
to protect themselves from Process.fork by regularly checking Process.pid
Until recently most libc would cache `getpid()` so this was a cheap
check to make.
However as of glibc version 2.25 the PID cache is removed and calls to
`getpid()` always invoke the actual system call which significantly degrades
the performance of existing applications.
The reason glibc removed the cache is that some libraries were bypassing
`fork(2)` by issuing system calls themselves, causing stale cache issues.
That isn't a concern for Ruby as bypassing MRI's primitive for forking
would render the VM unusable, so we can safely cache the PID.
Diffstat (limited to 'process.c')
-rw-r--r-- | process.c | 24 |
1 files changed, 21 insertions, 3 deletions
@@ -359,6 +359,8 @@ static ID id_MACH_ABSOLUTE_TIME_BASED_CLOCK_MONOTONIC; #endif static ID id_hertz; +static VALUE cached_pid = Qnil; + /* execv and execl are async-signal-safe since SUSv4 (POSIX.1-2008, XPG7) */ #if defined(__sun) && !defined(_XPG7) /* Solaris 10, 9, ... */ #define execv(path, argv) (rb_async_bug_errno("unreachable: async-signal-unsafe execv() is called", 0)) @@ -497,7 +499,23 @@ parent_redirect_close(int fd) static VALUE get_pid(void) { - return PIDT2NUM(getpid()); + if (UNLIKELY(NIL_P(cached_pid))) { + cached_pid = PIDT2NUM(getpid()); + } + return cached_pid; +} + +static void +clear_pid_cache(void) +{ + cached_pid = Qnil; +} + +static inline void +rb_process_atfork(void) +{ + clear_pid_cache(); + rb_thread_atfork(); /* calls mjit_resume() */ } /* @@ -4059,7 +4077,7 @@ rb_fork_ruby2(struct rb_process_status *status) disable_child_handler_fork_parent(&old); /* yes, bad name */ if (pid >= 0) { /* fork succeed */ - if (pid == 0) rb_thread_atfork(); + if (pid == 0) rb_process_atfork(); return pid; } @@ -6832,7 +6850,7 @@ rb_daemon(int nochdir, int noclose) before_fork_ruby(); err = daemon(nochdir, noclose); after_fork_ruby(); - rb_thread_atfork(); + rb_process_atfork(); #else int n; |