From 1fcea504b3a8541d039c3e63491e158433b06875 Mon Sep 17 00:00:00 2001 From: Andre Noll Date: Wed, 10 Aug 2011 19:50:38 +0200 Subject: [PATCH] ipc: Determine maximal size of a shared memory area at runtime. During command dispatch, the afs process allocates shm areas for the query result and passes the identifiers via the local socket to the child process of para_server which is executing the command. If the write to the (non-blocking) local socket fails, for example because the call would block, afs closes the connection to the child process immediately to avoid deadlocks. Therefore the maximal output size of an (afs) command depends linearly on the size of the shared memory areas, so it is desirable to allocate areas as large as possible. Currently, we use the SHMMAX if it is defined and fall back to the safe default value of 64K otherwise. However, this default is much smaller than the typical limit of 32M on Linux. Moreover, the maximal size of a shared memory area (shmmax) can be set at any time on most if not all operating systems, so runtime detection of shmmax is to be preferred. Unfortunately the way to obtain shmmax varies between operating systems. On Linux, the value is available as the contents of a file in /proc while on {Free,Net}BSD and Darwin sysctlbyname() must be called. Moreover, BSD and Darwin use different identifiers for the sysctlbyname() call. So any code that determines shmmax at runtime and works on all of the above systems must necessarily be ugly. This patch tries to concentrate all ugliness in the new shm_get_shmmax() function, so that the changes outside of ipc.c consist only of replacements SHMMAX -> shm_get_shmmax() and of the removal of the default SHMMAX setting. The new function only determines shmmax once when it is called for the first time. --- afs.c | 2 +- aft.c | 16 ++++++++-------- attribute.c | 8 ++++---- blob.c | 4 ++-- ipc.c | 46 ++++++++++++++++++++++++++++++++++++++++++++++ ipc.h | 5 +---- mood.c | 2 +- playlist.c | 2 +- 8 files changed, 64 insertions(+), 21 deletions(-) diff --git a/afs.c b/afs.c index 755537da..955b8f20 100644 --- a/afs.c +++ b/afs.c @@ -537,7 +537,7 @@ static int activate_mood_or_playlist(char *arg, int *num_admissible) static void com_select_callback(int fd, const struct osl_object *query) { struct para_buffer pb = { - .max_size = SHMMAX, + .max_size = shm_get_shmmax(), .private_data = &fd, .max_size_handler = pass_buffer_as_shm }; diff --git a/aft.c b/aft.c index f4080233..e91d734f 100644 --- a/aft.c +++ b/aft.c @@ -1037,7 +1037,7 @@ static int make_status_items(struct audio_file_data *afd, .flags = LS_FLAG_FULL_PATH | LS_FLAG_ADMISSIBLE_ONLY, .mode = LS_MODE_VERBOSE, }; - struct para_buffer pb = {.max_size = SHMMAX - 1}; + struct para_buffer pb = {.max_size = shm_get_shmmax() - 1}; time_t current_time; int ret; @@ -1048,7 +1048,7 @@ static int make_status_items(struct audio_file_data *afd, free(status_items); status_items = pb.buf; memset(&pb, 0, sizeof(pb)); - pb.max_size = SHMMAX - 1; + pb.max_size = shm_get_shmmax() - 1; pb.flags = PBF_SIZE_PREFIX; ret = print_list_item(&d, &opts, &pb, current_time); if (ret < 0) { @@ -1343,7 +1343,7 @@ static void com_ls_callback(int fd, const struct osl_object *query) { struct ls_options *opts = query->data; char *p, *pattern_start = (char *)query->data + sizeof(*opts); - struct para_buffer b = {.max_size = SHMMAX, + struct para_buffer b = {.max_size = shm_get_shmmax(), .flags = (opts->mode == LS_MODE_PARSER)? PBF_SIZE_PREFIX : 0, .max_size_handler = pass_buffer_as_shm, .private_data = &fd}; int i = 0, ret; @@ -1665,7 +1665,7 @@ static void com_add_callback(int fd, const struct osl_object *query) char afsi_buf[AFSI_SIZE]; uint32_t flags = read_u32(buf + CAB_FLAGS_OFFSET); struct afs_info default_afsi = {.last_played = 0}; - struct para_buffer msg = {.max_size = SHMMAX, + struct para_buffer msg = {.max_size = shm_get_shmmax(), .max_size_handler = pass_buffer_as_shm, .private_data = &fd}; uint16_t afhi_offset, chunks_offset; @@ -2080,7 +2080,7 @@ static void com_touch_callback(int fd, const struct osl_object *query) { struct touch_action_data tad = {.cto = query->data, .pb = { - .max_size = SHMMAX, + .max_size = shm_get_shmmax(), .private_data = &fd, .max_size_handler = pass_buffer_as_shm } @@ -2226,7 +2226,7 @@ static void com_rm_callback(int fd, const struct osl_object *query) { struct com_rm_action_data crd = {.flags = *(uint32_t *)query->data, .pb = { - .max_size = SHMMAX, + .max_size = shm_get_shmmax(), .private_data = &fd, .max_size_handler = pass_buffer_as_shm } @@ -2371,7 +2371,7 @@ static void com_cpsi_callback(int fd, const struct osl_object *query) struct cpsi_action_data cad = { .flags = *(unsigned *)query->data, .pb = { - .max_size = SHMMAX, + .max_size = shm_get_shmmax(), .private_data = &fd, .max_size_handler = pass_buffer_as_shm } @@ -2543,7 +2543,7 @@ static int check_audio_file(struct osl_row *row, void *data) void aft_check_callback(int fd, __a_unused const struct osl_object *query) { struct para_buffer pb = { - .max_size = SHMMAX, + .max_size = shm_get_shmmax(), .private_data = &fd, .max_size_handler = pass_buffer_as_shm }; diff --git a/attribute.c b/attribute.c index 42fa421c..f36f4e7d 100644 --- a/attribute.c +++ b/attribute.c @@ -149,7 +149,7 @@ static void com_lsatt_callback(int fd, const struct osl_object *query) struct lsatt_action_data laad = { .flags = *(unsigned *) query->data, .pb = { - .max_size = SHMMAX, + .max_size = shm_get_shmmax(), .private_data = &fd, .max_size_handler = pass_buffer_as_shm } @@ -295,7 +295,7 @@ static void com_addatt_callback(int fd, const struct osl_object *query) char *p; int ret = 1, ret2 = 0; struct para_buffer pb = { - .max_size = SHMMAX, + .max_size = shm_get_shmmax(), .private_data = &fd, .max_size_handler = pass_buffer_as_shm }; @@ -378,7 +378,7 @@ static void com_mvatt_callback(int fd, const struct osl_object *query) struct osl_object obj = {.data = old, .size = size}; struct osl_row *row; struct para_buffer pb = { - .max_size = SHMMAX, + .max_size = shm_get_shmmax(), .private_data = &fd, .max_size_handler = pass_buffer_as_shm }; @@ -448,7 +448,7 @@ static void com_rmatt_callback(int fd, const struct osl_object *query) struct remove_attribute_action_data raad = { .num_removed = 0, .pb = { - .max_size = SHMMAX, + .max_size = shm_get_shmmax(), .private_data = &fd, .max_size_handler = pass_buffer_as_shm } diff --git a/blob.c b/blob.c index 25aa2a6d..f98c7e5f 100644 --- a/blob.c +++ b/blob.c @@ -130,7 +130,7 @@ static void com_lsblob_callback(struct osl_table *table, struct lsblob_action_data lbad = { .flags = *(uint32_t *)query->data, .pb = { - .max_size = SHMMAX, + .max_size = shm_get_shmmax(), .private_data = &fd, .max_size_handler = pass_buffer_as_shm } @@ -261,7 +261,7 @@ static void com_rmblob_callback(struct osl_table *table, int fd, struct rmblob_data rmbd = { .num_removed = 0, .pb = { - .max_size = SHMMAX, + .max_size = shm_get_shmmax(), .private_data = &fd, .max_size_handler = pass_buffer_as_shm } diff --git a/ipc.c b/ipc.c index c1069ad9..674d1cb0 100644 --- a/ipc.c +++ b/ipc.c @@ -9,6 +9,10 @@ #include "para.h" #include "error.h" #include "ipc.h" +#include +#include +#include + #include #include #include @@ -171,3 +175,45 @@ int shm_detach(void *addr) int ret = shmdt(addr); return ret < 0? -ERRNO_TO_PARA_ERROR(errno) : 1; } + +# if defined __FreeBSD__ || defined __NetBSD__ +# define SYSCTL_SHMMAX_VARIABLE "kern.ipc.shmmax" +# elif defined __APPLE__ +# define SYSCTL_SHMMAX_VARIABLE "kern.sysv.shmmax" +# else +# undef SYSCTL_SHMMAX_VARIABLE +# endif + +size_t shm_get_shmmax(void) +{ + static size_t shmmax; + + if (shmmax > 0) /* only dance once */ + return shmmax; +#ifdef __linux__ /* get it from proc fs */ + { + int fd = open("/proc/sys/kernel/shmmax", O_RDONLY); + if (fd >= 0) { + char buf[100] = ""; + int ret = read(fd, buf, sizeof(buf) - 1); + if (ret > 0) { + buf[ret] = '\0'; + shmmax = strtoul(buf, NULL, 10); + } + } + } +#elif defined SYSCTL_SHMMAX_VARIABLE + { + size_t len = sizeof(shmmax); + sysctlbyname(SYSCTL_SHMMAX_VARIABLE, &shmmax, &len, NULL, 0); + } +#elif defined SHMMAX + shmmax = SHMMAX; +#endif + if (shmmax == 0) { + PARA_WARNING_LOG("unable to determine shmmax\n"); + shmmax = 65535; /* last ressort */ + } + PARA_INFO_LOG("shmmax: %zu\n", shmmax); + return shmmax; +} diff --git a/ipc.h b/ipc.h index 71e09ec1..c8d31c0c 100644 --- a/ipc.h +++ b/ipc.h @@ -11,7 +11,4 @@ int shm_new(size_t size); int shm_attach(int id, enum shm_attach_mode mode, void **result); int shm_detach(void *addr); int shm_destroy(int id); - -#ifndef SHMMAX -#define SHMMAX 65535 -#endif +size_t shm_get_shmmax(void); diff --git a/mood.c b/mood.c index 93461ee8..d9ae48bf 100644 --- a/mood.c +++ b/mood.c @@ -422,7 +422,7 @@ out: void mood_check_callback(int fd, __a_unused const struct osl_object *query) { struct para_buffer pb = { - .max_size = SHMMAX, + .max_size = shm_get_shmmax(), .private_data = &fd, .max_size_handler = pass_buffer_as_shm }; diff --git a/playlist.c b/playlist.c index 2d2f23b4..806e49d5 100644 --- a/playlist.c +++ b/playlist.c @@ -131,7 +131,7 @@ static int check_playlist(struct osl_row *row, void *data) void playlist_check_callback(int fd, __a_unused const struct osl_object *query) { struct para_buffer pb = { - .max_size = SHMMAX, + .max_size = shm_get_shmmax(), .private_data = &fd, .max_size_handler = pass_buffer_as_shm }; -- 2.39.2