lib: Return instead of exit in event

Modifies behavior of spdk_app_start() and spdk_app_parse_args()
such that they return on failure instead of terminating with
exit().

Change-Id: I82566417f04e1ae2e3ca60a00c72e664db26c9e4
Signed-off-by: Lance Hartmann <lance.hartmann@oracle.com>
Reviewed-on: https://review.gerrithub.io/401243
Tested-by: SPDK Automated Test System <sys_sgsw@intel.com>
Reviewed-by: Jim Harris <james.r.harris@intel.com>
Reviewed-by: Daniel Verkamp <daniel.verkamp@intel.com>
This commit is contained in:
Lance Hartmann 2018-02-22 18:50:51 -05:00 committed by Jim Harris
parent 53d5499e32
commit b9be940ae9
20 changed files with 181 additions and 63 deletions

View File

@ -33,6 +33,20 @@ A number of functions have been renamed:
The old names still exist but are deprecated. They will be removed in the v18.07 release.
### Lib
A set of changes were made in the SPDK's lib code altering,
instances of calls to `exit()` and `abort()` to return a failure instead
wherever reasonably possible.
spdk_app_start() no longer exit()'s on an internal failure, but
instead returns a non-zero error status.
spdk_app_parse_args() no longer exit()'s on help, '-h', or an invalid
option, but instead returns SPDK_APP_PARSE_ARGS_HELP and
SPDK_APP_PARSE_ARGS_FAIL, respectively, and SPDK_APP_PARSE_ARGS_SUCCESS
on success.
## v18.01: Blobstore Thin Provisioning
### Build System

View File

