Now that all layers in the stack support memfd blocks, use memfd pools for the global core mempool by default. Also introduce "disable-memfd" daemon argument and configuration option to disable memfd support at run-time, if desired. Signed-off-by: Ahmed S. Darwish <darwish.07 at gmail.com> --- man/pulse-daemon.conf.5.xml.in | 5 +++++ man/pulseaudio.1.xml.in | 11 +++++++++++ shell-completion/bash/pulseaudio | 4 ++-- shell-completion/zsh/_pulseaudio | 1 + src/daemon/cmdline.c | 13 ++++++++++++- src/daemon/daemon-conf.c | 1 + src/daemon/daemon-conf.h | 1 + src/daemon/main.c | 4 +++- src/pulsecore/core.c | 9 ++++++--- src/pulsecore/core.h | 2 +- src/pulsecore/protocol-native.c | 31 ++++++++++++++++++++++++------- 11 files changed, 67 insertions(+), 15 deletions(-) diff --git a/man/pulse-daemon.conf.5.xml.in b/man/pulse-daemon.conf.5.xml.in index 0367b1f..7530e6f 100644 --- a/man/pulse-daemon.conf.5.xml.in +++ b/man/pulse-daemon.conf.5.xml.in @@ -195,6 +195,11 @@ License along with PulseAudio; if not, see <http://www.gnu.org/licenses/>. </option> <option> + <p><opt>disable-memfd=</opt>. Disable memfd shared memory. Takes + a boolean argument, defaults to <opt>no</opt>.</p> + </option> + + <option> <p><opt>shm-size-bytes=</opt> Sets the shared memory segment size for the daemon, in bytes. If left unspecified or is set to 0 it will default to some system-specific default, usually 64 diff --git a/man/pulseaudio.1.xml.in b/man/pulseaudio.1.xml.in index 650b417..e006178 100644 --- a/man/pulseaudio.1.xml.in +++ b/man/pulseaudio.1.xml.in @@ -300,6 +300,17 @@ License along with PulseAudio; if not, see <http://www.gnu.org/licenses/>. </option> <option> + <p><opt>--disable-memfd</opt><arg>[=BOOL]</arg></p> + + <optdesc><p>PulseAudio clients and the server can exchange audio + data via memfds - the anonymous Linux Kernel shared memory mechanism + (on kernels that support this). If disabled PulseAudio will + communicate via POSIX shared memory. If POSIX shared memory is also + is disabled (see above), then PulseAudio will exclusively communicate + over sockets. .</p></optdesc> + </option> + + <option> <p><opt>-L | --load</opt><arg>="MODULE ARGUMENTS"</arg></p> <optdesc><p>Load the specified plugin module with the specified diff --git a/shell-completion/bash/pulseaudio b/shell-completion/bash/pulseaudio index cfcf7ff..153a757 100644 --- a/shell-completion/bash/pulseaudio +++ b/shell-completion/bash/pulseaudio @@ -500,13 +500,13 @@ _pulseaudio() --realtime= --disallow-module-loading= --disallow-exit= --exit-idle-time= --scache-idle-time= --log-level= -v --log-target= --log-meta= --log-time= --log-backtrace= -p --dl-search-path= --resample-method= --use-pit-file= - --no-cpu-limit= --disable-shm= -L --load= -F --file= -C -n' + --no-cpu-limit= --disable-shm= --disable-memfd= -L --load= -F --file= -C -n' _init_completion -n = || return case $cur in --system=*|--daemonize=*|--fail=*|--high-priority=*|--realtime=*| \ --disallow-*=*|--log-meta=*|--log-time=*|--use-pid-file=*| \ - --no-cpu-limit=*|--disable-shm=*) + --no-cpu-limit=*|--disable-shm=*|--disable-memfd=*) cur=${cur#*=} COMPREPLY=($(compgen -W 'true false' -- "$cur")) ;; diff --git a/shell-completion/zsh/_pulseaudio b/shell-completion/zsh/_pulseaudio index c7d68f5..266383f 100644 --- a/shell-completion/zsh/_pulseaudio +++ b/shell-completion/zsh/_pulseaudio @@ -690,6 +690,7 @@ _pulseaudio_completion() { '--use-pid-file=[create a PID file]:bool:(true false)' \ '--no-cpu-limit=[do not install CPU load limiter]:bool:(true false)' \ '--disable-shm=[disable shared memory support]:bool:(true false)' \ + '--disable-memfd=[disable memfd shared memory support]:bool:(true false)' \ {-L,--load=}'[load the specified module]:modules:_all_modules' \ {-F,--file=}'[run the specified script]:file:_files' \ '-C[open a command line on the running tty]' \ diff --git a/src/daemon/cmdline.c b/src/daemon/cmdline.c index 117147d..66f6198 100644 --- a/src/daemon/cmdline.c +++ b/src/daemon/cmdline.c @@ -63,6 +63,7 @@ enum { ARG_CHECK, ARG_NO_CPU_LIMIT, ARG_DISABLE_SHM, + ARG_DISABLE_MEMFD, ARG_DUMP_RESAMPLE_METHODS, ARG_SYSTEM, ARG_CLEANUP_SHM, @@ -100,6 +101,7 @@ static const struct option long_options[] = { {"system", 2, 0, ARG_SYSTEM}, {"no-cpu-limit", 2, 0, ARG_NO_CPU_LIMIT}, {"disable-shm", 2, 0, ARG_DISABLE_SHM}, + {"disable-memfd", 2, 0, ARG_DISABLE_MEMFD}, {"dump-resample-methods", 2, 0, ARG_DUMP_RESAMPLE_METHODS}, {"cleanup-shm", 2, 0, ARG_CLEANUP_SHM}, {NULL, 0, 0, 0} @@ -152,7 +154,8 @@ void pa_cmdline_help(const char *argv0) { " --use-pid-file[=BOOL] Create a PID file\n" " --no-cpu-limit[=BOOL] Do not install CPU load limiter on\n" " platforms that support it.\n" - " --disable-shm[=BOOL] Disable shared memory support.\n\n" + " --disable-shm[=BOOL] Disable shared memory support.\n" + " --disable-memfd[=BOOL] Disable memfd shared memory support.\n\n" "STARTUP SCRIPT:\n" " -L, --load=\"MODULE ARGUMENTS\" Load the specified plugin module with\n" @@ -389,6 +392,14 @@ int pa_cmdline_parse(pa_daemon_conf *conf, int argc, char *const argv [], int *d conf->disable_shm = !!b; break; + case ARG_DISABLE_MEMFD: + if ((b = optarg ? pa_parse_boolean(optarg) : 1) < 0) { + pa_log(_("--disable-memfd expects boolean argument")); + goto fail; + } + conf->disable_memfd = !!b; + break; + default: goto fail; } diff --git a/src/daemon/daemon-conf.c b/src/daemon/daemon-conf.c index 288aed2..a368da5 100644 --- a/src/daemon/daemon-conf.c +++ b/src/daemon/daemon-conf.c @@ -525,6 +525,7 @@ int pa_daemon_conf_load(pa_daemon_conf *c, const char *filename) { { "no-cpu-limit", pa_config_parse_bool, &c->no_cpu_limit, NULL }, { "cpu-limit", pa_config_parse_not_bool, &c->no_cpu_limit, NULL }, { "disable-shm", pa_config_parse_bool, &c->disable_shm, NULL }, + { "disable-memfd", pa_config_parse_bool, &c->disable_memfd, NULL }, { "enable-shm", pa_config_parse_not_bool, &c->disable_shm, NULL }, { "flat-volumes", pa_config_parse_bool, &c->flat_volumes, NULL }, { "lock-memory", pa_config_parse_bool, &c->lock_memory, NULL }, diff --git a/src/daemon/daemon-conf.h b/src/daemon/daemon-conf.h index 458784c..82b619f 100644 --- a/src/daemon/daemon-conf.h +++ b/src/daemon/daemon-conf.h @@ -66,6 +66,7 @@ typedef struct pa_daemon_conf { system_instance, no_cpu_limit, disable_shm, + disable_memfd, disable_remixing, disable_lfe_remixing, load_default_script_file, diff --git a/src/daemon/main.c b/src/daemon/main.c index c2f47b6..ae1185d 100644 --- a/src/daemon/main.c +++ b/src/daemon/main.c @@ -1017,7 +1017,9 @@ int main(int argc, char *argv[]) { pa_assert_se(mainloop = pa_mainloop_new()); - if (!(c = pa_core_new(pa_mainloop_get_api(mainloop), !conf->disable_shm, conf->shm_size))) { + if (!(c = pa_core_new(pa_mainloop_get_api(mainloop), !conf->disable_shm, + !conf->disable_shm && !conf->disable_memfd && pa_memfd_is_locally_supported(), + conf->shm_size))) { pa_log(_("pa_core_new() failed.")); goto finish; } diff --git a/src/pulsecore/core.c b/src/pulsecore/core.c index aab82f3..bd12553 100644 --- a/src/pulsecore/core.c +++ b/src/pulsecore/core.c @@ -61,16 +61,19 @@ static int core_process_msg(pa_msgobject *o, int code, void *userdata, int64_t o static void core_free(pa_object *o); -pa_core* pa_core_new(pa_mainloop_api *m, bool shared, size_t shm_size) { +pa_core* pa_core_new(pa_mainloop_api *m, bool shared, bool enable_memfd, size_t shm_size) { pa_core* c; pa_mempool *pool; + pa_mem_type_t type; int j; pa_assert(m); if (shared) { - if (!(pool = pa_global_mempool_new(PA_MEM_TYPE_SHARED_POSIX, shm_size))) { - pa_log_warn("Failed to allocate shared memory pool. Falling back to a normal memory pool."); + type = (enable_memfd) ? PA_MEM_TYPE_SHARED_MEMFD : PA_MEM_TYPE_SHARED_POSIX; + if (!(pool = pa_global_mempool_new(type, shm_size))) { + pa_log_warn("Failed to allocate %s memory pool. Falling back to a normal memory pool.", + pa_mem_type_to_string(type)); shared = false; } } diff --git a/src/pulsecore/core.h b/src/pulsecore/core.h index 9f5c445..1a3c490 100644 --- a/src/pulsecore/core.h +++ b/src/pulsecore/core.h @@ -218,7 +218,7 @@ enum { PA_CORE_MESSAGE_MAX }; -pa_core* pa_core_new(pa_mainloop_api *m, bool shared, size_t shm_size); +pa_core* pa_core_new(pa_mainloop_api *m, bool shared, bool enable_memfd, size_t shm_size); /* Check whether no one is connected to this core */ void pa_core_check_idle(pa_core *c); diff --git a/src/pulsecore/protocol-native.c b/src/pulsecore/protocol-native.c index 1e6d61c..5247729 100644 --- a/src/pulsecore/protocol-native.c +++ b/src/pulsecore/protocol-native.c @@ -2685,7 +2685,8 @@ static void command_auth(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_ta bool memfd_on_remote = false; pa_tagstruct *reply; pa_mem_type_t shm_type; - bool shm_on_remote = false, do_shm; + bool shm_on_remote = false, do_shm, do_memfd; + const char *reason; pa_native_connection_assert_ref(c); pa_assert(t); @@ -2777,10 +2778,12 @@ static void command_auth(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_ta } } - /* Enable shared memory support if possible */ + /* Enable shared memory and memfd support if possible */ do_shm = pa_mempool_is_shared(c->protocol->core->mempool) && c->is_local; + do_memfd = + do_shm && pa_mempool_is_memfd_backed(c->protocol->core->mempool); pa_log_debug("SHM possible: %s", pa_yes_no(do_shm)); @@ -2803,21 +2806,24 @@ static void command_auth(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_ta pa_log_debug("Negotiated SHM: %s", pa_yes_no(do_shm)); pa_pstream_enable_shm(c->pstream, do_shm); + if (do_shm) + pa_log_debug("Memfd possible: %s", pa_yes_no(do_memfd)); + else + do_memfd = false; + shm_type = PA_MEM_TYPE_PRIVATE; if (do_shm) { - if (c->version >= 31 && memfd_on_remote && pa_memfd_is_locally_supported()) { + if (c->version >= 31 && do_memfd && memfd_on_remote) shm_type = PA_MEM_TYPE_SHARED_MEMFD; - pa_pstream_enable_memfd(c->pstream); - } else + else shm_type = PA_MEM_TYPE_SHARED_POSIX; - pa_log_debug("Memfd possible: %s", pa_yes_no(pa_memfd_is_locally_supported())); pa_log_debug("Negotiated SHM type: %s", pa_mem_type_to_string(shm_type)); } reply = reply_new(tag); pa_tagstruct_putu32(reply, PA_PROTOCOL_VERSION | (do_shm ? 0x80000000 : 0) | - (pa_memfd_is_locally_supported() ? 0x40000000 : 0)); + (do_memfd ? 0x40000000 : 0)); #ifdef HAVE_CREDS { @@ -2834,6 +2840,17 @@ static void command_auth(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_ta pa_pstream_send_tagstruct(c->pstream, reply); #endif + /* The client enables memfd transport on its pstream only after + * inspecting our version flags to see if we support memfds too. + * + * Thus register any pools after sending the server's version + * flags and never before it. */ + if (shm_type == PA_MEM_TYPE_SHARED_MEMFD) { + pa_pstream_enable_memfd(c->pstream); + if (pa_pstream_register_memfd_mempool(c->pstream, c->protocol->core->mempool, &reason)) + pa_log("Failed to register memfd mempool. Reason: %s", reason); + } + setup_srbchannel(c, shm_type); } Regards, -- Darwish http://darwish.chasingpointers.com