From abfc67a3ca18f6a1610b257db445427ae7d6452d Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Tue, 19 Jan 2021 14:47:44 +0100 Subject: [PATCH] Revert "remove mlock and use MAP_LOCKED" This reverts commit ab91e94b59edd87c33f3d1cce1edf9706ed109d0. When no memory can be locked, the mmap fails with -EAGAIN. Fixes #592 --- pipewire-jack/src/pipewire-jack.c | 13 ++++++-- src/modules/module-client-node/remote-node.c | 20 +++++++++++-- src/pipewire/filter.c | 31 +++++++++++++------- src/pipewire/stream.c | 21 +++++++++---- 4 files changed, 64 insertions(+), 21 deletions(-) diff --git a/pipewire-jack/src/pipewire-jack.c b/pipewire-jack/src/pipewire-jack.c index 120432f76..f81bf298d 100644 --- a/pipewire-jack/src/pipewire-jack.c +++ b/pipewire-jack/src/pipewire-jack.c @@ -87,6 +87,7 @@ struct globals { }; static struct globals globals; +static bool mlock_warned = false; #define OBJECT_CHUNK 8 @@ -1722,8 +1723,6 @@ static int client_node_port_use_buffers(void *object, /* some apps write to the input buffer so we want everything readwrite */ fl = PW_MEMMAP_FLAG_READWRITE; } - if (c->allow_mlock) - fl |= PW_MEMMAP_FLAG_LOCKED; /* clear previous buffers */ clear_buffers(c, mix); @@ -1806,6 +1805,16 @@ static int client_node_port_use_buffers(void *object, } else { pw_log_warn("unknown buffer data type %d", d->type); } + if (c->allow_mlock && mlock(d->data, d->maxsize) < 0) { + if (errno != ENOMEM || !mlock_warned) { + pw_log_warn(NAME" %p: Failed to mlock memory %p %u: %s", c, + d->data, d->maxsize, + errno == ENOMEM ? + "This is not a problem but for best performance, " + "consider increasing RLIMIT_MEMLOCK" : strerror(errno)); + mlock_warned |= errno == ENOMEM; + } + } } SPA_FLAG_SET(b->flags, BUFFER_FLAG_OUT); if (direction == SPA_DIRECTION_OUTPUT) diff --git a/src/modules/module-client-node/remote-node.c b/src/modules/module-client-node/remote-node.c index c707475ce..f2e9612ac 100644 --- a/src/modules/module-client-node/remote-node.c +++ b/src/modules/module-client-node/remote-node.c @@ -44,6 +44,8 @@ #define MAX_MIX 4096 /** \cond */ +static bool mlock_warned = false; + struct buffer { uint32_t id; struct spa_buffer *buf; @@ -77,6 +79,7 @@ struct node_data { unsigned int do_free:1; unsigned int have_transport:1; unsigned int allow_mlock:1; + unsigned int warn_mlock:1; struct pw_client_node *client_node; struct spa_hook client_node_listener; @@ -615,8 +618,6 @@ client_node_port_use_buffers(void *object, } prot = PW_MEMMAP_FLAG_READWRITE; - if (data->allow_mlock) - prot |= PW_MEMMAP_FLAG_LOCKED; /* clear previous buffers */ clear_buffers(data, mix); @@ -643,6 +644,17 @@ client_node_port_use_buffers(void *object, bid->id = i; bid->mem = mm; + if (data->allow_mlock && mlock(mm->ptr, mm->size) < 0) + if (errno != ENOMEM || !mlock_warned) { + pw_log(data->warn_mlock ? SPA_LOG_LEVEL_WARN : SPA_LOG_LEVEL_DEBUG, + "Failed to mlock memory %p %u: %s", + mm->ptr, mm->size, + errno == ENOMEM ? + "This is not a problem but for best performance, " + "consider increasing RLIMIT_MEMLOCK" : strerror(errno)); + mlock_warned |= errno == ENOMEM; + } + size = sizeof(struct spa_buffer); for (j = 0; j < buffers[i].buffer->n_metas; j++) size += sizeof(struct spa_meta); @@ -1206,6 +1218,10 @@ static struct pw_proxy *node_export(struct pw_core *core, void *object, bool do_ if ((str = pw_properties_get(node->properties, "mem.allow-mlock")) != NULL) data->allow_mlock = pw_properties_parse_bool(str); + data->warn_mlock = true; + if ((str = pw_properties_get(node->properties, "mem.warn-mlock")) != NULL) + data->warn_mlock = pw_properties_parse_bool(str); + node->exported = true; spa_list_init(&data->free_mix); diff --git a/src/pipewire/filter.c b/src/pipewire/filter.c index 8bc977cef..91879ff25 100644 --- a/src/pipewire/filter.c +++ b/src/pipewire/filter.c @@ -51,6 +51,7 @@ #define MAX_PORTS 1024 static float empty[MAX_SAMPLES]; +static bool mlock_warned = false; static uint32_t mappable_dataTypes = (1<mapoffset, data->maxsize, impl->context->sc_pagesize); - flags = MAP_SHARED; - if (impl->allow_mlock) - flags |= MAP_LOCKED; - - ptr = mmap(NULL, range.size, prot, flags, data->fd, range.offset); + ptr = mmap(NULL, range.size, prot, MAP_SHARED, data->fd, range.offset); if (ptr == MAP_FAILED) { pw_log_error(NAME" %p: failed to mmap buffer mem: %m", impl); return -errno; @@ -583,6 +579,17 @@ static int map_data(struct filter *impl, struct spa_data *data, int prot) pw_log_debug(NAME" %p: fd %"PRIi64" mapped %d %d %p", impl, data->fd, range.offset, range.size, data->data); + if (impl->allow_mlock && mlock(data->data, data->maxsize) < 0) { + if (errno != ENOMEM || !mlock_warned) { + pw_log(impl->warn_mlock ? SPA_LOG_LEVEL_WARN : SPA_LOG_LEVEL_DEBUG, + NAME" %p: Failed to mlock memory %p %u: %s", impl, + data->data, data->maxsize, + errno == ENOMEM ? + "This is not a problem but for best performance, " + "consider increasing RLIMIT_MEMLOCK" : strerror(errno)); + mlock_warned |= errno == ENOMEM; + } + } return 0; } @@ -784,7 +791,7 @@ static void call_process(struct filter *impl) { struct pw_filter *filter = &impl->this; pw_log_trace(NAME" %p: call process", impl); - if (impl->process_rt) { + if (SPA_FLAG_IS_SET(impl->flags, PW_FILTER_FLAG_RT_PROCESS)) { pw_filter_emit_process(filter, impl->rt.position); } else { @@ -1234,6 +1241,10 @@ pw_filter_connect(struct pw_filter *filter, pw_log_debug(NAME" %p: connect", filter); impl->flags = flags; + impl->warn_mlock = SPA_FLAG_IS_SET(flags, PW_FILTER_FLAG_RT_PROCESS); + pw_properties_set(filter->properties, "mem.warn-mlock", + impl->warn_mlock ? "true" : "false"); + impl->impl_node.iface = SPA_INTERFACE_INIT( SPA_TYPE_INTERFACE_Node, SPA_VERSION_NODE, @@ -1244,12 +1255,10 @@ pw_filter_connect(struct pw_filter *filter, SPA_NODE_CHANGE_MASK_PROPS | SPA_NODE_CHANGE_MASK_PARAMS; - impl->process_rt = SPA_FLAG_IS_SET(flags, PW_STREAM_FLAG_RT_PROCESS); - impl->info = SPA_NODE_INFO_INIT(); impl->info.max_input_ports = MAX_PORTS; impl->info.max_output_ports = MAX_PORTS; - impl->info.flags = impl->process_rt ? SPA_NODE_FLAG_RT : 0; + impl->info.flags = impl->warn_mlock ? SPA_NODE_FLAG_RT : 0; impl->info.props = &filter->properties->dict; impl->params[0] = SPA_PARAM_INFO(SPA_PARAM_EnumFormat, 0); impl->params[1] = SPA_PARAM_INFO(SPA_PARAM_Meta, 0); diff --git a/src/pipewire/stream.c b/src/pipewire/stream.c index 958320137..2919d0859 100644 --- a/src/pipewire/stream.c +++ b/src/pipewire/stream.c @@ -49,6 +49,8 @@ #define MASK_BUFFERS (MAX_BUFFERS-1) #define MAX_PORTS 1 +static bool mlock_warned = false; + static uint32_t mappable_dataTypes = (1<mapoffset, data->maxsize, impl->context->sc_pagesize); - flags = MAP_SHARED; - if (impl->allow_mlock) - flags |= MAP_LOCKED; - - ptr = mmap(NULL, range.size, prot, flags, data->fd, range.offset); + ptr = mmap(NULL, range.size, prot, MAP_SHARED, data->fd, range.offset); if (ptr == MAP_FAILED) { pw_log_error(NAME" %p: failed to mmap buffer mem: %m", impl); return -errno; @@ -594,6 +591,17 @@ static int map_data(struct stream *impl, struct spa_data *data, int prot) pw_log_debug(NAME" %p: fd %"PRIi64" mapped %d %d %p", impl, data->fd, range.offset, range.size, data->data); + if (impl->allow_mlock && mlock(data->data, data->maxsize) < 0) { + if (errno != ENOMEM || !mlock_warned) { + pw_log(impl->process_rt ? SPA_LOG_LEVEL_WARN : SPA_LOG_LEVEL_DEBUG, + NAME" %p: Failed to mlock memory %p %u: %s", impl, + data->data, data->maxsize, + errno == ENOMEM ? + "This is not a problem but for best performance, " + "consider increasing RLIMIT_MEMLOCK" : strerror(errno)); + mlock_warned |= errno == ENOMEM; + } + } return 0; } @@ -1537,6 +1545,7 @@ pw_stream_connect(struct pw_stream *stream, pw_properties_set(stream->properties, PW_KEY_NODE_DONT_RECONNECT, "true"); impl->process_rt = SPA_FLAG_IS_SET(flags, PW_STREAM_FLAG_RT_PROCESS); + pw_properties_set(stream->properties, "mem.warn-mlock", impl->process_rt ? "true" : "false"); if ((pw_properties_get(stream->properties, PW_KEY_MEDIA_CLASS) == NULL)) { const char *media_type = pw_properties_get(stream->properties, PW_KEY_MEDIA_TYPE);