@ -93,7 +93,11 @@ main(int argc, char **argv)
spdk_app_opts_init(&opts);
opts.config_file = SPDK_ISCSI_DEFAULT_CONFIG;
opts.name = "iscsi";
spdk_app_parse_args(argc, argv, &opts, "b", iscsi_parse_arg, iscsi_usage);
if ((rc = spdk_app_parse_args(argc, argv, &opts, "b",
iscsi_parse_arg, iscsi_usage)) !=
SPDK_APP_PARSE_ARGS_SUCCESS) {
exit(rc);
}
if (g_daemon_mode) {
if (daemon(1, 0) < 0) {
@ -107,6 +111,9 @@ main(int argc, char **argv)
/* Blocks until the application is exiting */
rc = spdk_app_start(&opts, spdk_startup, NULL, NULL);
if (rc) {
SPDK_ERRLOG("Start iscsi target daemon: spdk_app_start() retn non-zero\n");
}
spdk_app_fini();

View File

@ -62,7 +62,11 @@ main(int argc, char **argv)
opts.name = "nvmf";
opts.config_file = SPDK_NVMF_DEFAULT_CONFIG;
opts.max_delay_us = 1000; /* 1 ms */
spdk_app_parse_args(argc, argv, &opts, "", nvmf_parse_arg, nvmf_usage);
if ((rc = spdk_app_parse_args(argc, argv, &opts, "",
nvmf_parse_arg, nvmf_usage)) !=
SPDK_APP_PARSE_ARGS_SUCCESS) {
exit(rc);
}
rc = spdk_nvmf_tgt_start(&opts);

View File

@ -335,6 +335,9 @@ spdk_nvmf_tgt_start(struct spdk_app_opts *opts)
/* Blocks until the application is exiting */
rc = spdk_app_start(opts, nvmf_tgt_advance_state, NULL, NULL);
if (rc) {
SPDK_ERRLOG("spdk_app_start() retn non-zero\n");
}
spdk_app_fini();

View File

@ -99,7 +99,11 @@ main(int argc, char *argv[])
vhost_app_opts_init(&opts);
spdk_app_parse_args(argc, argv, &opts, "f:S:", vhost_parse_arg, vhost_usage);
if ((rc = spdk_app_parse_args(argc, argv, &opts, "f:S:",
vhost_parse_arg, vhost_usage)) !=
SPDK_APP_PARSE_ARGS_SUCCESS) {
exit(rc);
}
if (g_pid_path) {
save_pid(g_pid_path);

View File

@ -70,4 +70,6 @@ scheduled to execute periodically on a timer if low latency is not required.
The framework itself is bundled into a higher level abstraction called an "app". Once
spdk_app_start() is called, it will block the current thread until the application
terminates by calling spdk_app_stop().
terminates by calling spdk_app_stop() or an error condition occurs during the
initialization code within spdk_app_start(), itself, before invoking the caller's
supplied function.

View File

@ -470,7 +470,8 @@ main(int argc, char **argv)
/*
* spdk_app_start() will block running hello_start() until
* spdk_app_stop() is called by someone (not simply when
* hello_start() returns)
* hello_start() returns), or if an error occurs during
* spdk_app_start() before hello_start() runs.
*/
rc = spdk_app_start(&opts, hello_start, hello_context, NULL);
if (rc) {

View File

@ -111,14 +111,16 @@ void spdk_app_opts_init(struct spdk_app_opts *opts);
* Before calling this function, the fields of opts must be initialized by
* spdk_app_opts_init(). Once started, the framework will call start_fn on the
* master core with the arguments provided. This call will block until spdk_app_stop()
* is called.
* is called, or if an error condition occurs during the intialization
* code within spdk_app_start(), itself, before invoking the caller's
* supplied function.
*
* \param opts Initialization options used for this application.
* \param start_fn Event function that is called when the framework starts.
* \param arg1 Argument passed to function start_fn.
* \param arg2 Argument passed to function start_fn.
*
* \return 0 on success or abnormal exit on failure.
* \return 0 on success or non-zero on failure.
*/
int spdk_app_start(struct spdk_app_opts *opts, spdk_event_fn start_fn,
void *arg1, void *arg2);
@ -145,7 +147,7 @@ void spdk_app_start_shutdown(void);
* process and returns. Once the shutdown process is complete, spdk_app_start()
* will return.
*
* \param rc The rc value specified here will be returned to caller of spdk_app_stat.
* \param rc The rc value specified here will be returned to caller of spdk_app_start().
*/
void spdk_app_stop(int rc);
@ -185,6 +187,13 @@ struct spdk_cpuset *spdk_app_get_core_mask(void);
#define SPDK_APP_GETOPT_STRING "c:de:hi:m:n:p:qr:s:t:"
enum spdk_app_parse_args_rvals {
SPDK_APP_PARSE_ARGS_HELP = 0,
SPDK_APP_PARSE_ARGS_SUCCESS = 1,
SPDK_APP_PARSE_ARGS_FAIL = 2
};
typedef enum spdk_app_parse_args_rvals spdk_app_parse_args_rvals_t;
/**
* Helper function for parsing arguments and printing usage messages.
*
@ -195,13 +204,13 @@ struct spdk_cpuset *spdk_app_get_core_mask(void);
* Characters in this string must not conflict with characters in SPDK_APP_GETOPT_STRING.
* \param parse Function pointer to call if an argument in getopt_str is found.
* \param usage Function pointer to print usage messages for app-specific command
* line parameters.
*
* \return 0 on success or exit application directly otherwise.
* line parameters.
*\return SPDK_APP_PARSE_ARGS_FAIL on failure, SPDK_APP_PARSE_ARGS_SUCCESS on
* success, SPDK_APP_PARSE_ARGS_HELP if '-h' passed as an option.
*/
int spdk_app_parse_args(int argc, char **argv, struct spdk_app_opts *opts,
const char *getopt_str, void (*parse)(int ch, char *arg),
void (*usage)(void));
spdk_app_parse_args_rvals_t spdk_app_parse_args(int argc, char **argv,
struct spdk_app_opts *opts, const char *getopt_str,
void (*parse)(int ch, char *arg), void (*usage)(void));
/**
* Allocate an event to be passed to spdk_event_call().

View File

@ -288,7 +288,7 @@ spdk_app_start(struct spdk_app_opts *opts, spdk_event_fn start_fn,
if (!opts) {
SPDK_ERRLOG("opts should not be NULL\n");
exit(EXIT_FAILURE);
return 1;
}
if (opts->print_level > SPDK_LOG_WARN &&
@ -319,12 +319,12 @@ spdk_app_start(struct spdk_app_opts *opts, spdk_event_fn start_fn,
if (rc != 0) {
SPDK_ERRLOG("Could not read config file %s\n", opts->config_file);
spdk_conf_free(config);
exit(EXIT_FAILURE);
return 1;
}
if (spdk_conf_first_section(config) == NULL) {
SPDK_ERRLOG("Invalid config file %s\n", opts->config_file);
spdk_conf_free(config);
exit(EXIT_FAILURE);
return 1;
}
}
spdk_conf_set_as_default(config);
@ -369,8 +369,9 @@ spdk_app_start(struct spdk_app_opts *opts, spdk_event_fn start_fn,
if (spdk_env_init(&env_opts) < 0) {
SPDK_ERRLOG("Unable to initialize SPDK env\n");
spdk_log_close();
spdk_conf_free(g_spdk_app.config);
exit(EXIT_FAILURE);
return 1;
}
SPDK_NOTICELOG("Total cores available: %d\n", spdk_env_get_core_count());
@ -380,15 +381,17 @@ spdk_app_start(struct spdk_app_opts *opts, spdk_event_fn start_fn,
* reactor_mask will be 0x1 which will enable core 0 to run one
* reactor.
*/
if (spdk_reactors_init(opts->max_delay_us)) {
if ((rc = spdk_reactors_init(opts->max_delay_us)) != 0) {
SPDK_ERRLOG("Invalid reactor mask.\n");
spdk_log_close();
spdk_conf_free(g_spdk_app.config);
exit(EXIT_FAILURE);
return 1;
}
if (spdk_app_setup_signal_handlers(opts)) {
if ((rc = spdk_app_setup_signal_handlers(opts)) != 0) {
spdk_conf_free(g_spdk_app.config);
exit(EXIT_FAILURE);
spdk_log_close();
return 1;
}
if (opts->shm_id >= 0) {
@ -459,6 +462,9 @@ _spdk_app_stop(void *arg1, void *arg2)
void
spdk_app_stop(int rc)
{
if (rc) {
SPDK_WARNLOG("spdk_app_stop'd on non-zero\n");
}
g_spdk_app.rc = rc;
/*
* We want to run spdk_subsystem_fini() from the same lcore where spdk_subsystem_init()
@ -492,7 +498,7 @@ usage(char *executable_name, struct spdk_app_opts *default_opts, void (*app_usag
app_usage();
}
int
spdk_app_parse_args_rvals_t
spdk_app_parse_args(int argc, char **argv, struct spdk_app_opts *opts,
const char *app_getopt_str, void (*app_parse)(int ch, char *arg),
void (*app_usage)(void))
@ -500,6 +506,7 @@ spdk_app_parse_args(int argc, char **argv, struct spdk_app_opts *opts,
int ch, rc;
struct spdk_app_opts default_opts;
char *getopt_str;
spdk_app_parse_args_rvals_t rval = SPDK_APP_PARSE_ARGS_SUCCESS;
memcpy(&default_opts, opts, sizeof(default_opts));
@ -510,7 +517,8 @@ spdk_app_parse_args(int argc, char **argv, struct spdk_app_opts *opts,
getopt_str = spdk_sprintf_alloc("%s%s", app_getopt_str, SPDK_APP_GETOPT_STRING);
if (getopt_str == NULL) {
fprintf(stderr, "Could not allocate getopt_str in %s()\n", __func__);
exit(EXIT_FAILURE);
rval = SPDK_APP_PARSE_ARGS_FAIL;
goto parse_early_fail;
}
while ((ch = getopt(argc, argv, getopt_str)) != -1) {
@ -526,7 +534,8 @@ spdk_app_parse_args(int argc, char **argv, struct spdk_app_opts *opts,
break;
case 'h':
usage(argv[0], &default_opts, app_usage);
exit(EXIT_SUCCESS);
rval = SPDK_APP_PARSE_ARGS_HELP;
goto parse_done;
case 'i':
opts->shm_id = atoi(optarg);
break;
@ -553,7 +562,8 @@ spdk_app_parse_args(int argc, char **argv, struct spdk_app_opts *opts,
if (rc != 0) {
fprintf(stderr, "invalid memory pool size `-s %s`\n", optarg);
usage(argv[0], &default_opts, app_usage);
exit(EXIT_FAILURE);
rval = SPDK_APP_PARSE_ARGS_FAIL;
goto parse_done;
}
if (mem_size_has_prefix) {
@ -566,7 +576,8 @@ spdk_app_parse_args(int argc, char **argv, struct spdk_app_opts *opts,
if (mem_size_mb > INT_MAX) {
fprintf(stderr, "invalid memory pool size `-s %s`\n", optarg);
usage(argv[0], &default_opts, app_usage);
exit(EXIT_FAILURE);
rval = SPDK_APP_PARSE_ARGS_FAIL;
goto parse_done;
}
opts->mem_size = (int) mem_size_mb;
@ -577,25 +588,36 @@ spdk_app_parse_args(int argc, char **argv, struct spdk_app_opts *opts,
if (rc < 0) {
fprintf(stderr, "unknown flag\n");
usage(argv[0], &default_opts, app_usage);
exit(EXIT_FAILURE);
rval = SPDK_APP_PARSE_ARGS_FAIL;
goto parse_done;
}
opts->print_level = SPDK_LOG_DEBUG;
#ifndef DEBUG
fprintf(stderr, "%s must be built with CONFIG_DEBUG=y for -t flag\n",
argv[0]);
usage(argv[0], &default_opts, app_usage);
exit(EXIT_FAILURE);
#endif
rval = SPDK_APP_PARSE_ARGS_FAIL;
goto parse_done;
#else
break;
#endif
case '?':
/*
* In the event getopt() above detects an option
* in argv that is NOT in the getopt_str,
* getopt() will return a '?' indicating failure.
*/
usage(argv[0], &default_opts, app_usage);
exit(EXIT_FAILURE);
rval = SPDK_APP_PARSE_ARGS_FAIL;
goto parse_done;
default:
app_parse(ch, optarg);
}
}
parse_done:
free(getopt_str);
return 0;
parse_early_fail:
return rval;
}

View File

@ -32,6 +32,7 @@
*/
#include "spdk/stdinc.h"
#include "spdk/likely.h"
#include "spdk_internal/event.h"
#include "spdk_internal/log.h"
@ -130,7 +131,7 @@ static struct spdk_reactor *
spdk_reactor_get(uint32_t lcore)
{
struct spdk_reactor *reactor;
reactor = &g_reactors[lcore];
reactor = spdk_likely(g_reactors) ? &g_reactors[lcore] : NULL;
return reactor;
}
@ -725,7 +726,7 @@ spdk_reactors_fini(void)
SPDK_ENV_FOREACH_CORE(i) {
reactor = spdk_reactor_get(i);
if (reactor->events != NULL) {
if (spdk_likely(reactor != NULL) && reactor->events != NULL) {
spdk_ring_free(reactor->events);
}
}
@ -737,6 +738,7 @@ spdk_reactors_fini(void)
}
free(g_reactors);
g_reactors = NULL;
}
SPDK_LOG_REGISTER_COMPONENT("reactor", SPDK_LOG_REACTOR)

View File

@ -33,6 +33,8 @@
#include "rocksdb/env.h"
#include <set>
#include <iostream>
#include <stdexcept>
extern "C" {
#include "spdk/env.h"
@ -53,6 +55,7 @@ struct spdk_bs_dev *g_bs_dev;
uint32_t g_lcore = 0;
std::string g_bdev_name;
volatile bool g_spdk_ready = false;
volatile bool g_spdk_start_failure = false;
struct sync_args {
struct spdk_io_channel *channel;
};
@ -293,6 +296,12 @@ public:
}
};
class SpdkAppStartException : public std::runtime_error
{
public:
SpdkAppStartException(std::string mess): std::runtime_error(mess) {}
};
class SpdkEnv : public EnvWrapper
{
private:
@ -578,12 +587,25 @@ static void *
initialize_spdk(void *arg)
{
struct spdk_app_opts *opts = (struct spdk_app_opts *)arg;
int rc;
spdk_app_start(opts, spdk_rocksdb_run, NULL, NULL);
spdk_app_fini();
delete opts;
rc = spdk_app_start(opts, spdk_rocksdb_run, NULL, NULL);
/*
* TODO: Revisit for case of internal failure of
* spdk_app_start(), itself. At this time, it's known
* the only application's use of spdk_app_stop() passes
* a zero; i.e. no fail (non-zero) cases so here we
* assume there was an internal failure and flag it
* so we can throw an exception.
*/
if (rc) {
g_spdk_start_failure = true;
} else {
spdk_app_fini();
delete opts;
}
pthread_exit(NULL);
}
SpdkEnv::SpdkEnv(Env *base_env, const std::string &dir, const std::string &conf,
@ -602,8 +624,12 @@ SpdkEnv::SpdkEnv(Env *base_env, const std::string &dir, const std::string &conf,
g_bdev_name = mBdev;
pthread_create(&mSpdkTid, NULL, &initialize_spdk, opts);
while (!g_spdk_ready)
while (!g_spdk_ready && !g_spdk_start_failure)
;
if (g_spdk_start_failure) {
delete opts;
throw SpdkAppStartException("spdk_app_start() unable to start spdk_rocksdb_run()");
}
SpdkInitializeThread();
}
@ -635,12 +661,19 @@ SpdkEnv::~SpdkEnv()
Env *NewSpdkEnv(Env *base_env, const std::string &dir, const std::string &conf,
const std::string &bdev, uint64_t cache_size_in_mb)
{
SpdkEnv *spdk_env = new SpdkEnv(base_env, dir, conf, bdev, cache_size_in_mb);
if (g_fs != NULL) {
return spdk_env;
} else {
delete spdk_env;
try {
SpdkEnv *spdk_env = new SpdkEnv(base_env, dir, conf, bdev, cache_size_in_mb);
if (g_fs != NULL) {
return spdk_env;
} else {
delete spdk_env;
return NULL;
}
} catch (SpdkAppStartException &e) {
SPDK_ERRLOG("NewSpdkEnv: exception caught: %s", e.what());
return NULL;
} catch (...) {
SPDK_ERRLOG("NewSpdkEnv: default exception caught");
return NULL;
}
}

View File

@ -127,6 +127,9 @@ spdk_trace_init(const char *shm_name)
void
spdk_trace_cleanup(void)
{
munmap(g_trace_histories, sizeof(struct spdk_trace_histories));
if (g_trace_histories) {
munmap(g_trace_histories, sizeof(struct spdk_trace_histories));
g_trace_histories = NULL;
}
shm_unlink(g_shm_name);
}

View File

@ -85,9 +85,10 @@ main(int argc, char **argv)
opts.shutdown_cb = bdev_svc_shutdown;
opts.max_delay_us = 1000 * 1000;
rc = spdk_app_parse_args(argc, argv, &opts, "", bdev_svc_parse_arg, bdev_svc_usage);
if (rc) {
return rc;
if ((rc = spdk_app_parse_args(argc, argv, &opts, "",
bdev_svc_parse_arg, bdev_svc_usage)) !=
SPDK_APP_PARSE_ARGS_SUCCESS) {
exit(rc);
}
rc = spdk_app_start(&opts, bdev_svc_start, (void *)(intptr_t)opts.shm_id, NULL);

View File

@ -140,7 +140,7 @@ main(int argc, char **argv)
opts.shutdown_cb = stub_shutdown;
opts.max_delay_us = 1000 * 1000;
spdk_app_start(&opts, stub_start, (void *)(intptr_t)opts.shm_id, NULL);
ch = spdk_app_start(&opts, stub_start, (void *)(intptr_t)opts.shm_id, NULL);
return 0;
return ch;
}

View File

@ -761,6 +761,7 @@ main(int argc, char **argv)
struct spdk_app_opts opts = {};
int time_in_sec;
uint64_t show_performance_period_in_usec = 0;
int rc;
/* default value */
config_file = NULL;
@ -927,7 +928,10 @@ main(int argc, char **argv)
}
opts.shutdown_cb = spdk_bdevperf_shutdown_cb;
spdk_app_start(&opts, bdevperf_run, NULL, NULL);
rc = spdk_app_start(&opts, bdevperf_run, NULL, NULL);
if (rc) {
g_run_failed = true;
}
if (g_shutdown) {
g_time_in_usec = g_shutdown_tsc * 1000000 / spdk_get_ticks_hz();

View File

@ -318,6 +318,7 @@ spdk_fuse_shutdown(void)
int main(int argc, char **argv)
{
struct spdk_app_opts opts = {};
int rc = 0;
if (argc < 4) {
fprintf(stderr, "usage: %s <conffile> <bdev name> <mountpoint>\n", argv[0]);
@ -336,8 +337,8 @@ int main(int argc, char **argv)
g_fuse_argc = argc - 2;
g_fuse_argv = &argv[2];
spdk_app_start(&opts, spdk_fuse_run, NULL, NULL);
rc = spdk_app_start(&opts, spdk_fuse_run, NULL, NULL);
spdk_app_fini();
return 0;
return rc;
}

View File

@ -121,6 +121,7 @@ mkfs_parse_arg(int ch, char *arg)
int main(int argc, char **argv)
{
struct spdk_app_opts opts = {};
int rc = 0;
if (argc < 3) {
SPDK_ERRLOG("usage: %s <conffile> <bdevname>\n", argv[0]);
@ -136,10 +137,14 @@ int main(int argc, char **argv)
spdk_fs_set_cache_size(512);
g_bdev_name = argv[2];
spdk_app_parse_args(argc, argv, &opts, "C:", mkfs_parse_arg, mkfs_usage);
if ((rc = spdk_app_parse_args(argc, argv, &opts, "C:",
mkfs_parse_arg, mkfs_usage)) !=
SPDK_APP_PARSE_ARGS_SUCCESS) {
exit(rc);
}
spdk_app_start(&opts, spdk_mkfs_run, NULL, NULL);
rc = spdk_app_start(&opts, spdk_mkfs_run, NULL, NULL);
spdk_app_fini();
return 0;
return rc;
}

View File

@ -141,6 +141,7 @@ main(int argc, char **argv)
{
struct spdk_app_opts opts = {};
int op;
int rc = 0;
opts.name = "event_perf";
@ -168,11 +169,11 @@ main(int argc, char **argv)
printf("Running I/O for %d seconds...", g_time_in_sec);
fflush(stdout);
spdk_app_start(&opts, event_perf_start, NULL, NULL);
rc = spdk_app_start(&opts, event_perf_start, NULL, NULL);
spdk_app_fini();
performance_dump(g_time_in_sec);
printf("done.\n");
return 0;
return rc;
}

View File

@ -106,6 +106,7 @@ main(int argc, char **argv)
{
struct spdk_app_opts opts;
int op;
int rc = 0;
spdk_app_opts_init(&opts);
opts.name = "reactor";
@ -129,9 +130,9 @@ main(int argc, char **argv)
exit(1);
}
spdk_app_start(&opts, test_start, NULL, NULL);
rc = spdk_app_start(&opts, test_start, NULL, NULL);
spdk_app_fini();
return 0;
return rc;
}

View File

@ -100,6 +100,7 @@ main(int argc, char **argv)
{
struct spdk_app_opts opts;
int op;
int rc;
spdk_app_opts_init(&opts);
opts.name = "reactor_perf";
@ -132,11 +133,11 @@ main(int argc, char **argv)
opts.shutdown_cb = test_cleanup;
spdk_app_start(&opts, test_start, NULL, NULL);
rc = spdk_app_start(&opts, test_start, NULL, NULL);
spdk_app_fini();
printf("Performance: %8ju events per second\n", g_call_count / g_time_in_sec);
return 0;
return rc;
}