[pulseaudio-discuss] [PATCH v3 11/11] core: Use memfd transport by default
Ahmed S. Darwish
darwish.07 at gmail.com
Sat Mar 12 23:17:08 UTC 2016
Now that all layers in the stack support memfd blocks, use memfd
pools for the global core mempool by default.
Also introduce "enable-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>
---
PROTOCOL | 4 ++++
man/pulse-daemon.conf.5.xml.in | 7 +++++-
man/pulseaudio.1.xml.in | 15 +++++++++---
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 | 49 +++++++++++++++++++++++++++++++---------
12 files changed, 87 insertions(+), 23 deletions(-)
diff --git a/PROTOCOL b/PROTOCOL
index 76cdd27..6bec969 100644
--- a/PROTOCOL
+++ b/PROTOCOL
@@ -383,6 +383,10 @@ Unless memfd support is compiled out or disabled by enable-memfd=no client
option, clients now uses memfd SHM by default to transfer playback audio
block references to the server.
+Unless memfd support is compiled out or disabled by enable-memfd=no server
+option, server now uses memfd SHM by default for its global core and rw
+srbchannel mempools.
+
#### If you just changed the protocol, read this
## module-tunnel depends on the sink/source/sink-input/source-input protocol
## internals, so if you changed these, you might have broken module-tunnel.
diff --git a/man/pulse-daemon.conf.5.xml.in b/man/pulse-daemon.conf.5.xml.in
index 0367b1f..1abc94f 100644
--- a/man/pulse-daemon.conf.5.xml.in
+++ b/man/pulse-daemon.conf.5.xml.in
@@ -189,12 +189,17 @@ License along with PulseAudio; if not, see <http://www.gnu.org/licenses/>.
<option>
<p><opt>enable-shm=</opt> Enable data transfer via POSIX
- shared memory. Takes a boolean argument, defaults to
+ or memfd shared memory. Takes a boolean argument, defaults to
<opt>yes</opt>. The <opt>--disable-shm</opt> command line
argument takes precedence.</p>
</option>
<option>
+ <p><opt>enable-memfd=</opt>. Enable 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..3187ef5 100644
--- a/man/pulseaudio.1.xml.in
+++ b/man/pulseaudio.1.xml.in
@@ -292,14 +292,23 @@ License along with PulseAudio; if not, see <http://www.gnu.org/licenses/>.
<p><opt>--disable-shm</opt><arg>[=BOOL]</arg></p>
<optdesc><p>PulseAudio clients and the server can exchange audio
- data via POSIX shared memory segments (on systems that support
- this). If disabled PulseAudio will communicate exclusively over
- sockets. Please note that data transfer via shared memory
+ data via POSIX or memfd shared memory segments (on systems that
+ support this). If disabled PulseAudio will communicate exclusively
+ over sockets. Please note that data transfer via shared memory
segments is always disabled when PulseAudio is running with
<opt>--system</opt> enabled (see above).</p></optdesc>
</option>
<option>
+ <p><opt>--enable-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.</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..e473b9c 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= --enable-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=*|--enable-memfd=*)
cur=${cur#*=}
COMPREPLY=($(compgen -W 'true false' -- "$cur"))
;;
diff --git a/shell-completion/zsh/_pulseaudio b/shell-completion/zsh/_pulseaudio
index c7d68f5..e065085 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)' \
+ '--enable-memfd=[enable 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..0454b6d 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_ENABLE_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},
+ {"enable-memfd", 2, 0, ARG_ENABLE_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"
+ " --enable-memfd[=BOOL] Enable 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_ENABLE_MEMFD:
+ if ((b = optarg ? pa_parse_boolean(optarg) : 1) < 0) {
+ pa_log(_("--enable-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..d859c77 100644
--- a/src/daemon/daemon-conf.c
+++ b/src/daemon/daemon-conf.c
@@ -526,6 +526,7 @@ int pa_daemon_conf_load(pa_daemon_conf *c, const char *filename) {
{ "cpu-limit", pa_config_parse_not_bool, &c->no_cpu_limit, NULL },
{ "disable-shm", pa_config_parse_bool, &c->disable_shm, NULL },
{ "enable-shm", pa_config_parse_not_bool, &c->disable_shm, NULL },
+ { "enable-memfd", pa_config_parse_not_bool, &c->disable_memfd, NULL },
{ "flat-volumes", pa_config_parse_bool, &c->flat_volumes, NULL },
{ "lock-memory", pa_config_parse_bool, &c->lock_memory, NULL },
{ "enable-deferred-volume", pa_config_parse_bool, &c->deferred_volume, 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 56cbe9d..6d102f5 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_mempool_new(PA_MEM_TYPE_SHARED_POSIX, shm_size, false))) {
- 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_mempool_new(type, shm_size, false))) {
+ 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 3f39431..7b57b89 100644
--- a/src/pulsecore/protocol-native.c
+++ b/src/pulsecore/protocol-native.c
@@ -2598,7 +2598,7 @@ static void command_exit(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_ta
pa_pstream_send_simple_ack(c->pstream, tag); /* nonsense */
}
-static void setup_srbchannel(pa_native_connection *c) {
+static void setup_srbchannel(pa_native_connection *c, pa_mem_type_t shm_type) {
pa_srbchannel_template srbt;
pa_srbchannel *srb;
pa_memchunk mc;
@@ -2626,20 +2626,25 @@ static void setup_srbchannel(pa_native_connection *c) {
return;
}
- if (!(c->rw_mempool = pa_mempool_new(PA_MEM_TYPE_SHARED_POSIX, c->protocol->core->shm_size, true))) {
+ if (!(c->rw_mempool = pa_mempool_new(shm_type, c->protocol->core->shm_size, true))) {
pa_log_warn("Disabling srbchannel, reason: Failed to allocate shared "
"writable memory pool.");
return;
}
+
+ if (shm_type == PA_MEM_TYPE_SHARED_MEMFD) {
+ const char *reason;
+ if (pa_pstream_register_memfd_mempool(c->pstream, c->rw_mempool, &reason)) {
+ pa_log_warn("Disabling srbchannel, reason: Failed to register memfd mempool: %s", reason);
+ goto fail;
+ }
+ }
pa_mempool_set_is_remote_writable(c->rw_mempool, true);
srb = pa_srbchannel_new(c->protocol->core->mainloop, c->rw_mempool);
if (!srb) {
pa_log_debug("Failed to create srbchannel");
-
- pa_mempool_unref(c->rw_mempool);
- c->rw_mempool = NULL;
- return;
+ goto fail;
}
pa_log_debug("Enabling srbchannel...");
pa_srbchannel_export(srb, &srbt);
@@ -2659,6 +2664,13 @@ static void setup_srbchannel(pa_native_connection *c) {
pa_pstream_send_memblock(c->pstream, 0, 0, 0, &mc);
c->srbpending = srb;
+ return;
+
+fail:
+ if (c->rw_mempool) {
+ pa_mempool_unref(c->rw_mempool);
+ c->rw_mempool = NULL;
+ }
}
static void command_enable_srbchannel(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
@@ -2677,7 +2689,7 @@ static void command_enable_srbchannel(pa_pdispatch *pd, uint32_t command, uint32
static void command_auth(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
const void*cookie;
- bool memfd_on_remote = false;
+ bool memfd_on_remote = false, do_memfd = false;
pa_tagstruct *reply;
pa_mem_type_t shm_type;
bool shm_on_remote = false, do_shm;
@@ -2772,7 +2784,7 @@ 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;
@@ -2798,9 +2810,12 @@ 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);
+ do_memfd =
+ do_shm && pa_mempool_is_memfd_backed(c->protocol->core->mempool);
+
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 && memfd_on_remote && do_memfd) {
pa_pstream_enable_memfd(c->pstream);
shm_type = PA_MEM_TYPE_SHARED_MEMFD;
} else
@@ -2812,7 +2827,7 @@ static void command_auth(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_ta
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
{
@@ -2829,7 +2844,19 @@ static void command_auth(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_ta
pa_pstream_send_tagstruct(c->pstream, reply);
#endif
- setup_srbchannel(c);
+ /* 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) {
+ const char *reason;
+
+ 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);
}
static void command_register_memfd_shmid(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
--
2.7.2
More information about the pulseaudio-discuss
mailing list