Delay the initialization of the thread model until after backend->config_complete; this is safe, since we don't make any lock calls until backend->connect. Then add a function callback that filters can use to further reduce things based on runtime configuration.
Signed-off-by: Eric Blake <[email protected]> --- Is it worth having filters both #define THREAD_MODEL and optionally declare .thread_model? We have no API stability requirements; we could instead declare that NBDKIT_REGISTER_FILTER() does NOT require a macro THREAD_MODEL, and that .thread_model is optional (defaulting to parallel, but MUST be provided by filters that want to reduce things). --- docs/nbdkit-filter.pod | 25 ++++++++++++++++++++++--- include/nbdkit-filter.h | 1 + server/filters.c | 8 ++++++++ server/main.c | 10 ++++++---- 4 files changed, 37 insertions(+), 7 deletions(-) diff --git a/docs/nbdkit-filter.pod b/docs/nbdkit-filter.pod index 857f241..4033789 100644 --- a/docs/nbdkit-filter.pod +++ b/docs/nbdkit-filter.pod @@ -109,12 +109,16 @@ All filters should start by including this header file. =head1 C<#define THREAD_MODEL> -All filters must define a thread model. See -L<nbdkit-plugin(3)/THREADS> for a discussion of thread models. +All filters must define a default thread model by defining +C<THREAD_MODEL>. See L<nbdkit-plugin(3)/THREADS> for a discussion of +thread models. The final thread model is the smallest (ie. most serialized) out of all the filters and the plugin. Filters cannot alter the thread model -to make it larger (more parallel). +to make it larger (more parallel). However, they can dynamically +request a smaller (more serialized) model from decisions made during +C<.config> and C<.config_complete>, by implementing a <.thread_model> +function callback. If possible filters should be be written to handle fully parallel requests (C<NBDKIT_THREAD_MODEL_PARALLEL>, even multiple requests @@ -267,6 +271,21 @@ what already appears in C<.description>. If the filter doesn't take any config parameters you should probably omit this. +=head2 C<.thread_model> + + int (*thread_model) (void); + +This optional function is called after C<.config_complete> to provide +the filter an opportunity to reduce the resulting thread model below +the value used at compilation via C<THREAD_MODEL>. The resulting +thread model for all connections is determined by selecting the most +restrictive model from the C<THREAD_MODEL> of the plugin and all +filters, and from the results of any C<.thread_model> across all +filters. + +If there is an error, C<.thread_model> should call C<nbdkit_error> +with an error message and return C<-1>. + =head2 C<.open> void * (*open) (nbdkit_next_open *next, void *nxdata, diff --git a/include/nbdkit-filter.h b/include/nbdkit-filter.h index 5893dd8..70d32ce 100644 --- a/include/nbdkit-filter.h +++ b/include/nbdkit-filter.h @@ -115,6 +115,7 @@ struct nbdkit_filter { const char *key, const char *value); int (*config_complete) (nbdkit_next_config_complete *next, void *nxdata); const char *config_help; + int (*thread_model) (void); void * (*open) (nbdkit_next_open *next, void *nxdata, int readonly); diff --git a/server/filters.c b/server/filters.c index 3bd91fe..87a9c0e 100644 --- a/server/filters.c +++ b/server/filters.c @@ -99,6 +99,14 @@ filter_thread_model (struct backend *b) if (filter_thread_model < thread_model) /* more serialized */ thread_model = filter_thread_model; + if (f->filter.thread_model) { + filter_thread_model = f->filter.thread_model (); + if (filter_thread_model == -1) + exit (EXIT_FAILURE); + if (filter_thread_model < thread_model) + thread_model = filter_thread_model; + } + return thread_model; } diff --git a/server/main.c b/server/main.c index 8ad3f7a..d46888a 100644 --- a/server/main.c +++ b/server/main.c @@ -1,5 +1,5 @@ /* nbdkit - * Copyright (C) 2013-2018 Red Hat Inc. + * Copyright (C) 2013-2019 Red Hat Inc. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are @@ -568,9 +568,6 @@ main (int argc, char *argv[]) debug_flags = next; } - /* Select a thread model. */ - lock_init_thread_model (); - if (help) { struct backend *b; @@ -643,6 +640,11 @@ main (int argc, char *argv[]) backend->config_complete (backend); + /* Select a thread model. Plugin models are fixed at compile time, + * but filters are allowed to reduce the level during config. + */ + lock_init_thread_model (); + start_serving (); backend->free (backend); -- 2.20.1 _______________________________________________ Libguestfs mailing list [email protected] https://www.redhat.com/mailman/listinfo/libguestfs
