MINOR: pools: add a new global option "no-memory-trimming"

Some users with very large numbers of connections have been facing
extremely long malloc_trim() calls on reload that managed to trigger
the watchdog! That's a bit counter-productive. It's even possible
that some implementations are not perfectly reliable or that their
trimming time grows quadratically with the memory used. Instead of
constantly trying to work around these issues, let's offer an option
to disable this mechanism, since nobody had been complaining in the
past, and this was only meant to be an improvement.

This should be backported to 2.4 where trimming on reload started to
appear.
diff --git a/doc/configuration.txt b/doc/configuration.txt
index 4795dd2..6660aa7 100644
--- a/doc/configuration.txt
+++ b/doc/configuration.txt
@@ -1070,6 +1070,7 @@
    - maxsslconn
    - maxsslrate
    - maxzlibmem
+   - no-memory-trimming
    - noepoll
    - nokqueue
    - noevports
@@ -2380,6 +2381,22 @@
   with "show info" on the line "MaxZlibMemUsage", the memory used by zlib is
   "ZlibMemUsage" in bytes.
 
+no-memory-trimming
+  Disables memory trimming ("malloc_trim") at a few moments where attempts are
+  made to reclaim lots of memory (on memory shortage or on reload). Trimming
+  memory forces the system's allocator to scan all unused areas and to release
+  them. This is generally seen as nice action to leave more available memory to
+  a new process while the old one is unlikely to make significant use of it.
+  But some systems dealing with tens to hundreds of thousands of concurrent
+  connections may experience a lot of memory fragmentation, that may render
+  this release operation extremely long. During this time, no more traffic
+  passes through the process, new connections are not accepted anymore, some
+  health checks may even fail, and the watchdog may even trigger and kill the
+  unresponsive process, leaving a huge core dump. If this ever happens, then it
+  is suggested to use this option to disable trimming and stop trying to be
+  nice with the new process. Note that advanced memory allocators usually do
+  not suffer from such a problem.
+
 noepoll
   Disables the use of the "epoll" event polling system on Linux. It is
   equivalent to the command-line argument "-de". The next polling system
diff --git a/src/pool.c b/src/pool.c
index b3520d7..fe10bad 100644
--- a/src/pool.c
+++ b/src/pool.c
@@ -83,6 +83,7 @@
 
 static int mem_fail_rate __read_mostly = 0;
 static int using_default_allocator __read_mostly = 1;
+static int disable_trim __read_mostly = 0;
 static int(*my_mallctl)(const char *, void *, size_t *, void *, size_t) = NULL;
 
 /* ask the allocator to trim memory pools.
@@ -95,6 +96,9 @@
 {
 	int isolated = thread_isolated();
 
+	if (disable_trim)
+		return;
+
 	if (!isolated)
 		thread_isolate();
 
@@ -1073,9 +1077,21 @@
 	return 0;
 }
 
+/* config parser for global "no-memory-trimming" */
+static int mem_parse_global_no_mem_trim(char **args, int section_type, struct proxy *curpx,
+                                       const struct proxy *defpx, const char *file, int line,
+                                       char **err)
+{
+	if (too_many_args(0, args, err, NULL))
+		return -1;
+	disable_trim = 1;
+	return 0;
+}
+
 /* register global config keywords */
 static struct cfg_kw_list mem_cfg_kws = {ILH, {
 	{ CFG_GLOBAL, "tune.fail-alloc", mem_parse_global_fail_alloc },
+	{ CFG_GLOBAL, "no-memory-trimming", mem_parse_global_no_mem_trim },
 	{ 0, NULL, NULL }
 }};