Richard W.M. Jones
2013-Feb-18 21:20 UTC
[Libguestfs] [PATCH for discussion only 0/3] Implement mutexes to limit number of concurrent instances of libguestfs.
These three patches (for discussion only, NOT to be applied) implement a mutex system that lets the user limit the number of libguestfs instances that can be launched per host. There are two uses that I have identified for this: firstly so we can enable parallel-tests (the default in automake >= 1.13) without blowing up the host. Secondly oVirt has raised concerns about how to limit the number of libguestfs appliances that can run to prevent this from interfering with their ordinary guests. The mutex is easy to use: You specify a POSIX semaphore file and the maximum number of instances you want to allow to run at the same time, eg: LIBGUESTFS_MUTEX_FILE=/guestfs.mutex LIBGUESTFS_MUTEX_LIMIT=3 export LIBGUESTFS_MUTEX_FILE LIBGUESTFS_MUTEX_LIMIT As long as each handle has the same settings, the limit is applied transparently, with handles over the limit waiting for earlier ones to finish. (These can of course also be set through the API). There is also a way to have libguestfs choose a suitable limit for you, and the system is entirely optional so that *not* setting these variables results in no limits -- ie. the same as current behaviour. Unfortunately this doesn't quite work because the design of POSIX semaphores is a slightly braindead. It's not possible to have the semaphore be automatically recovered if the process crashes. See: http://stackoverflow.com/questions/2053679/how-do-i-recover-a-semaphore-when-the-process-that-decremented-it-to-zero-crashe As a result when you try to run the tests you'll find that the semaphore count slowly creeps up until the test suite stops running. In any case, POSIX semaphores are annoying in other ways; for example they don't live in the true filesystem, but in their own separate namespace (exposed under /dev/shm). To get around this I'll have to reimplement this using filesystem locks. Rich.
Richard W.M. Jones
2013-Feb-18 21:20 UTC
[Libguestfs] [PATCH for discussion only 1/3] handle: Define DEFAULT_MEMSIZE, MIN_MEMSIZE constants.
From: "Richard W.M. Jones" <rjones at redhat.com> This is just code motion. --- src/guestfs-internal.h | 4 ++++ src/handle.c | 4 ++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/guestfs-internal.h b/src/guestfs-internal.h index c52b9a5..48ab745 100644 --- a/src/guestfs-internal.h +++ b/src/guestfs-internal.h @@ -56,6 +56,10 @@ #define TRACE4(name, arg1, arg2, arg3, arg4) #endif +/* Default, minimum appliance memory size. */ +#define DEFAULT_MEMSIZE 500 +#define MIN_MEMSIZE 128 + /* Some limits on what the inspection code will read, for safety. */ /* Small text configuration files. diff --git a/src/handle.c b/src/handle.c index 786ba13..c630daf 100644 --- a/src/handle.c +++ b/src/handle.c @@ -101,7 +101,7 @@ guestfs_create_flags (unsigned flags, ...) g->recovery_proc = 1; g->autosync = 1; - g->memsize = 500; + g->memsize = DEFAULT_MEMSIZE; /* Start with large serial numbers so they are easy to spot * inside the protocol. @@ -202,7 +202,7 @@ parse_environment (guestfs_h *g, str = do_getenv (data, "LIBGUESTFS_MEMSIZE"); if (str) { - if (sscanf (str, "%d", &memsize) != 1 || memsize < 128) { + if (sscanf (str, "%d", &memsize) != 1 || memsize < MIN_MEMSIZE) { error (g, _("non-numeric or too small value for LIBGUESTFS_MEMSIZE")); return -1; } -- 1.8.1.2
Richard W.M. Jones
2013-Feb-18 21:20 UTC
[Libguestfs] [PATCH for discussion only 2/3] handle: Implement mutexes.
From: "Richard W.M. Jones" <rjones at redhat.com> These limit the number of concurrent handles which can be used at once. --- fish/guestfish.pod | 8 ++ generator/actions.ml | 87 +++++++++++++++++ generator/events.ml | 4 + ocaml/t/guestfs_400_events.ml | 5 +- po/POTFILES | 1 + src/Makefile.am | 1 + src/guestfs-internal.h | 11 +++ src/guestfs.pod | 120 ++++++++++++++++++++++++ src/handle.c | 20 +++- src/launch.c | 4 + src/mutex.c | 213 ++++++++++++++++++++++++++++++++++++++++++ src/proto.c | 1 + test-tool/test-tool.c | 3 + 13 files changed, 476 insertions(+), 2 deletions(-) create mode 100644 src/mutex.c diff --git a/fish/guestfish.pod b/fish/guestfish.pod index 5fec2f2..28dde6c 100644 --- a/fish/guestfish.pod +++ b/fish/guestfish.pod @@ -1279,6 +1279,14 @@ example: LIBGUESTFS_MEMSIZE=700 +=item LIBGUESTFS_MUTEX_FILE + +=item LIBGUESTFS_MUTEX_LIMIT + +Set these in order to limit the number of concurrent guestfish +sessions launched at once. See L<guestfs(3)/MUTEX> and +L</set-mutex-limit>. + =item LIBGUESTFS_PATH Set the path that guestfish uses to search for kernel and initrd.img. diff --git a/generator/actions.ml b/generator/actions.ml index 4f18f41..d664a7a 100644 --- a/generator/actions.ml +++ b/generator/actions.ml @@ -2694,6 +2694,93 @@ the default. Else C</var/tmp> is the default." }; longdesc = "\ Get the directory used by the handle to store the appliance cache." }; + { defaults with + name = "set_mutex_file"; + style = RErr, [OptString "mutexfile"], []; + config_only = true; blocking = false; + shortdesc = "set mutex filename to limit concurrent handles"; + longdesc = "\ +Set the name of the semaphore file used to limit concurrent handles. +The name must start with a C</> character, and contain no other +C</> characters (eg. C</guestfs.mutex>). See L<sem_overview(7)> +for an explanation. + +See L<guestfs(3)/MUTEX>." }; + + { defaults with + name = "get_mutex_file"; + style = RConstOptString "mutexfile", [], []; + blocking = false; + shortdesc = "get mutex filename"; + longdesc = "\ +Get the name of the semaphore file. + +See C<guestfs_set_mutex_file> and L<guestfs(3)/MUTEX>." }; + + { defaults with + name = "set_mutex_limit"; + style = RErr, [Int "limit"], []; + config_only = true; blocking = false; + shortdesc = "set mutex to limit concurrent handles"; + longdesc = "\ +This sets the limit of the number of concurrent handles that +may be launched at the same time. The intention is to limit +the overall load that libguestfs places on the host. + +Note that in the current implementation which uses a POSIX +semaphore, you have to delete the semaphore file (or reboot the +host) in order to change this limit. See L<sem_overview(7)> for +the location of the semaphore file. This may be fixed in future. + +As well as ordinary positive integers, meaning to limit +the number of launched handles to C<limit>, various magic +values are possible too: + +=over 4 + +=item C<limit> E<ge> 1 + +Limit the number of launched handles to at most C<limit> concurrently. + +=item C<0> + +Disable limits. + +=item C<-2> + +Let libguestfs choose a suitable limit based on the free memory +available on the host when the semaphore is first created. + +If there is less memory available than libguestfs thinks is necessary, +libguestfs will still allow one handle to run (otherwise that handle +would be waiting forever). + +This is probably the best choice for most users. + +=item C<limit> E<le> -128 + +Calculate the maximum number of concurrent handles by dividing +the free memory by C<-limit>. This calculation is done when the +semaphore is first created. + +Libguestfs will always allow at least one handle to run +(otherwise that handle would be waiting forever). + +=back + +For more information see L<guestfs(3)/MUTEX>." }; + + { defaults with + name = "get_mutex_limit"; + style = RInt "limit", [], []; + blocking = false; + shortdesc = "get mutex limit"; + longdesc = "\ +This returns the mutex limit. If not previously set, the +default is C<0> (meaning the mutex feature is disabled). + +See C<guestfs_set_mutex_limit> and L<guestfs(3)/MUTEX>." }; + ] (* daemon_functions are any functions which cause some action diff --git a/generator/events.ml b/generator/events.ml index 58c0c54..9c69705 100644 --- a/generator/events.ml +++ b/generator/events.ml @@ -39,6 +39,10 @@ let events = [ "enter"; (* enter a function *) "libvirt_auth"; (* libvirt authentication request *) + + "mutex_blocked"; (* mutex events *) + "mutex_entered"; + "mutex_released"; ] let events = mapi (fun i name -> name, 1 lsl i) events diff --git a/ocaml/t/guestfs_400_events.ml b/ocaml/t/guestfs_400_events.ml index be40608..76d27a5 100644 --- a/ocaml/t/guestfs_400_events.ml +++ b/ocaml/t/guestfs_400_events.ml @@ -29,7 +29,10 @@ let log g ev eh buf array | Guestfs.EVENT_LIBRARY -> "library" | Guestfs.EVENT_TRACE -> "trace" | Guestfs.EVENT_ENTER -> "enter" - | Guestfs.EVENT_LIBVIRT_AUTH -> "libvirt_auth" in + | Guestfs.EVENT_LIBVIRT_AUTH -> "libvirt_auth" + | Guestfs.EVENT_MUTEX_BLOCKED -> "mutex_blocked" + | Guestfs.EVENT_MUTEX_ENTERED -> "mutex_entered" + | Guestfs.EVENT_MUTEX_RELEASED -> "mutex_released" in let eh : int = Obj.magic eh in diff --git a/po/POTFILES b/po/POTFILES index 0686966..e3430f2 100644 --- a/po/POTFILES +++ b/po/POTFILES @@ -263,6 +263,7 @@ src/libvirt-domain.c src/listfs.c src/lpj.c src/match.c +src/mutex.c src/osinfo.c src/private-data.c src/proto.c diff --git a/src/Makefile.am b/src/Makefile.am index 2c3af05..3410803 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -171,6 +171,7 @@ libguestfs_la_SOURCES = \ listfs.c \ lpj.c \ match.c \ + mutex.c \ osinfo.c \ private-data.c \ proto.c \ diff --git a/src/guestfs-internal.h b/src/guestfs-internal.h index 48ab745..00c029e 100644 --- a/src/guestfs-internal.h +++ b/src/guestfs-internal.h @@ -23,6 +23,8 @@ #include <libintl.h> +#include <semaphore.h> + #include <rpc/types.h> #include <rpc/xdr.h> @@ -292,6 +294,11 @@ struct guestfs_h virConnectCredentialPtr requested_credentials; #endif + /* Used by the handle mutex (see src/mutex.c). */ + char *mutex_file; + int mutex_limit; + sem_t *semaphore; + /**** Private data for attach-methods. ****/ /* NB: This cannot be a union because of a pathological case where * the user changes attach-method while reusing the handle to launch @@ -519,6 +526,10 @@ extern char *guestfs___appliance_command_line (guestfs_h *g, const char *applian /* launch-appliance.c */ extern char *guestfs___drive_name (size_t index, char *ret); +/* mutex.c */ +extern int guestfs___acquire_mutex (guestfs_h *g); +extern void guestfs___release_mutex (guestfs_h *g); + /* inspect.c */ extern void guestfs___free_inspect_info (guestfs_h *g); extern int guestfs___feature_available (guestfs_h *g, const char *feature); diff --git a/src/guestfs.pod b/src/guestfs.pod index d21ac8c..bec1249 100644 --- a/src/guestfs.pod +++ b/src/guestfs.pod @@ -718,6 +718,100 @@ available from the L</guestfs_inspect_is_live>, L</guestfs_inspect_is_netinst> and L</guestfs_inspect_is_multipart> calls. +=head2 MUTEX + +You can limit the number of launched handles (per host) to avoid +having too many libguestfs instances running at once. This is known +as the handle "mutex". This works by having a shared semaphore. If +the limit is reached, handles wait on this semaphore until other +instances finish. + +The default is no lock file and no limit on the number of concurrent +handles. + +=head3 SETTING THE MUTEX LOCK FILE AND LIMIT + +To use this feature, after you open each handle but before calling +L</guestfs_launch>, set the semaphore filename and limit by calling +L</guestfs_set_mutex_file> and L</guestfs_set_mutex_limit>. + +The semaphore filename is a special type of filename that starts with +a C</> character and contains no other C</> characters +(eg. C</guestfs.mutex>). See L<sem_overview(7)> for an explanation. + +The same filename should be passed to every handle. + +The limit is simply an integer (the number of handles). The limit can +have various magic values too, read the documentation for +L</guestfs_set_mutex_limit>. + +Alternatively, ensure that the following environment variables are set +globally for every libguestfs user / process: C<LIBGUESTFS_MUTEX_FILE> +and C<LIBGUESTFS_MUTEX_LIMIT>. + +The example below shows how to use the environment variables. The +special limit of C<-2> causes libguestfs to choose a suitable limit +based on the amount of free memory on the host: + + LIBGUESTFS_MUTEX_FILE=/guestfs.mutex + LIBGUESTFS_MUTEX_LIMIT=-2 + export LIBGUESTFS_MUTEX_FILE LIBGUESTFS_MUTEX_LIMIT + +=head3 MUTEX CHANGES TO LAUNCH AND CLOSE + +When the mutex has been configured, L</guestfs_launch> may block if +there are too many other handles running at the same time. Similarly, +L</guestfs_shutdown> or L</guestfs_close> may release the lock causing +another handle that was waiting to start launching. + +You can see if handles are blocked by enabling debugging or by +registering for events (see next section). + +=head3 MUTEX EVENTS + +The API allows callers to receive an event when a handle is blocked +acquiring the lock, has acquired the lock, or has released the lock. +Events only let you monitor this; they don't let you change the mutex +behaviour on the fly. + +The three events are C<GUESTFS_EVENT_MUTEX_BLOCKED> (blocked when +trying to acquire the mutex), C<GUESTFS_EVENT_MUTEX_ENTERED> +(successfully acquired the mutex), and C<GUESTFS_EVENT_MUTEX_RELEASED> +(have just released the mutex). All events have a string payload +which is the name of the semaphore file (ie. the same string passed to +L</guestfs_set_mutex_file>). + +Note that the C<BLOCKED> event is only generated if the handle +actually waits, not if the handle goes straight into the mutex. + +If mutexes are not configured, then none of these events will be +generated. + +For further information about events, see L</EVENTS>. + +=head3 MUTEX IMPLEMENTATION NOTES + +Currently the mutex is implemented using POSIX semaphores (this +implementation detail may change in future). + +The mutex is only enabled if the mutex semaphore file is set and the +limit is set to a non-zero value. + +The mutex only affects when handles can be launched. You can still +create as many handles as you like, which should be safe because +handles that are not launched just use a little memory in the current +process. + +The mutex must be enabled on all handles. If you don't enable it on a +particular handle, then that handle will ignore the mutex (even if it +is set on other handles). + +Currently, if you want to change the limit then you have to delete the +semaphore file. + +For the magic negative values of the limit, libguestfs uses the output +of the L<free(1)> command to determine free memory on the host. + =head2 SPECIAL CONSIDERATIONS FOR WINDOWS GUESTS Libguestfs can mount NTFS partitions. It does this using the @@ -2486,6 +2580,24 @@ authentication information. See L</LIBVIRT AUTHENTICATION> below. If no callback is registered: C<virConnectAuthPtrDefault> is used (suitable for command-line programs only). +=item GUESTFS_EVENT_MUTEX_BLOCKED +(payload type: lock file name) + +During launch, the handle is blocked waiting for the mutex. +See L</MUTEX>. + +=item GUESTFS_EVENT_MUTEX_ENTERED +(payload type: lock file name) + +During launch, the handle acquired the mutex lock. +See L</MUTEX>. + +=item GUESTFS_EVENT_MUTEX_RELEASED +(payload type: lock file name) + +During shutdown, the handle released the mutex lock. +See L</MUTEX>. + =back =head2 EVENT API @@ -4131,6 +4243,14 @@ example: LIBGUESTFS_MEMSIZE=700 +=item LIBGUESTFS_MUTEX_FILE + +=item LIBGUESTFS_MUTEX_LIMIT + +Set these in order to limit the number of concurrent libguestfs +handles running at once. See L</MUTEX> and +L</guestfs_set_mutex_limit>. + =item LIBGUESTFS_PATH Set the path that libguestfs uses to search for a supermin appliance. diff --git a/src/handle.c b/src/handle.c index c630daf..6c9b311 100644 --- a/src/handle.c +++ b/src/handle.c @@ -144,6 +144,7 @@ guestfs_create_flags (unsigned flags, ...) return g; error: + free (g->mutex_file); free (g->attach_method_arg); free (g->path); free (g->qemu); @@ -157,7 +158,7 @@ parse_environment (guestfs_h *g, char *(*do_getenv) (const void *data, const char *), const void *data) { - int memsize; + int memsize, limit; char *str; /* Don't bother checking the return values of functions @@ -215,6 +216,20 @@ parse_environment (guestfs_h *g, return -1; } + str = do_getenv (data, "LIBGUESTFS_MUTEX_FILE"); + if (str) + guestfs_set_mutex_file (g, str); + + str = do_getenv (data, "LIBGUESTFS_MUTEX_LIMIT"); + if (str) { + if (sscanf (str, "%d", &limit) != 1) { + error (g, _("non-numeric value for LIBGUESTFS_MUTEX_LIMIT")); + return -1; + } + if (guestfs_set_mutex_limit (g, limit) == -1) + return -1; + } + return 0; } @@ -326,6 +341,7 @@ guestfs_close (guestfs_h *g) if (g->pda) hash_free (g->pda); + free (g->mutex_file); free (g->tmpdir); free (g->env_tmpdir); free (g->int_tmpdir); @@ -378,6 +394,8 @@ shutdown_backend (guestfs_h *g, int check_for_errors) if (g->attach_ops->shutdown (g, check_for_errors) == -1) ret = -1; + guestfs___release_mutex (g); + guestfs___free_drives (g); g->state = CONFIG; diff --git a/src/launch.c b/src/launch.c index 7c37667..0401c42 100644 --- a/src/launch.c +++ b/src/launch.c @@ -597,6 +597,10 @@ guestfs__launch (guestfs_h *g) return -1; } + /* Acquire mutex if we need to. */ + if (guestfs___acquire_mutex (g) == -1) + return -1; + /* Start the clock ... */ gettimeofday (&g->launch_t, NULL); TRACE0 (launch_start); diff --git a/src/mutex.c b/src/mutex.c new file mode 100644 index 0000000..82efc9b --- /dev/null +++ b/src/mutex.c @@ -0,0 +1,213 @@ +/* libguestfs + * Copyright (C) 2013 Red Hat Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include <config.h> + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <fcntl.h> +#include <sys/stat.h> +#include <semaphore.h> +#include <errno.h> + +#include "guestfs.h" +#include "guestfs-internal.h" +#include "guestfs-internal-actions.h" +#include "guestfs_protocol.h" + +int +guestfs__set_mutex_file (guestfs_h *g, const char *file) +{ + free (g->mutex_file); + g->mutex_file = NULL; + + if (file) + g->mutex_file = safe_strdup (g, file); + + return 0; +} + +const char * +guestfs__get_mutex_file (guestfs_h *g) +{ + return g->mutex_file; +} + +int +guestfs__set_mutex_limit (guestfs_h *g, int limit) +{ + if (limit > 1000) { /* that would be > 1000 concurrent handles */ + error (g, _("mutex limit is too large. If you want it to be unlimited set it to 0. If you want a larger-but-finite limit then you have to recompile libguestfs.")); + return -1; + } + if (limit == -1) { + error (g, _("mutex limit cannot be set to -1 (did you mean -2?)")); + return -1; + } + if (limit >= -127 && limit <= -3) { + error (g, _("mutex limit cannot be set to -3..-127")); + return -1; + } + if (limit < -10000) { /* that would be a > 10 GB process limit */ + error (g, _("mutex limit is too small")); + return -1; + } + + g->mutex_limit = limit; + return 0; +} + +int +guestfs__get_mutex_limit (guestfs_h *g) +{ + return g->mutex_limit; +} + +static int +mutex_is_enabled (guestfs_h *g) +{ + return g->mutex_file != NULL && g->mutex_limit != 0; +} + +static void +read_free_memory (guestfs_h *g, void *datav, const char *line, size_t len) +{ + int *mbytesp = (int *) datav; + + if (sscanf (line, "%d", mbytesp) == -1) + *mbytesp = -1; +} + +static int +get_free_memory (guestfs_h *g) +{ + CLEANUP_CMD_CLOSE struct command *cmd = guestfs___new_command (g); + int r, mbytes = -1; + + guestfs___cmd_add_string_unquoted (cmd, "free -m | " + "grep 'buffers/cache' | " + "awk '{print $NF}'"); + guestfs___cmd_set_stdout_callback (cmd, read_free_memory, &mbytes, 0); + r = guestfs___cmd_run (cmd); + if (r == -1) + return -1; + if (!WIFEXITED (r) || WEXITSTATUS (r) != 0) { + error (g, _("failed when trying to read free memory")); + return -1; + } + + if (mbytes == -1) { + error (g, _("unexpected output from 'free -m' command")); + return -1; + } + + debug (g, "get_free_memory: %d MB free", mbytes); + + return mbytes; +} + +static int +get_initial_value (guestfs_h *g) +{ + int free_mbytes; + + if (g->mutex_limit >= 1) + return g->mutex_limit; + + free_mbytes = get_free_memory (g); + if (free_mbytes == -1) + return -1; + + if (g->mutex_limit == -2) { + /* This is an overestimate ... */ + int estimate_size_per_appliance = DEFAULT_MEMSIZE + 350; + return MAX (1, free_mbytes / estimate_size_per_appliance); + } + + return MAX (1, free_mbytes / -g->mutex_limit); +} + +/* This is called very early in 'launch' to acquire the mutex. */ +int +guestfs___acquire_mutex (guestfs_h *g) +{ + sem_t *semaphore; + int v; + + if (!mutex_is_enabled (g)) + return 0; + + v = get_initial_value (g); + if (v == -1) + return -1; + + debug (g, "mutex: initializing semaphore %s with value %d (note that if the semaphore exists already, then this value is ignored)", g->mutex_file, v); + + /* XXX umask */ + semaphore = sem_open (g->mutex_file, O_CREAT|O_CLOEXEC, 0777, (unsigned) v); + if (semaphore == SEM_FAILED) { + perrorf (g, _("mutex: sem_open: %s"), g->mutex_file); + return -1; + } + + if (sem_trywait (semaphore) == -1) { + if (errno == EAGAIN) { + debug (g, _("mutex: blocked waiting for semaphore %s " + "(see \"MUTEX\" in guestfs(3))"), + g->mutex_file); + + guestfs___call_callbacks_message (g, GUESTFS_EVENT_MUTEX_BLOCKED, + g->mutex_file, strlen (g->mutex_file)); + + if (sem_wait (semaphore) == -1) + goto error; + } + else { + error: + perrorf (g, _("mutex: sem_wait: %s"), g->mutex_file); + sem_close (semaphore); + return -1; + } + } + + g->semaphore = semaphore; + + guestfs___call_callbacks_message (g, GUESTFS_EVENT_MUTEX_ENTERED, + g->mutex_file, strlen (g->mutex_file)); + + return 0; +} + +/* This is called late in 'shutdown' to release the mutex. */ +void +guestfs___release_mutex (guestfs_h *g) +{ + if (!g->semaphore) + return; + + if (sem_post (g->semaphore) == -1) + debug (g, "sem_post: %s", g->mutex_file); + if (sem_close (g->semaphore) == -1) + debug (g, "sem_close: %s", g->mutex_file); + g->semaphore = NULL; + + guestfs___call_callbacks_message (g, GUESTFS_EVENT_MUTEX_RELEASED, + g->mutex_file, strlen (g->mutex_file)); +} diff --git a/src/proto.c b/src/proto.c index 2e3b480..f909f6e 100644 --- a/src/proto.c +++ b/src/proto.c @@ -168,6 +168,7 @@ child_cleanup (guestfs_h *g) g->fd[1] = -1; g->sock = -1; memset (&g->launch_t, 0, sizeof g->launch_t); + guestfs___release_mutex (g); guestfs___free_drives (g); g->state = CONFIG; guestfs___call_callbacks_void (g, GUESTFS_EVENT_SUBPROCESS_QUIT); diff --git a/test-tool/test-tool.c b/test-tool/test-tool.c index d71caed..621f625 100644 --- a/test-tool/test-tool.c +++ b/test-tool/test-tool.c @@ -248,6 +248,9 @@ main (int argc, char *argv[]) free (p); printf ("guestfs_get_direct: %d\n", guestfs_get_direct (g)); printf ("guestfs_get_memsize: %d\n", guestfs_get_memsize (g)); + printf ("guestfs_get_mutex_file: %s\n", + guestfs_get_mutex_file (g) ? : "(null)"); + printf ("guestfs_get_mutex_limit: %d\n", guestfs_get_mutex_limit (g)); printf ("guestfs_get_network: %d\n", guestfs_get_network (g)); printf ("guestfs_get_path: %s\n", guestfs_get_path (g) ? : "(null)"); printf ("guestfs_get_pgroup: %d\n", guestfs_get_pgroup (g)); -- 1.8.1.2
Richard W.M. Jones
2013-Feb-18 21:20 UTC
[Libguestfs] [PATCH for discussion only 3/3] tests: Set mutex limit to 2 when running tests.
From: "Richard W.M. Jones" <rjones at redhat.com> This also enables parallel-tests if it is the default in automake (ie. automake >= 1.13, see commit 2c68aca9d791414e011d31bfc09255158972599b). --- configure.ac | 2 +- run.in | 11 +++++++++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index 5129f4f..eba8c54 100644 --- a/configure.ac +++ b/configure.ac @@ -24,7 +24,7 @@ m4_define([libguestfs_release], [11]) AC_INIT([libguestfs],libguestfs_major.libguestfs_minor.libguestfs_release) AC_CONFIG_AUX_DIR([build-aux]) -AM_INIT_AUTOMAKE([foreign serial-tests]) +AM_INIT_AUTOMAKE([foreign]) m4_ifndef([AM_SILENT_RULES], [m4_define([AM_SILENT_RULES],[])]) AM_SILENT_RULES([yes]) # make --enable-silent-rules the default. diff --git a/run.in b/run.in index 9cfa88d..37e80d8 100755 --- a/run.in +++ b/run.in @@ -56,6 +56,17 @@ chcon --reference=/tmp tmp 2>/dev/null ||: # Set local environment relative to this script. export LIBGUESTFS_PATH="$b/appliance" +# Limit number of concurrent handles for tests, but let the user +# override this. +if [ -z "$LIBGUESTFS_MUTEX_FILE" ]; then + LIBGUESTFS_MUTEX_FILE="/guestfs.mutex.$(id -u)" + export LIBGUESTFS_MUTEX_FILE +fi +if [ -z "$LIBGUESTFS_MUTEX_LIMIT" ]; then + LIBGUESTFS_MUTEX_LIMIT=2 + export LIBGUESTFS_MUTEX_LIMIT +fi + if [ -z "$LD_LIBRARY_PATH" ]; then LD_LIBRARY_PATH="$b/src/.libs:$b/gobject/.libs" else -- 1.8.1.2
Daniel P. Berrange
2013-Feb-19 14:17 UTC
[Libguestfs] [PATCH for discussion only 0/3] Implement mutexes to limit number of concurrent instances of libguestfs.
On Mon, Feb 18, 2013 at 09:20:42PM +0000, Richard W.M. Jones wrote:> These three patches (for discussion only, NOT to be applied) implement > a mutex system that lets the user limit the number of libguestfs > instances that can be launched per host. There are two uses that I > have identified for this: firstly so we can enable parallel-tests (the > default in automake >= 1.13) without blowing up the host. Secondly > oVirt has raised concerns about how to limit the number of libguestfs > appliances that can run to prevent this from interfering with their > ordinary guests.IMHO this whole feature is of dubious worth & overly simplistic. For automake you can already control parallelization of tests just by varying the '-jNNN' number. If oVirt wants to limit the number of appliances it creates, it should just do so itself. For appliances not directly invoked by ovirt, I don't see that this is going to help, since you can't rely on the env vars being set. Daniel -- |: http://berrange.com -o- http://www.flickr.com/photos/dberrange/ :| |: http://libvirt.org -o- http://virt-manager.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: http://entangle-photo.org -o- http://live.gnome.org/gtk-vnc :|
Apparently Analagous Threads
- upgraded to kernel 2.4.19 from 2.4.7, samba not found from windows, network ok
- Root did not create the semaphore
- [PATCH 1/3] Introduce nouveau_bo_wait for waiting on a BO with a GPU channel
- [PATCH 1/3] Introduce nouveau_bo_wait for waiting on a BO with a GPU channel (v2)
- Prevent infinite recursion in rwrite()