Add event-driven application framework
Change-Id: Iba90db6d8853dde972b4eec2c35eb44eeddae780 Signed-off-by: Daniel Verkamp <daniel.verkamp@intel.com>
This commit is contained in:
parent
ab1f6bdc54
commit
eeeac6676d
@ -44,6 +44,7 @@ timing_exit afterboot
|
||||
|
||||
timing_enter lib
|
||||
|
||||
time test/lib/event/event.sh
|
||||
time test/lib/nvme/nvme.sh
|
||||
time test/lib/memory/memory.sh
|
||||
time test/lib/ioat/ioat.sh
|
||||
|
290
include/spdk/event.h
Normal file
290
include/spdk/event.h
Normal file
@ -0,0 +1,290 @@
|
||||
/*-
|
||||
* BSD LICENSE
|
||||
*
|
||||
* Copyright (c) Intel Corporation.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in
|
||||
* the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
* * Neither the name of Intel Corporation nor the names of its
|
||||
* contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/** \file
|
||||
* Event framework public API.
|
||||
*
|
||||
* This is a framework for writing asynchronous, polled-mode, shared-nothing
|
||||
* server applications. The framework relies on DPDK for much of its underlying
|
||||
* architecture. The framework defines several concepts - reactors, events, pollers,
|
||||
* and subsystems - that are described in the following sections.
|
||||
*
|
||||
* The framework runs one thread per core (the user provides a core mask), where
|
||||
* each thread is a tight loop. The threads never block for any reason. These threads
|
||||
* are called reactors and their main responsibility is to process incoming events
|
||||
* from a queue.
|
||||
*
|
||||
* An event, defined by \ref spdk_event is a bundled function pointer and arguments that
|
||||
* can be sent to a different core and executed. The function pointer is executed only once,
|
||||
* and then the entire event is freed. These functions should never block and preferably
|
||||
* should execute very quickly. Events also have a pointer to a 'next' event that will be
|
||||
* executed upon completion of the given event, which allows chaining. This is
|
||||
* very much a simplified version of futures, promises, and continuations designed within
|
||||
* the constraints of the C programming language.
|
||||
*
|
||||
* The framework also defines another type of function called a poller. Pollers are also
|
||||
* functions with arguments that can be bundled and sent to a different core to be executed,
|
||||
* but they are instead executed repeatedly on that core until unregistered. The reactor
|
||||
* will handle interspersing calls to the pollers with other event processing automatically.
|
||||
* Pollers are intended to poll hardware as a replacement for interrupts and they should not
|
||||
* generally be used for any other purpose.
|
||||
*
|
||||
* The framework also defines an interface for subsystems, which are libraries of code that
|
||||
* depend on this framework. A library can register itself as a subsystem and provide
|
||||
* pointers to initialize and destroy itself which will be called at the appropriate time.
|
||||
* This is purely for sequencing initialization code in a convenient manner within the
|
||||
* framework.
|
||||
*
|
||||
* The framework itself is bundled into a higher level abstraction called an "app". Once
|
||||
* \ref spdk_app_start is called it will block the current thread until the application
|
||||
* terminates (by calling \ref spdk_app_stop).
|
||||
*/
|
||||
|
||||
#ifndef SPDK_EVENT_H
|
||||
#define SPDK_EVENT_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "spdk/queue.h"
|
||||
|
||||
#define SPDK_APP_DEFAULT_LOG_FACILITY "local7"
|
||||
#define SPDK_APP_DEFAULT_LOG_PRIORITY "info"
|
||||
|
||||
typedef struct spdk_event *spdk_event_t;
|
||||
typedef void (*spdk_event_fn)(spdk_event_t);
|
||||
|
||||
/**
|
||||
* \brief An event is a function that is passed to and called on an lcore.
|
||||
*/
|
||||
struct spdk_event {
|
||||
uint32_t lcore;
|
||||
spdk_event_fn fn;
|
||||
void *arg1;
|
||||
void *arg2;
|
||||
struct spdk_event *next;
|
||||
};
|
||||
|
||||
typedef void (*spdk_poller_fn)(void *arg);
|
||||
|
||||
/**
|
||||
* \brief A poller is a function that is repeatedly called on an lcore.
|
||||
*/
|
||||
struct spdk_poller {
|
||||
uint32_t lcore;
|
||||
spdk_poller_fn fn;
|
||||
void *arg;
|
||||
};
|
||||
|
||||
#define SPDK_POLLER_RING_SIZE 4096
|
||||
|
||||
/*
|
||||
* -1 accounts for the empty slot needed to differentiate between ring empty
|
||||
* and ring full.
|
||||
*/
|
||||
#define SPDK_MAX_POLLERS_PER_CORE (SPDK_POLLER_RING_SIZE - 1)
|
||||
|
||||
typedef void (*spdk_app_shutdown_cb)(void);
|
||||
typedef void (*spdk_sighandler_t)(int);
|
||||
|
||||
#define SPDK_APP_DPDK_DEFAULT_MEM_SIZE 2048
|
||||
#define SPDK_APP_DPDK_DEFAULT_MASTER_CORE 0
|
||||
#define SPDK_APP_DPDK_DEFAULT_MEM_CHANNEL 4
|
||||
#define SPDK_APP_DPDK_DEFAULT_CORE_MASK "0x1"
|
||||
|
||||
/**
|
||||
* \brief Event framework initialization options
|
||||
*/
|
||||
struct spdk_app_opts {
|
||||
const char *name;
|
||||
const char *config_file;
|
||||
const char *reactor_mask;
|
||||
const char *log_facility;
|
||||
const char *tpoint_group_mask;
|
||||
|
||||
int instance_id;
|
||||
|
||||
spdk_app_shutdown_cb shutdown_cb;
|
||||
spdk_event_fn start_fn;
|
||||
spdk_sighandler_t usr1_handler;
|
||||
|
||||
bool enable_coredump;
|
||||
uint32_t dpdk_mem_channel;
|
||||
uint32_t dpdk_master_core;
|
||||
int dpdk_mem_size;
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief Initialize the default value of opts
|
||||
*/
|
||||
void spdk_app_opts_init(struct spdk_app_opts *opts);
|
||||
|
||||
/**
|
||||
* \brief Initialize DPDK via opts.
|
||||
*/
|
||||
void spdk_init_dpdk(struct spdk_app_opts *opts);
|
||||
|
||||
/**
|
||||
* \brief Initialize an application to use the event framework. This must be called prior to using
|
||||
* any other functions in this library.
|
||||
*/
|
||||
void spdk_app_init(struct spdk_app_opts *opts);
|
||||
|
||||
/**
|
||||
* \brief Perform final shutdown operations on an application using the event framework.
|
||||
*/
|
||||
void spdk_app_fini(void);
|
||||
|
||||
/**
|
||||
* \brief Start the framework. Once started, the framework will call start_fn on the master
|
||||
* core with the arguments provided. This call will block until \ref spdk_app_stop is called.
|
||||
*/
|
||||
int spdk_app_start(spdk_event_fn start_fn, void *arg1, void *arg2);
|
||||
|
||||
/**
|
||||
* \brief Stop the framework. This does not wait for all threads to exit. Instead, it kicks off
|
||||
* the shutdown process and returns. Once the shutdown process is complete, \ref spdk_app_start will return.
|
||||
*/
|
||||
void spdk_app_stop(int rc);
|
||||
|
||||
/**
|
||||
* \brief Generate a configuration file that corresponds to the current running state.
|
||||
*/
|
||||
int spdk_app_get_running_config(char **config_str, char *name);
|
||||
|
||||
/**
|
||||
* \brief Return the instance id for this application.
|
||||
*/
|
||||
int spdk_app_get_instance_id(void);
|
||||
|
||||
/**
|
||||
* \brief Convert a string containing a CPU core mask into a bitmask
|
||||
*/
|
||||
int spdk_app_parse_core_mask(const char *mask, uint64_t *cpumask);
|
||||
|
||||
/**
|
||||
* \brief Return a mask of the CPU cores active for this application
|
||||
*/
|
||||
uint64_t spdk_app_get_core_mask(void);
|
||||
|
||||
/**
|
||||
* \brief Return the number of CPU cores utilized by this application
|
||||
*/
|
||||
int spdk_app_get_core_count(void);
|
||||
|
||||
/**
|
||||
* \brief Allocate an event to be passed to \ref spdk_event_call
|
||||
*/
|
||||
spdk_event_t spdk_event_allocate(uint32_t lcore, spdk_event_fn fn,
|
||||
void *arg1, void *arg2,
|
||||
spdk_event_t next);
|
||||
|
||||
/**
|
||||
* \brief Pass the given event to the associated lcore and call the function.
|
||||
*/
|
||||
void spdk_event_call(spdk_event_t event);
|
||||
|
||||
#define spdk_event_get_next(event) (event)->next
|
||||
#define spdk_event_get_arg1(event) (event)->arg1
|
||||
#define spdk_event_get_arg2(event) (event)->arg2
|
||||
|
||||
/* TODO: This is only used by tests and should be made private */
|
||||
void spdk_event_queue_run_all(uint32_t lcore);
|
||||
|
||||
/**
|
||||
* \brief Register a poller on the given lcore.
|
||||
*/
|
||||
void spdk_poller_register(struct spdk_poller *poller,
|
||||
uint32_t lcore,
|
||||
struct spdk_event *complete);
|
||||
|
||||
/**
|
||||
* \brief Unregister a poller on the given lcore.
|
||||
*/
|
||||
void spdk_poller_unregister(struct spdk_poller *poller,
|
||||
struct spdk_event *complete);
|
||||
|
||||
/**
|
||||
* \brief Move a poller from its current lcore to a new lcore.
|
||||
*/
|
||||
void spdk_poller_migrate(struct spdk_poller *poller, int new_lcore,
|
||||
struct spdk_event *complete);
|
||||
|
||||
struct spdk_subsystem {
|
||||
const char *name;
|
||||
int (*init)(void);
|
||||
int (*fini)(void);
|
||||
void (*config)(FILE *fp);
|
||||
TAILQ_ENTRY(spdk_subsystem) tailq;
|
||||
};
|
||||
|
||||
struct spdk_subsystem_depend {
|
||||
const char *name;
|
||||
const char *depends_on;
|
||||
TAILQ_ENTRY(spdk_subsystem_depend) tailq;
|
||||
};
|
||||
|
||||
void spdk_add_subsystem(struct spdk_subsystem *subsystem);
|
||||
void spdk_add_subsystem_depend(struct spdk_subsystem_depend *depend);
|
||||
|
||||
/**
|
||||
* \brief Register a new subsystem
|
||||
*/
|
||||
#define SPDK_SUBSYSTEM_REGISTER(_name, _init, _fini, _config) \
|
||||
static struct spdk_subsystem __subsystem_ ## _name = { \
|
||||
.name = #_name, \
|
||||
.init = _init, \
|
||||
.fini = _fini, \
|
||||
.config = _config, \
|
||||
}; \
|
||||
__attribute__((constructor)) static void _name ## _register(void) \
|
||||
{ \
|
||||
spdk_add_subsystem(&__subsystem_ ## _name); \
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Declare that a subsystem depends on another subsystem.
|
||||
*/
|
||||
#define SPDK_SUBSYSTEM_DEPEND(_name, _depends_on) \
|
||||
static struct spdk_subsystem_depend __subsystem_ ## _name ## _depend_on ## _depends_on = { \
|
||||
.name = #_name, \
|
||||
.depends_on = #_depends_on, \
|
||||
}; \
|
||||
__attribute__((constructor)) static void _name ## _depend_on ## _depends_on(void) \
|
||||
{ \
|
||||
spdk_add_subsystem_depend(&__subsystem_ ## _name ## _depend_on ## _depends_on); \
|
||||
}
|
||||
|
||||
#endif
|
@ -34,7 +34,7 @@
|
||||
SPDK_ROOT_DIR := $(abspath $(CURDIR)/..)
|
||||
include $(SPDK_ROOT_DIR)/mk/spdk.common.mk
|
||||
|
||||
DIRS-y += conf cunit json jsonrpc log memory trace util nvme ioat
|
||||
DIRS-y += conf cunit event json jsonrpc log memory trace util nvme ioat
|
||||
|
||||
.PHONY: all clean $(DIRS-y)
|
||||
|
||||
|
40
lib/event/Makefile
Normal file
40
lib/event/Makefile
Normal file
@ -0,0 +1,40 @@
|
||||
#
|
||||
# BSD LICENSE
|
||||
#
|
||||
# Copyright (c) Intel Corporation.
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions
|
||||
# are met:
|
||||
#
|
||||
# * Redistributions of source code must retain the above copyright
|
||||
# notice, this list of conditions and the following disclaimer.
|
||||
# * Redistributions in binary form must reproduce the above copyright
|
||||
# notice, this list of conditions and the following disclaimer in
|
||||
# the documentation and/or other materials provided with the
|
||||
# distribution.
|
||||
# * Neither the name of Intel Corporation nor the names of its
|
||||
# contributors may be used to endorse or promote products derived
|
||||
# from this software without specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#
|
||||
|
||||
SPDK_ROOT_DIR := $(abspath $(CURDIR)/../..)
|
||||
|
||||
CFLAGS += $(DPDK_INC)
|
||||
LIBNAME = event
|
||||
C_SRCS = app.c dpdk_init.c reactor.c subsystem.c
|
||||
|
||||
include $(SPDK_ROOT_DIR)/mk/spdk.lib.mk
|
478
lib/event/app.c
Normal file
478
lib/event/app.c
Normal file
@ -0,0 +1,478 @@
|
||||
/*-
|
||||
* BSD LICENSE
|
||||
*
|
||||
* Copyright (c) Intel Corporation.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in
|
||||
* the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
* * Neither the name of Intel Corporation nor the names of its
|
||||
* contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "spdk/event.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/resource.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <fcntl.h>
|
||||
#include <signal.h>
|
||||
|
||||
#include <rte_debug.h>
|
||||
|
||||
#include "spdk/log.h"
|
||||
#include "spdk/conf.h"
|
||||
#include "spdk/trace.h"
|
||||
|
||||
#include "reactor.h"
|
||||
#include "subsystem.h"
|
||||
|
||||
/* Add enough here to append ".pid" plus 2 digit instance ID */
|
||||
#define SPDK_APP_PIDFILE_MAX_LENGTH 40
|
||||
#define SPDK_APP_PIDFILE_PREFIX "/var/run"
|
||||
|
||||
struct spdk_app {
|
||||
struct spdk_conf *config;
|
||||
char pidfile[SPDK_APP_PIDFILE_MAX_LENGTH];
|
||||
int instance_id;
|
||||
spdk_app_shutdown_cb shutdown_cb;
|
||||
int rc;
|
||||
};
|
||||
|
||||
static struct spdk_app g_spdk_app;
|
||||
static spdk_event_t g_shutdown_event = NULL;
|
||||
|
||||
static int spdk_app_write_pidfile(void);
|
||||
static void spdk_app_remove_pidfile(void);
|
||||
|
||||
int
|
||||
spdk_app_get_instance_id(void)
|
||||
{
|
||||
return g_spdk_app.instance_id;
|
||||
}
|
||||
|
||||
/* Global section */
|
||||
#define GLOBAL_CONFIG_TMPL \
|
||||
"# Configuration file\n" \
|
||||
"#\n" \
|
||||
"# Please write all parameters using ASCII.\n" \
|
||||
"# The parameter must be quoted if it includes whitespace.\n" \
|
||||
"#\n" \
|
||||
"# Configuration syntax:\n" \
|
||||
"# Spaces at head of line are deleted, other spaces are as separator\n" \
|
||||
"# Lines starting with '#' are comments and not evaluated.\n" \
|
||||
"# Lines ending with '\\' are concatenated with the next line.\n" \
|
||||
"# Bracketed keys are section keys grouping the following value keys.\n" \
|
||||
"# Number of section key is used as a tag number.\n" \
|
||||
"# Ex. [TargetNode1] = TargetNode section key with tag number 1\n" \
|
||||
"[Global]\n" \
|
||||
" Comment \"Global section\"\n" \
|
||||
"\n" \
|
||||
" # Users can restrict work items to only run on certain cores by\n" \
|
||||
" # specifying a ReactorMask. Default is to allow work items to run\n" \
|
||||
" # on all cores. Core 0 must be set in the mask if one is specified.\n" \
|
||||
" # Default: 0xFFFF (cores 0-15)\n" \
|
||||
" ReactorMask \"0x%" PRIX64 "\"\n" \
|
||||
"\n" \
|
||||
" # Tracepoint group mask for spdk trace buffers\n" \
|
||||
" # Default: 0x0 (all tracepoint groups disabled)\n" \
|
||||
" # Set to 0xFFFFFFFFFFFFFFFF to enable all tracepoint groups.\n" \
|
||||
" TpointGroupMask \"0x%" PRIX64 "\"\n" \
|
||||
"\n" \
|
||||
" # syslog facility\n" \
|
||||
" LogFacility \"%s\"\n" \
|
||||
"\n"
|
||||
|
||||
static void
|
||||
spdk_app_config_dump_global_section(FILE *fp)
|
||||
{
|
||||
if (NULL == fp)
|
||||
return;
|
||||
|
||||
/* FIXME - lookup log facility and put it in place of "local7" below */
|
||||
fprintf(fp, GLOBAL_CONFIG_TMPL,
|
||||
spdk_app_get_core_mask(), spdk_trace_get_tpoint_group_mask(),
|
||||
"local7");
|
||||
}
|
||||
|
||||
int
|
||||
spdk_app_get_running_config(char **config_str, char *name)
|
||||
{
|
||||
FILE *fp = NULL;
|
||||
int fd = -1;
|
||||
long length = 0, ret = 0;
|
||||
char vbuf[BUFSIZ];
|
||||
char config_template[64];
|
||||
|
||||
snprintf(config_template, sizeof(config_template), "/tmp/%s.XXXXXX", name);
|
||||
/* Create temporary file to hold config */
|
||||
fd = mkstemp(config_template);
|
||||
if (fd == -1) {
|
||||
fprintf(stderr, "mkstemp failed\n");
|
||||
return -1;
|
||||
}
|
||||
fp = fdopen(fd, "wb+");
|
||||
if (NULL == fp) {
|
||||
fprintf(stderr, "error opening tmpfile fd = %d\n", fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Buffered IO */
|
||||
setvbuf(fp, vbuf, _IOFBF, BUFSIZ);
|
||||
|
||||
spdk_app_config_dump_global_section(fp);
|
||||
spdk_subsystem_config(fp);
|
||||
|
||||
length = ftell(fp);
|
||||
|
||||
*config_str = malloc(length + 1);
|
||||
if (!*config_str) {
|
||||
perror("config_str");
|
||||
fclose(fp);
|
||||
return -1;
|
||||
}
|
||||
fseek(fp, 0, SEEK_SET);
|
||||
ret = fread(*config_str, sizeof(char), length, fp);
|
||||
if (ret < length)
|
||||
fprintf(stderr, "%s: warning - short read\n", __func__);
|
||||
fclose(fp);
|
||||
(*config_str)[length] = '\0';
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const char *
|
||||
spdk_get_log_facility(struct spdk_conf *config)
|
||||
{
|
||||
struct spdk_conf_section *sp;
|
||||
const char *logfacility;
|
||||
|
||||
sp = spdk_conf_find_section(config, "Global");
|
||||
if (sp == NULL) {
|
||||
return SPDK_APP_DEFAULT_LOG_FACILITY;
|
||||
}
|
||||
|
||||
logfacility = spdk_conf_section_get_val(sp, "LogFacility");
|
||||
if (logfacility == NULL) {
|
||||
return SPDK_APP_DEFAULT_LOG_FACILITY;
|
||||
}
|
||||
|
||||
return logfacility;
|
||||
}
|
||||
|
||||
static void
|
||||
__shutdown_signal(int signo)
|
||||
{
|
||||
/*
|
||||
* Call pre-allocated shutdown event. Note that it is not
|
||||
* safe to allocate the event within the signal handlers
|
||||
* context, since that context is not a DPDK thread so
|
||||
* buffer allocation is not permitted.
|
||||
*/
|
||||
if (g_shutdown_event != NULL) {
|
||||
spdk_event_call(g_shutdown_event);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
__shutdown_event_cb(spdk_event_t event)
|
||||
{
|
||||
g_spdk_app.shutdown_cb();
|
||||
}
|
||||
|
||||
void
|
||||
spdk_app_opts_init(struct spdk_app_opts *opts)
|
||||
{
|
||||
if (!opts)
|
||||
return;
|
||||
|
||||
memset(opts, 0, sizeof(*opts));
|
||||
|
||||
opts->enable_coredump = true;
|
||||
opts->instance_id = -1;
|
||||
opts->dpdk_mem_size = -1;
|
||||
opts->dpdk_master_core = SPDK_APP_DPDK_DEFAULT_MASTER_CORE;
|
||||
opts->dpdk_mem_channel = SPDK_APP_DPDK_DEFAULT_MEM_CHANNEL;
|
||||
opts->reactor_mask = SPDK_APP_DPDK_DEFAULT_CORE_MASK;
|
||||
}
|
||||
|
||||
void
|
||||
spdk_app_init(struct spdk_app_opts *opts)
|
||||
{
|
||||
struct spdk_conf *config;
|
||||
struct spdk_conf_section *sp;
|
||||
struct sigaction sigact;
|
||||
sigset_t signew;
|
||||
char shm_name[64];
|
||||
int rc;
|
||||
uint64_t tpoint_group_mask;
|
||||
char *end;
|
||||
|
||||
if (opts->enable_coredump) {
|
||||
struct rlimit core_limits;
|
||||
|
||||
core_limits.rlim_cur = core_limits.rlim_max = RLIM_INFINITY;
|
||||
setrlimit(RLIMIT_CORE, &core_limits);
|
||||
}
|
||||
|
||||
config = spdk_conf_allocate();
|
||||
RTE_VERIFY(config != NULL);
|
||||
if (opts->config_file) {
|
||||
rc = spdk_conf_read(config, opts->config_file);
|
||||
if (rc != 0) {
|
||||
fprintf(stderr, "Could not read config file %s\n", opts->config_file);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
if (config->section == NULL) {
|
||||
fprintf(stderr, "Invalid config file %s\n", opts->config_file);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
spdk_conf_set_as_default(config);
|
||||
|
||||
if (opts->instance_id == -1) {
|
||||
sp = spdk_conf_find_section(config, "Global");
|
||||
if (sp != NULL) {
|
||||
opts->instance_id = spdk_conf_section_get_intval(sp, "InstanceID");
|
||||
}
|
||||
}
|
||||
|
||||
if (opts->instance_id < 0) {
|
||||
opts->instance_id = 0;
|
||||
}
|
||||
|
||||
memset(&g_spdk_app, 0, sizeof(g_spdk_app));
|
||||
g_spdk_app.config = config;
|
||||
g_spdk_app.instance_id = opts->instance_id;
|
||||
g_spdk_app.shutdown_cb = opts->shutdown_cb;
|
||||
snprintf(g_spdk_app.pidfile, sizeof(g_spdk_app.pidfile), "%s/%s.pid.%d",
|
||||
SPDK_APP_PIDFILE_PREFIX, opts->name, opts->instance_id);
|
||||
spdk_app_write_pidfile();
|
||||
|
||||
/* open log files */
|
||||
if (opts->log_facility == NULL) {
|
||||
opts->log_facility = spdk_get_log_facility(g_spdk_app.config);
|
||||
if (opts->log_facility == NULL) {
|
||||
fprintf(stderr, "NULL logfacility\n");
|
||||
spdk_conf_free(g_spdk_app.config);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
rc = spdk_set_log_facility(opts->log_facility);
|
||||
if (rc < 0) {
|
||||
fprintf(stderr, "log facility error\n");
|
||||
spdk_conf_free(g_spdk_app.config);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
rc = spdk_set_log_priority(SPDK_APP_DEFAULT_LOG_PRIORITY);
|
||||
if (rc < 0) {
|
||||
fprintf(stderr, "log priority error\n");
|
||||
spdk_conf_free(g_spdk_app.config);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
spdk_open_log();
|
||||
|
||||
if (opts->reactor_mask == NULL) {
|
||||
sp = spdk_conf_find_section(g_spdk_app.config, "Global");
|
||||
if (sp != NULL) {
|
||||
if (spdk_conf_section_get_val(sp, "WorkerMask")) {
|
||||
fprintf(stderr, "WorkerMask not valid key name."
|
||||
" Use ReactorMask instead.\n");
|
||||
spdk_conf_free(g_spdk_app.config);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
opts->reactor_mask = spdk_conf_section_get_val(sp, "ReactorMask");
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* If mask not specified on command line or in configuration file,
|
||||
* reactor_mask will be NULL which will enable all cores to run
|
||||
* reactors.
|
||||
*/
|
||||
if (spdk_reactor_subsystem_init(opts->reactor_mask)) {
|
||||
fprintf(stderr, "Invalid reactor mask.\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
/* setup signal handler thread */
|
||||
pthread_sigmask(SIG_SETMASK, NULL, &signew);
|
||||
|
||||
memset(&sigact, 0, sizeof(sigact));
|
||||
sigact.sa_handler = SIG_IGN;
|
||||
sigemptyset(&sigact.sa_mask);
|
||||
rc = sigaction(SIGPIPE, &sigact, NULL);
|
||||
if (rc < 0) {
|
||||
SPDK_ERRLOG("sigaction(SIGPIPE) failed\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if (opts->shutdown_cb != NULL) {
|
||||
g_shutdown_event = spdk_event_allocate(rte_lcore_id(), __shutdown_event_cb,
|
||||
NULL, NULL, NULL);
|
||||
|
||||
sigact.sa_handler = __shutdown_signal;
|
||||
sigemptyset(&sigact.sa_mask);
|
||||
rc = sigaction(SIGINT, &sigact, NULL);
|
||||
if (rc < 0) {
|
||||
SPDK_ERRLOG("sigaction(SIGINT) failed\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
sigaddset(&signew, SIGINT);
|
||||
|
||||
sigact.sa_handler = __shutdown_signal;
|
||||
sigemptyset(&sigact.sa_mask);
|
||||
rc = sigaction(SIGTERM, &sigact, NULL);
|
||||
if (rc < 0) {
|
||||
SPDK_ERRLOG("sigaction(SIGTERM) failed\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
sigaddset(&signew, SIGTERM);
|
||||
}
|
||||
|
||||
if (opts->usr1_handler != NULL) {
|
||||
sigact.sa_handler = opts->usr1_handler;
|
||||
sigemptyset(&sigact.sa_mask);
|
||||
rc = sigaction(SIGUSR1, &sigact, NULL);
|
||||
if (rc < 0) {
|
||||
SPDK_ERRLOG("sigaction(SIGUSR1) failed\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
sigaddset(&signew, SIGUSR1);
|
||||
}
|
||||
|
||||
sigaddset(&signew, SIGQUIT);
|
||||
sigaddset(&signew, SIGHUP);
|
||||
pthread_sigmask(SIG_SETMASK, &signew, NULL);
|
||||
|
||||
snprintf(shm_name, sizeof(shm_name), "/%s_trace.%d", opts->name, opts->instance_id);
|
||||
spdk_trace_init(shm_name);
|
||||
|
||||
if (opts->tpoint_group_mask == NULL) {
|
||||
sp = spdk_conf_find_section(g_spdk_app.config, "Global");
|
||||
if (sp != NULL) {
|
||||
opts->tpoint_group_mask = spdk_conf_section_get_val(sp, "TpointGroupMask");
|
||||
}
|
||||
}
|
||||
|
||||
if (opts->tpoint_group_mask != NULL) {
|
||||
errno = 0;
|
||||
tpoint_group_mask = strtoull(opts->tpoint_group_mask, &end, 16);
|
||||
if (*end != '\0' || errno) {
|
||||
SPDK_ERRLOG("invalid tpoint mask %s\n", opts->tpoint_group_mask);
|
||||
} else {
|
||||
spdk_trace_set_tpoint_group_mask(tpoint_group_mask);
|
||||
}
|
||||
}
|
||||
|
||||
rc = spdk_subsystem_init();
|
||||
if (rc < 0) {
|
||||
SPDK_ERRLOG("spdk_subsystem_init() failed\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
spdk_app_fini(void)
|
||||
{
|
||||
spdk_subsystem_fini();
|
||||
spdk_trace_cleanup();
|
||||
spdk_app_remove_pidfile();
|
||||
spdk_conf_free(g_spdk_app.config);
|
||||
spdk_close_log();
|
||||
}
|
||||
|
||||
int
|
||||
spdk_app_start(spdk_event_fn start_fn, void *arg1, void *arg2)
|
||||
{
|
||||
spdk_event_t event;
|
||||
|
||||
g_spdk_app.rc = 0;
|
||||
|
||||
event = spdk_event_allocate(rte_get_master_lcore(), start_fn,
|
||||
arg1, arg2, NULL);
|
||||
/* Queues up the event, but can't run it until the reactors start */
|
||||
spdk_event_call(event);
|
||||
|
||||
/* This blocks until spdk_app_stop is called */
|
||||
spdk_reactor_subsystem_start();
|
||||
|
||||
return g_spdk_app.rc;
|
||||
}
|
||||
|
||||
void
|
||||
spdk_app_stop(int rc)
|
||||
{
|
||||
spdk_reactor_subsystem_stop();
|
||||
g_spdk_app.rc = rc;
|
||||
}
|
||||
|
||||
static int
|
||||
spdk_app_write_pidfile(void)
|
||||
{
|
||||
FILE *fp;
|
||||
pid_t pid;
|
||||
struct flock lock = {
|
||||
.l_type = F_WRLCK,
|
||||
.l_whence = SEEK_SET,
|
||||
.l_start = 0,
|
||||
.l_len = 0,
|
||||
};
|
||||
|
||||
fp = fopen(g_spdk_app.pidfile, "w");
|
||||
if (fp == NULL) {
|
||||
SPDK_ERRLOG("pidfile open error %d\n", errno);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (fcntl(fileno(fp), F_SETLK, &lock) != 0) {
|
||||
fprintf(stderr, "Cannot create lock on file %s, probably you"
|
||||
" should use different instance id\n", g_spdk_app.pidfile);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
pid = getpid();
|
||||
fprintf(fp, "%d\n", (int)pid);
|
||||
fclose(fp);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
spdk_app_remove_pidfile(void)
|
||||
{
|
||||
int rc;
|
||||
|
||||
rc = remove(g_spdk_app.pidfile);
|
||||
if (rc != 0) {
|
||||
SPDK_ERRLOG("pidfile remove error %d\n", errno);
|
||||
/* ignore error */
|
||||
}
|
||||
}
|
194
lib/event/dpdk_init.c
Normal file
194
lib/event/dpdk_init.c
Normal file
@ -0,0 +1,194 @@
|
||||
/*-
|
||||
* BSD LICENSE
|
||||
*
|
||||
* Copyright (c) Intel Corporation.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in
|
||||
* the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
* * Neither the name of Intel Corporation nor the names of its
|
||||
* contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "spdk/event.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <rte_debug.h>
|
||||
#include <rte_config.h>
|
||||
#include <rte_per_lcore.h>
|
||||
#include <rte_eal.h>
|
||||
#include <rte_launch.h>
|
||||
#include <rte_common.h>
|
||||
|
||||
#include "spdk/string.h"
|
||||
|
||||
enum dpdk_eal_args {
|
||||
EAL_PROGNAME_ARG = 0,
|
||||
EAL_COREMASK_ARG,
|
||||
EAL_MEMCHAN_ARG,
|
||||
EAL_MEMSIZE_ARG,
|
||||
EAL_MASTER_CORE_ARG,
|
||||
EAL_FILE_PREFIX_ARG,
|
||||
EAL_ARG_COUNT
|
||||
};
|
||||
|
||||
/* g_arg_strings contains the original pointers allocated via
|
||||
* spdk_sprintf_alloc(). These pointers are copied to g_ealargs
|
||||
* for passing to DPDK rte_eal_init(). Since DPDK may modify the
|
||||
* pointer values, we use g_arg_strings() to free the strings after
|
||||
* rte_eal_init() completes.
|
||||
*/
|
||||
static char *g_arg_strings[EAL_ARG_COUNT];
|
||||
static char *g_ealargs[EAL_ARG_COUNT];
|
||||
|
||||
static void
|
||||
spdk_free_ealargs(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < EAL_ARG_COUNT; i++)
|
||||
free(g_arg_strings[i]);
|
||||
}
|
||||
|
||||
static unsigned long long
|
||||
spdk_get_eal_coremask(const char *coremask)
|
||||
{
|
||||
unsigned long long core_mask, max_coremask = 0;
|
||||
int num_cores_online;
|
||||
|
||||
num_cores_online = sysconf(_SC_NPROCESSORS_ONLN);
|
||||
if (num_cores_online > 0) {
|
||||
if (num_cores_online > RTE_MAX_LCORE) {
|
||||
num_cores_online = RTE_MAX_LCORE;
|
||||
}
|
||||
if (num_cores_online >= 64) {
|
||||
max_coremask = ~0ULL;
|
||||
} else {
|
||||
max_coremask = (1ULL << num_cores_online) - 1;
|
||||
}
|
||||
}
|
||||
|
||||
core_mask = strtoull(coremask, NULL, 16);
|
||||
core_mask &= max_coremask;
|
||||
|
||||
return core_mask;
|
||||
}
|
||||
|
||||
static void
|
||||
spdk_build_eal_cmdline(struct spdk_app_opts *opts)
|
||||
{
|
||||
unsigned long long core_mask;
|
||||
|
||||
/* set the program name */
|
||||
g_arg_strings[EAL_PROGNAME_ARG] = spdk_sprintf_alloc("%s", opts->name);
|
||||
if (g_arg_strings[EAL_PROGNAME_ARG] == NULL) {
|
||||
rte_exit(EXIT_FAILURE, "g_arg_strings spdk_sprintf_alloc");
|
||||
}
|
||||
|
||||
/*set the coremask */
|
||||
core_mask = spdk_get_eal_coremask(opts->reactor_mask);
|
||||
g_arg_strings[EAL_COREMASK_ARG] = spdk_sprintf_alloc("-c %llx", core_mask);
|
||||
if (g_arg_strings[EAL_COREMASK_ARG] == NULL) {
|
||||
spdk_free_ealargs();
|
||||
rte_exit(EXIT_FAILURE, "g_arg_strings spdk_sprintf_alloc");
|
||||
}
|
||||
|
||||
/* set the memory channel number */
|
||||
g_arg_strings[EAL_MEMCHAN_ARG] = spdk_sprintf_alloc("-n %d", opts->dpdk_mem_channel);
|
||||
if (g_arg_strings[EAL_MEMCHAN_ARG] == NULL) {
|
||||
spdk_free_ealargs();
|
||||
rte_exit(EXIT_FAILURE, "g_arg_strings spdk_sprintf_alloc");
|
||||
}
|
||||
|
||||
/* set the memory size */
|
||||
if (opts->dpdk_mem_size == -1)
|
||||
opts->dpdk_mem_size = SPDK_APP_DPDK_DEFAULT_MEM_SIZE;
|
||||
g_arg_strings[EAL_MEMSIZE_ARG] = spdk_sprintf_alloc("-m %d", opts->dpdk_mem_size);
|
||||
if (g_arg_strings[EAL_MEMSIZE_ARG] == NULL) {
|
||||
spdk_free_ealargs();
|
||||
rte_exit(EXIT_FAILURE, "g_arg_strings spdk_sprintf_alloc");
|
||||
}
|
||||
|
||||
/* set the master core */
|
||||
g_arg_strings[EAL_MASTER_CORE_ARG] = spdk_sprintf_alloc("--master-lcore=%d",
|
||||
opts->dpdk_master_core);
|
||||
if (g_arg_strings[EAL_MASTER_CORE_ARG] == NULL) {
|
||||
spdk_free_ealargs();
|
||||
rte_exit(EXIT_FAILURE, "g_arg_strings spdk_sprintf_alloc");
|
||||
}
|
||||
|
||||
#ifdef __linux__
|
||||
/* set the hugepage file prefix */
|
||||
g_arg_strings[EAL_FILE_PREFIX_ARG] = spdk_sprintf_alloc("--file-prefix=rte%d",
|
||||
opts->instance_id);
|
||||
#else
|
||||
/* --file-prefix is not required on FreeBSD */
|
||||
g_arg_strings[EAL_FILE_PREFIX_ARG] = strdup("");
|
||||
#endif
|
||||
if (g_arg_strings[EAL_FILE_PREFIX_ARG] == NULL) {
|
||||
spdk_free_ealargs();
|
||||
rte_exit(EXIT_FAILURE, "ealargs spdk_sprintf_alloc");
|
||||
}
|
||||
|
||||
memcpy(g_ealargs, g_arg_strings, sizeof(g_arg_strings));
|
||||
}
|
||||
|
||||
void
|
||||
spdk_init_dpdk(struct spdk_app_opts *opts)
|
||||
{
|
||||
int i, rc;
|
||||
static bool g_dpdk_initialized = false;
|
||||
|
||||
/* to make sure DPDK is only initialized once */
|
||||
if (g_dpdk_initialized)
|
||||
rte_exit(EXIT_FAILURE, "DPDK is already initialized\n");
|
||||
|
||||
spdk_build_eal_cmdline(opts);
|
||||
|
||||
printf("Starting Intel(R) DPDK initialization ... \n");
|
||||
printf("[ DPDK EAL parameters: ");
|
||||
for (i = 0; i < EAL_ARG_COUNT; i++) {
|
||||
printf("%s ", g_ealargs[i]);
|
||||
}
|
||||
printf("]\n");
|
||||
|
||||
fflush(stdout);
|
||||
rc = rte_eal_init(EAL_ARG_COUNT, g_ealargs);
|
||||
spdk_free_ealargs();
|
||||
|
||||
if (rc < 0)
|
||||
rte_exit(EXIT_FAILURE, "Invalid EAL arguments for DPDK\n");
|
||||
|
||||
g_dpdk_initialized = true;
|
||||
|
||||
printf("done.\n");
|
||||
}
|
577
lib/event/reactor.c
Normal file
577
lib/event/reactor.c
Normal file
@ -0,0 +1,577 @@
|
||||
/*-
|
||||
* BSD LICENSE
|
||||
*
|
||||
* Copyright (c) Intel Corporation.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in
|
||||
* the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
* * Neither the name of Intel Corporation nor the names of its
|
||||
* contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "spdk/event.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#ifdef __linux__
|
||||
#include <sys/prctl.h>
|
||||
#endif
|
||||
|
||||
#ifdef __FreeBSD__
|
||||
#include <pthread_np.h>
|
||||
#endif
|
||||
|
||||
#include <rte_config.h>
|
||||
#include <rte_debug.h>
|
||||
#include <rte_mempool.h>
|
||||
#include <rte_ring.h>
|
||||
#include <rte_timer.h>
|
||||
|
||||
#include "reactor.h"
|
||||
|
||||
#include "spdk/log.h"
|
||||
|
||||
enum spdk_reactor_state {
|
||||
SPDK_REACTOR_STATE_INVALID = 0,
|
||||
SPDK_REACTOR_STATE_INITIALIZED = 1,
|
||||
SPDK_REACTOR_STATE_RUNNING = 2,
|
||||
SPDK_REACTOR_STATE_EXITING = 3,
|
||||
SPDK_REACTOR_STATE_SHUTDOWN = 4,
|
||||
};
|
||||
|
||||
struct spdk_reactor {
|
||||
/* Logical core number for this reactor. */
|
||||
uint32_t lcore;
|
||||
|
||||
/*
|
||||
* Contains pollers actively running on this reactor. Pollers
|
||||
* are run round-robin. The reactor takes one poller from the head
|
||||
* of the ring, executes it, then puts it back at the tail of
|
||||
* the ring.
|
||||
*/
|
||||
struct rte_ring *active_pollers;
|
||||
|
||||
struct rte_ring *events;
|
||||
};
|
||||
|
||||
static struct spdk_reactor g_reactors[RTE_MAX_LCORE];
|
||||
static uint64_t g_reactor_mask = 0;
|
||||
static int g_reactor_count = 0;
|
||||
|
||||
static enum spdk_reactor_state g_reactor_state = SPDK_REACTOR_STATE_INVALID;
|
||||
|
||||
static void spdk_reactor_construct(struct spdk_reactor *w, uint32_t lcore);
|
||||
|
||||
struct rte_mempool *g_spdk_event_mempool;
|
||||
|
||||
/** \file
|
||||
|
||||
*/
|
||||
|
||||
static struct spdk_reactor *
|
||||
spdk_reactor_get(uint32_t lcore)
|
||||
{
|
||||
struct spdk_reactor *reactor;
|
||||
reactor = &g_reactors[lcore];
|
||||
return reactor;
|
||||
}
|
||||
|
||||
spdk_event_t
|
||||
spdk_event_allocate(uint32_t lcore, spdk_event_fn fn, void *arg1, void *arg2,
|
||||
spdk_event_t next)
|
||||
{
|
||||
struct spdk_event *event = NULL;
|
||||
int rc;
|
||||
|
||||
rc = rte_mempool_get(g_spdk_event_mempool, (void **)&event);
|
||||
RTE_VERIFY((rc == 0) && (event != NULL));
|
||||
|
||||
event->lcore = lcore;
|
||||
event->fn = fn;
|
||||
event->arg1 = arg1;
|
||||
event->arg2 = arg2;
|
||||
event->next = next;
|
||||
|
||||
return event;
|
||||
}
|
||||
|
||||
static void
|
||||
spdk_event_free(struct spdk_event *event)
|
||||
{
|
||||
rte_mempool_put(g_spdk_event_mempool, (void *)event);
|
||||
}
|
||||
|
||||
void
|
||||
spdk_event_call(spdk_event_t event)
|
||||
{
|
||||
int rc;
|
||||
struct spdk_reactor *reactor;
|
||||
|
||||
reactor = spdk_reactor_get(event->lcore);
|
||||
|
||||
RTE_VERIFY(reactor->events != NULL);
|
||||
rc = rte_ring_enqueue(reactor->events, event);
|
||||
RTE_VERIFY(rc == 0);
|
||||
}
|
||||
|
||||
static uint32_t
|
||||
spdk_event_queue_count(uint32_t lcore)
|
||||
{
|
||||
struct spdk_reactor *reactor;
|
||||
|
||||
reactor = spdk_reactor_get(lcore);
|
||||
|
||||
if (reactor->events == NULL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return rte_ring_count(reactor->events);
|
||||
}
|
||||
|
||||
static void
|
||||
spdk_event_queue_run_single(uint32_t lcore)
|
||||
{
|
||||
struct spdk_event *event = NULL;
|
||||
struct spdk_reactor *reactor;
|
||||
int rc;
|
||||
|
||||
reactor = spdk_reactor_get(lcore);
|
||||
|
||||
RTE_VERIFY(reactor->events != NULL);
|
||||
rc = rte_ring_dequeue(reactor->events, (void **)&event);
|
||||
|
||||
if ((rc != 0) || event == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
event->fn(event);
|
||||
spdk_event_free(event);
|
||||
}
|
||||
|
||||
static void
|
||||
spdk_event_queue_run(uint32_t lcore, uint32_t count)
|
||||
{
|
||||
while (count--) {
|
||||
spdk_event_queue_run_single(lcore);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
spdk_event_queue_run_all(uint32_t lcore)
|
||||
{
|
||||
uint32_t count;
|
||||
|
||||
count = spdk_event_queue_count(lcore);
|
||||
spdk_event_queue_run(lcore, count);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
\brief Set current reactor thread name to "reactor <cpu #>".
|
||||
|
||||
This makes the reactor threads distinguishable in top and gdb.
|
||||
|
||||
*/
|
||||
static void set_reactor_thread_name(void)
|
||||
{
|
||||
char thread_name[16];
|
||||
|
||||
snprintf(thread_name, sizeof(thread_name), "reactor %d",
|
||||
rte_lcore_id());
|
||||
|
||||
#if defined(__linux__)
|
||||
prctl(PR_SET_NAME, thread_name, 0, 0, 0);
|
||||
#elif defined(__FreeBSD__)
|
||||
pthread_set_name_np(pthread_self(), thread_name);
|
||||
#else
|
||||
#error missing platform support for thread name
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
\brief This is the main function of the reactor thread.
|
||||
|
||||
\code
|
||||
|
||||
while (1)
|
||||
if (new work items to be scheduled)
|
||||
dequeue work item from new work item ring
|
||||
enqueue work item to active work item ring
|
||||
else if (active work item count > 0)
|
||||
dequeue work item from active work item ring
|
||||
invoke work item function pointer
|
||||
if (work item state == RUNNING)
|
||||
enqueue work item to active work item ring
|
||||
else if (application state != RUNNING)
|
||||
# exit the reactor loop
|
||||
break
|
||||
else
|
||||
sleep for 100ms
|
||||
|
||||
\endcode
|
||||
|
||||
Note that new work items are posted to a separate ring so that the
|
||||
active work item ring can be kept single producer/single consumer and
|
||||
only be touched by reactor itself. This avoids atomic operations
|
||||
on the active work item ring which would hurt performance.
|
||||
|
||||
*/
|
||||
static int
|
||||
_spdk_reactor_run(void *arg)
|
||||
{
|
||||
struct spdk_reactor *reactor = arg;
|
||||
struct spdk_poller *poller = NULL;
|
||||
int rc;
|
||||
|
||||
set_reactor_thread_name();
|
||||
SPDK_NOTICELOG("waiting for work item to arrive...\n");
|
||||
|
||||
while (1) {
|
||||
spdk_event_queue_run_all(rte_lcore_id());
|
||||
|
||||
rte_timer_manage();
|
||||
|
||||
if (rte_ring_dequeue(reactor->active_pollers, (void **)&poller) == 0) {
|
||||
poller->fn(poller->arg);
|
||||
rc = rte_ring_enqueue(reactor->active_pollers,
|
||||
(void *)poller);
|
||||
if (rc != 0) {
|
||||
SPDK_ERRLOG("poller could not be enqueued\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
if (g_reactor_state != SPDK_REACTOR_STATE_RUNNING) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
spdk_reactor_construct(struct spdk_reactor *reactor, uint32_t lcore)
|
||||
{
|
||||
char ring_name[64];
|
||||
|
||||
reactor->lcore = lcore;
|
||||
|
||||
snprintf(ring_name, sizeof(ring_name), "spdk_active_pollers_%d", lcore);
|
||||
reactor->active_pollers =
|
||||
rte_ring_create(ring_name, SPDK_POLLER_RING_SIZE, rte_lcore_to_socket_id(lcore),
|
||||
RING_F_SP_ENQ | RING_F_SC_DEQ);
|
||||
|
||||
snprintf(ring_name, sizeof(ring_name) - 1, "spdk_event_queue_%u", lcore);
|
||||
reactor->events =
|
||||
rte_ring_create(ring_name, 65536, rte_lcore_to_socket_id(lcore), RING_F_SC_DEQ);
|
||||
RTE_VERIFY(reactor->events != NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
spdk_reactor_start(struct spdk_reactor *reactor)
|
||||
{
|
||||
if (reactor->lcore != rte_get_master_lcore()) {
|
||||
switch (rte_eal_get_lcore_state(reactor->lcore)) {
|
||||
case FINISHED:
|
||||
rte_eal_wait_lcore(reactor->lcore);
|
||||
/* drop through */
|
||||
case WAIT:
|
||||
rte_eal_remote_launch(_spdk_reactor_run, (void *)reactor, reactor->lcore);
|
||||
break;
|
||||
case RUNNING:
|
||||
printf("Something already running on lcore %d\n", reactor->lcore);
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
_spdk_reactor_run(reactor);
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
spdk_app_get_core_count(void)
|
||||
{
|
||||
return g_reactor_count;
|
||||
}
|
||||
|
||||
int
|
||||
spdk_app_parse_core_mask(const char *mask, uint64_t *cpumask)
|
||||
{
|
||||
unsigned int i;
|
||||
char *end;
|
||||
|
||||
if (mask == NULL || cpumask == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
errno = 0;
|
||||
*cpumask = strtoull(mask, &end, 16);
|
||||
if (*end != '\0' || errno) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (i = 0; i < RTE_MAX_LCORE && i < 64; i++) {
|
||||
if ((*cpumask & (1ULL << i)) && !rte_lcore_is_enabled(i)) {
|
||||
*cpumask &= ~(1ULL << i);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
spdk_reactor_parse_mask(const char *mask)
|
||||
{
|
||||
int i;
|
||||
int ret = 0;
|
||||
uint32_t master_core = rte_get_master_lcore();
|
||||
|
||||
if (g_reactor_state >= SPDK_REACTOR_STATE_INITIALIZED) {
|
||||
SPDK_ERRLOG("cannot set reactor mask after application has started\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
g_reactor_mask = 0;
|
||||
|
||||
if (mask == NULL) {
|
||||
/* No mask specified so use the same mask as DPDK. */
|
||||
RTE_LCORE_FOREACH(i) {
|
||||
g_reactor_mask |= (1ULL << i);
|
||||
}
|
||||
} else {
|
||||
ret = spdk_app_parse_core_mask(mask, &g_reactor_mask);
|
||||
if (ret != 0) {
|
||||
SPDK_ERRLOG("reactor mask %s specified on command line "
|
||||
"is invalid\n", mask);
|
||||
return ret;
|
||||
}
|
||||
if (!(g_reactor_mask & (1ULL << master_core))) {
|
||||
SPDK_ERRLOG("master_core %d must be set in core mask\n", master_core);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint64_t
|
||||
spdk_app_get_core_mask(void)
|
||||
{
|
||||
return g_reactor_mask;
|
||||
}
|
||||
|
||||
|
||||
static uint64_t
|
||||
spdk_reactor_get_socket_mask(void)
|
||||
{
|
||||
int i;
|
||||
uint32_t socket_id;
|
||||
uint64_t socket_info = 0;
|
||||
|
||||
RTE_LCORE_FOREACH(i) {
|
||||
if (((1ULL << i) & g_reactor_mask)) {
|
||||
socket_id = rte_lcore_to_socket_id(i);
|
||||
socket_info |= (1ULL << socket_id);
|
||||
}
|
||||
}
|
||||
|
||||
return socket_info;
|
||||
}
|
||||
|
||||
void
|
||||
spdk_reactor_subsystem_start(void)
|
||||
{
|
||||
struct spdk_reactor *reactor;
|
||||
uint32_t i;
|
||||
|
||||
RTE_VERIFY(rte_get_master_lcore() == rte_lcore_id());
|
||||
|
||||
g_reactor_state = SPDK_REACTOR_STATE_RUNNING;
|
||||
|
||||
RTE_LCORE_FOREACH_SLAVE(i) {
|
||||
if (((1ULL << i) & spdk_app_get_core_mask())) {
|
||||
reactor = spdk_reactor_get(i);
|
||||
spdk_reactor_start(reactor);
|
||||
}
|
||||
}
|
||||
|
||||
/* Start the master reactor */
|
||||
reactor = spdk_reactor_get(rte_get_master_lcore());
|
||||
spdk_reactor_start(reactor);
|
||||
|
||||
rte_eal_mp_wait_lcore();
|
||||
|
||||
g_reactor_state = SPDK_REACTOR_STATE_SHUTDOWN;
|
||||
}
|
||||
|
||||
void spdk_reactor_subsystem_stop(void)
|
||||
{
|
||||
g_reactor_state = SPDK_REACTOR_STATE_EXITING;
|
||||
}
|
||||
|
||||
int
|
||||
spdk_reactor_subsystem_init(const char *mask)
|
||||
{
|
||||
uint32_t i;
|
||||
int rc;
|
||||
struct spdk_reactor *reactor;
|
||||
|
||||
rc = spdk_reactor_parse_mask(mask);
|
||||
if (rc < 0) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
printf("Occupied cpu core mask is 0x%lx\n", spdk_app_get_core_mask());
|
||||
printf("Occupied cpu socket mask is 0x%lx\n", spdk_reactor_get_socket_mask());
|
||||
|
||||
RTE_LCORE_FOREACH(i) {
|
||||
if (((1ULL << i) & spdk_app_get_core_mask())) {
|
||||
reactor = spdk_reactor_get(i);
|
||||
spdk_reactor_construct(reactor, i);
|
||||
g_reactor_count++;
|
||||
}
|
||||
}
|
||||
|
||||
/* TODO: separate event mempools per socket */
|
||||
g_spdk_event_mempool = rte_mempool_create("spdk_event_mempool", 262144,
|
||||
sizeof(struct spdk_event), 128, 0,
|
||||
NULL, NULL, NULL, NULL,
|
||||
SOCKET_ID_ANY, 0);
|
||||
|
||||
if (g_spdk_event_mempool == NULL) {
|
||||
SPDK_ERRLOG("spdk_event_mempool allocation failed\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
g_reactor_state = SPDK_REACTOR_STATE_INITIALIZED;
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
int
|
||||
spdk_reactor_subsystem_fini(void)
|
||||
{
|
||||
/* TODO: free rings and mempool */
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
_spdk_event_add_poller(spdk_event_t event)
|
||||
{
|
||||
struct spdk_reactor *reactor = spdk_event_get_arg1(event);
|
||||
struct spdk_poller *poller = spdk_event_get_arg2(event);
|
||||
struct spdk_event *next = spdk_event_get_next(event);
|
||||
|
||||
poller->lcore = reactor->lcore;
|
||||
|
||||
rte_ring_enqueue(reactor->active_pollers, (void *)poller);
|
||||
|
||||
if (next) {
|
||||
spdk_event_call(next);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
spdk_poller_register(struct spdk_poller *poller,
|
||||
uint32_t lcore, spdk_event_t complete)
|
||||
{
|
||||
struct spdk_reactor *reactor;
|
||||
struct spdk_event *event;
|
||||
|
||||
reactor = spdk_reactor_get(lcore);
|
||||
event = spdk_event_allocate(lcore, _spdk_event_add_poller, reactor, poller, complete);
|
||||
spdk_event_call(event);
|
||||
}
|
||||
|
||||
static void
|
||||
_spdk_event_remove_poller(spdk_event_t event)
|
||||
{
|
||||
struct spdk_reactor *reactor = spdk_event_get_arg1(event);
|
||||
struct spdk_poller *poller = spdk_event_get_arg2(event);
|
||||
struct spdk_event *next = spdk_event_get_next(event);
|
||||
struct spdk_poller *tmp = NULL;
|
||||
uint32_t i;
|
||||
int rc;
|
||||
|
||||
/* Loop over all pollers, without breaking early, so that
|
||||
* the list of pollers stays in the same order. */
|
||||
for (i = 0; i < rte_ring_count(reactor->active_pollers); i++) {
|
||||
rte_ring_dequeue(reactor->active_pollers, (void **)&tmp);
|
||||
if (tmp != poller) {
|
||||
rc = rte_ring_enqueue(reactor->active_pollers, (void *)tmp);
|
||||
if (rc != 0) {
|
||||
SPDK_ERRLOG("poller could not be enqueued\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (next) {
|
||||
spdk_event_call(next);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
spdk_poller_unregister(struct spdk_poller *poller,
|
||||
struct spdk_event *complete)
|
||||
{
|
||||
struct spdk_reactor *reactor;
|
||||
struct spdk_event *event;
|
||||
|
||||
reactor = spdk_reactor_get(poller->lcore);
|
||||
event = spdk_event_allocate(poller->lcore, _spdk_event_remove_poller, reactor, poller, complete);
|
||||
|
||||
spdk_event_call(event);
|
||||
}
|
||||
|
||||
static void
|
||||
_spdk_poller_migrate(spdk_event_t event)
|
||||
{
|
||||
struct spdk_poller *poller = spdk_event_get_arg1(event);
|
||||
struct spdk_event *next = spdk_event_get_next(event);
|
||||
|
||||
/* Register the poller on the current lcore. This works
|
||||
* because we already set this event up so that it is called
|
||||
* on the new_lcore.
|
||||
*/
|
||||
spdk_poller_register(poller, rte_lcore_id(), next);
|
||||
}
|
||||
|
||||
void
|
||||
spdk_poller_migrate(struct spdk_poller *poller, int new_lcore,
|
||||
struct spdk_event *complete)
|
||||
{
|
||||
struct spdk_event *event;
|
||||
|
||||
RTE_VERIFY(spdk_app_get_core_mask() & (1ULL << new_lcore));
|
||||
RTE_VERIFY(poller != NULL);
|
||||
|
||||
event = spdk_event_allocate(new_lcore, _spdk_poller_migrate, poller, NULL, complete);
|
||||
|
||||
spdk_poller_unregister(poller, event);
|
||||
}
|
43
lib/event/reactor.h
Normal file
43
lib/event/reactor.h
Normal file
@ -0,0 +1,43 @@
|
||||
/*-
|
||||
* BSD LICENSE
|
||||
*
|
||||
* Copyright (c) Intel Corporation.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in
|
||||
* the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
* * Neither the name of Intel Corporation nor the names of its
|
||||
* contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef SPDK_REACTOR_H_
|
||||
#define SPDK_REACTOR_H_
|
||||
|
||||
int spdk_reactor_subsystem_init(const char *mask);
|
||||
int spdk_reactor_subsystem_fini(void);
|
||||
|
||||
void spdk_reactor_subsystem_start(void);
|
||||
void spdk_reactor_subsystem_stop(void);
|
||||
|
||||
#endif
|
172
lib/event/subsystem.c
Normal file
172
lib/event/subsystem.c
Normal file
@ -0,0 +1,172 @@
|
||||
/*-
|
||||
* BSD LICENSE
|
||||
*
|
||||
* Copyright (c) Intel Corporation.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in
|
||||
* the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
* * Neither the name of Intel Corporation nor the names of its
|
||||
* contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "spdk/event.h"
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "subsystem.h"
|
||||
|
||||
static TAILQ_HEAD(spdk_subsystem_list, spdk_subsystem) g_subsystems =
|
||||
TAILQ_HEAD_INITIALIZER(g_subsystems);
|
||||
static TAILQ_HEAD(subsystem_depend, spdk_subsystem_depend) g_depends =
|
||||
TAILQ_HEAD_INITIALIZER(g_depends);
|
||||
|
||||
void
|
||||
spdk_add_subsystem(struct spdk_subsystem *subsystem)
|
||||
{
|
||||
TAILQ_INSERT_TAIL(&g_subsystems, subsystem, tailq);
|
||||
}
|
||||
|
||||
void
|
||||
spdk_add_subsystem_depend(struct spdk_subsystem_depend *depend)
|
||||
{
|
||||
TAILQ_INSERT_TAIL(&g_depends, depend, tailq);
|
||||
}
|
||||
|
||||
static struct spdk_subsystem *
|
||||
spdk_subsystem_find(struct spdk_subsystem_list *list, const char *name)
|
||||
{
|
||||
struct spdk_subsystem *iter;
|
||||
|
||||
TAILQ_FOREACH(iter, list, tailq) {
|
||||
if (strcmp(name, iter->name) == 0) {
|
||||
return iter;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
subsystem_sort(void)
|
||||
{
|
||||
bool depends_on, depends_on_sorted;
|
||||
struct spdk_subsystem *subsystem, *subsystem_tmp;
|
||||
struct spdk_subsystem_depend *subsystem_dep;
|
||||
|
||||
struct spdk_subsystem_list subsystems_list = TAILQ_HEAD_INITIALIZER(subsystems_list);
|
||||
|
||||
while (!TAILQ_EMPTY(&g_subsystems)) {
|
||||
TAILQ_FOREACH_SAFE(subsystem, &g_subsystems, tailq, subsystem_tmp) {
|
||||
depends_on = false;
|
||||
TAILQ_FOREACH(subsystem_dep, &g_depends, tailq) {
|
||||
if (strcmp(subsystem->name, subsystem_dep->name) == 0) {
|
||||
depends_on = true;
|
||||
depends_on_sorted = !!spdk_subsystem_find(&subsystems_list, subsystem_dep->depends_on);
|
||||
if (depends_on_sorted)
|
||||
continue;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (depends_on == false) {
|
||||
TAILQ_REMOVE(&g_subsystems, subsystem, tailq);
|
||||
TAILQ_INSERT_TAIL(&subsystems_list, subsystem, tailq);
|
||||
} else {
|
||||
if (depends_on_sorted == true) {
|
||||
TAILQ_REMOVE(&g_subsystems, subsystem, tailq);
|
||||
TAILQ_INSERT_TAIL(&subsystems_list, subsystem, tailq);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TAILQ_FOREACH_SAFE(subsystem, &subsystems_list, tailq, subsystem_tmp) {
|
||||
TAILQ_REMOVE(&subsystems_list, subsystem, tailq);
|
||||
TAILQ_INSERT_TAIL(&g_subsystems, subsystem, tailq);
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
spdk_subsystem_init(void)
|
||||
{
|
||||
int rc = 0;
|
||||
struct spdk_subsystem *subsystem;
|
||||
struct spdk_subsystem_depend *dep;
|
||||
|
||||
/* Verify that all dependency name and depends_on subsystems are registered */
|
||||
TAILQ_FOREACH(dep, &g_depends, tailq) {
|
||||
if (!spdk_subsystem_find(&g_subsystems, dep->name)) {
|
||||
fprintf(stderr, "subsystem %s is missing\n", dep->name);
|
||||
return -1;
|
||||
}
|
||||
if (!spdk_subsystem_find(&g_subsystems, dep->depends_on)) {
|
||||
fprintf(stderr, "subsystem %s dependency %s is missing\n",
|
||||
dep->name, dep->depends_on);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
subsystem_sort();
|
||||
|
||||
TAILQ_FOREACH(subsystem, &g_subsystems, tailq) {
|
||||
if (subsystem->init) {
|
||||
rc = subsystem->init();
|
||||
if (rc)
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
int
|
||||
spdk_subsystem_fini(void)
|
||||
{
|
||||
int rc = 0;
|
||||
struct spdk_subsystem *cur;
|
||||
|
||||
cur = TAILQ_LAST(&g_subsystems, spdk_subsystem_list);
|
||||
do {
|
||||
if (cur->fini) {
|
||||
rc = cur->fini();
|
||||
if (rc)
|
||||
return rc;
|
||||
}
|
||||
cur = TAILQ_PREV(cur, spdk_subsystem_list, tailq);
|
||||
} while (cur);
|
||||
return rc;
|
||||
}
|
||||
|
||||
void
|
||||
spdk_subsystem_config(FILE *fp)
|
||||
{
|
||||
struct spdk_subsystem *subsystem;
|
||||
|
||||
TAILQ_FOREACH(subsystem, &g_subsystems, tailq) {
|
||||
if (subsystem->config)
|
||||
subsystem->config(fp);
|
||||
}
|
||||
}
|
43
lib/event/subsystem.h
Normal file
43
lib/event/subsystem.h
Normal file
@ -0,0 +1,43 @@
|
||||
/*-
|
||||
* BSD LICENSE
|
||||
*
|
||||
* Copyright (c) Intel Corporation.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in
|
||||
* the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
* * Neither the name of Intel Corporation nor the names of its
|
||||
* contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef SPDK_SUBSYSTEM_H_
|
||||
#define SPDK_SUBSYSTEM_H_
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
int spdk_subsystem_init(void);
|
||||
int spdk_subsystem_fini(void);
|
||||
void spdk_subsystem_config(FILE *fp);
|
||||
|
||||
#endif
|
@ -151,7 +151,7 @@ DPDK_INC_DIR ?= $(DPDK_DIR_ABS)/include
|
||||
DPDK_LIB_DIR ?= $(DPDK_DIR_ABS)/lib
|
||||
|
||||
DPDK_INC = -I$(DPDK_INC_DIR)
|
||||
DPDK_LIB = -L$(DPDK_LIB_DIR) -lrte_eal -lrte_mempool -lrte_ring -Wl,-rpath=$(DPDK_LIB_DIR)
|
||||
DPDK_LIB = -L$(DPDK_LIB_DIR) -lrte_eal -lrte_mempool -lrte_ring -lrte_timer -Wl,-rpath=$(DPDK_LIB_DIR)
|
||||
# librte_malloc was removed after DPDK 2.1. Link this library conditionally based on its
|
||||
# existence to maintain backward compatibility.
|
||||
ifneq ($(wildcard $(DPDK_DIR_ABS)/lib/librte_malloc.*),)
|
||||
|
@ -34,7 +34,7 @@
|
||||
SPDK_ROOT_DIR := $(abspath $(CURDIR)/../..)
|
||||
include $(SPDK_ROOT_DIR)/mk/spdk.common.mk
|
||||
|
||||
DIRS-y = log json jsonrpc nvme memory ioat
|
||||
DIRS-y = event log json jsonrpc nvme memory ioat
|
||||
|
||||
.PHONY: all clean $(DIRS-y)
|
||||
|
||||
|
44
test/lib/event/Makefile
Normal file
44
test/lib/event/Makefile
Normal file
@ -0,0 +1,44 @@
|
||||
#
|
||||
# BSD LICENSE
|
||||
#
|
||||
# Copyright (c) Intel Corporation.
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions
|
||||
# are met:
|
||||
#
|
||||
# * Redistributions of source code must retain the above copyright
|
||||
# notice, this list of conditions and the following disclaimer.
|
||||
# * Redistributions in binary form must reproduce the above copyright
|
||||
# notice, this list of conditions and the following disclaimer in
|
||||
# the documentation and/or other materials provided with the
|
||||
# distribution.
|
||||
# * Neither the name of Intel Corporation nor the names of its
|
||||
# contributors may be used to endorse or promote products derived
|
||||
# from this software without specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#
|
||||
|
||||
SPDK_ROOT_DIR := $(abspath $(CURDIR)/../../..)
|
||||
include $(SPDK_ROOT_DIR)/mk/spdk.common.mk
|
||||
|
||||
DIRS-y = event subsystem
|
||||
|
||||
.PHONY: all clean $(DIRS-y)
|
||||
|
||||
all: $(DIRS-y)
|
||||
clean: $(DIRS-y)
|
||||
|
||||
include $(SPDK_ROOT_DIR)/mk/spdk.subdirs.mk
|
10
test/lib/event/event.sh
Executable file
10
test/lib/event/event.sh
Executable file
@ -0,0 +1,10 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
testdir=$(readlink -f $(dirname $0))
|
||||
rootdir=$testdir/../../..
|
||||
source $rootdir/scripts/autotest_common.sh
|
||||
|
||||
timing_enter event
|
||||
$testdir/event/event -m 0xF -t 5
|
||||
$testdir/subsystem/subsystem_ut
|
||||
timing_exit event
|
1
test/lib/event/event/.gitignore
vendored
Normal file
1
test/lib/event/event/.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
||||
event
|
57
test/lib/event/event/Makefile
Normal file
57
test/lib/event/event/Makefile
Normal file
@ -0,0 +1,57 @@
|
||||
#
|
||||
# BSD LICENSE
|
||||
#
|
||||
# Copyright (c) Intel Corporation.
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions
|
||||
# are met:
|
||||
#
|
||||
# * Redistributions of source code must retain the above copyright
|
||||
# notice, this list of conditions and the following disclaimer.
|
||||
# * Redistributions in binary form must reproduce the above copyright
|
||||
# notice, this list of conditions and the following disclaimer in
|
||||
# the documentation and/or other materials provided with the
|
||||
# distribution.
|
||||
# * Neither the name of Intel Corporation nor the names of its
|
||||
# contributors may be used to endorse or promote products derived
|
||||
# from this software without specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#
|
||||
|
||||
SPDK_ROOT_DIR := $(abspath $(CURDIR)/../../../..)
|
||||
include $(SPDK_ROOT_DIR)/mk/spdk.common.mk
|
||||
|
||||
CFLAGS += $(DPDK_INC)
|
||||
APP = event
|
||||
C_SRCS := event.c
|
||||
|
||||
SPDK_LIBS += $(SPDK_ROOT_DIR)/lib/event/libspdk_event.a \
|
||||
$(SPDK_ROOT_DIR)/lib/trace/libspdk_trace.a \
|
||||
$(SPDK_ROOT_DIR)/lib/conf/libspdk_conf.a \
|
||||
$(SPDK_ROOT_DIR)/lib/util/libspdk_util.a \
|
||||
$(SPDK_ROOT_DIR)/lib/log/libspdk_log.a \
|
||||
|
||||
LIBS += $(SPDK_LIBS) -lpthread $(DPDK_LIB) -lrt
|
||||
|
||||
all : $(APP)
|
||||
|
||||
$(APP) : $(OBJS) $(SPDK_LIBS)
|
||||
$(LINK_C)
|
||||
|
||||
clean :
|
||||
$(CLEAN_C) $(APP)
|
||||
|
||||
include $(SPDK_ROOT_DIR)/mk/spdk.deps.mk
|
178
test/lib/event/event/event.c
Normal file
178
test/lib/event/event/event.c
Normal file
@ -0,0 +1,178 @@
|
||||
/*-
|
||||
* BSD LICENSE
|
||||
*
|
||||
* Copyright (c) Intel Corporation.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in
|
||||
* the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
* * Neither the name of Intel Corporation nor the names of its
|
||||
* contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdbool.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <rte_config.h>
|
||||
#include <rte_eal.h>
|
||||
#include <rte_debug.h>
|
||||
#include <rte_mempool.h>
|
||||
#include <rte_cycles.h>
|
||||
#include <rte_malloc.h>
|
||||
#include <rte_ring.h>
|
||||
#include <rte_lcore.h>
|
||||
|
||||
#include "spdk/event.h"
|
||||
#include "spdk/log.h"
|
||||
|
||||
static uint64_t g_tsc_rate;
|
||||
static uint64_t g_tsc_us_rate;
|
||||
|
||||
static int g_time_in_sec;
|
||||
|
||||
static __thread uint64_t __call_count = 0;
|
||||
static uint64_t call_count[RTE_MAX_LCORE];
|
||||
|
||||
static void
|
||||
submit_new_event(spdk_event_t event)
|
||||
{
|
||||
static __thread uint32_t next_lcore = RTE_MAX_LCORE;
|
||||
|
||||
if (next_lcore == RTE_MAX_LCORE) {
|
||||
next_lcore = rte_get_next_lcore(rte_lcore_id(), 0, 1);
|
||||
}
|
||||
|
||||
++__call_count;
|
||||
event = spdk_event_allocate(next_lcore, submit_new_event, NULL, NULL, NULL);
|
||||
spdk_event_call(event);
|
||||
}
|
||||
|
||||
static int
|
||||
event_work_fn(void *arg)
|
||||
{
|
||||
uint64_t tsc_end;
|
||||
|
||||
tsc_end = rte_get_timer_cycles() + g_time_in_sec * g_tsc_rate;
|
||||
|
||||
submit_new_event(NULL);
|
||||
submit_new_event(NULL);
|
||||
submit_new_event(NULL);
|
||||
submit_new_event(NULL);
|
||||
|
||||
while (1) {
|
||||
|
||||
spdk_event_queue_run_all(rte_lcore_id());
|
||||
|
||||
if (rte_get_timer_cycles() > tsc_end) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
call_count[rte_lcore_id()] = __call_count;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
usage(char *program_name)
|
||||
{
|
||||
printf("%s options\n", program_name);
|
||||
printf("\t[-m core mask for distributing I/O submission/completion work\n");
|
||||
printf("\t\t(default: 0x1 - use core 0 only)]\n");
|
||||
printf("\t[-t time in seconds]\n");
|
||||
}
|
||||
|
||||
static void
|
||||
performance_dump(int io_time)
|
||||
{
|
||||
uint32_t i;
|
||||
|
||||
printf("\n");
|
||||
RTE_LCORE_FOREACH(i) {
|
||||
printf("lcore %2d: %8ju\n", i, call_count[i] / g_time_in_sec);
|
||||
}
|
||||
|
||||
fflush(stdout);
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
struct spdk_app_opts opts;
|
||||
int op;
|
||||
int i;
|
||||
|
||||
spdk_app_opts_init(&opts);
|
||||
opts.name = "event";
|
||||
|
||||
g_time_in_sec = 0;
|
||||
|
||||
while ((op = getopt(argc, argv, "m:t:")) != -1) {
|
||||
switch (op) {
|
||||
case 'm':
|
||||
opts.reactor_mask = optarg;
|
||||
break;
|
||||
case 't':
|
||||
g_time_in_sec = atoi(optarg);
|
||||
break;
|
||||
default:
|
||||
usage(argv[0]);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
if (!g_time_in_sec) {
|
||||
usage(argv[0]);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
optind = 1; /*reset the optind */
|
||||
|
||||
spdk_init_dpdk(&opts);
|
||||
spdk_app_init(&opts);
|
||||
|
||||
g_tsc_rate = rte_get_timer_hz();
|
||||
g_tsc_us_rate = g_tsc_rate / (1000 * 1000);
|
||||
|
||||
printf("Running I/O for %d seconds...", g_time_in_sec);
|
||||
fflush(stdout);
|
||||
|
||||
/* call event_work_fn on each slave lcore */
|
||||
RTE_LCORE_FOREACH_SLAVE(i) {
|
||||
rte_eal_remote_launch(event_work_fn, NULL, i);
|
||||
}
|
||||
|
||||
/* call event_work_fn on lcore0 */
|
||||
event_work_fn(NULL);
|
||||
|
||||
rte_eal_mp_wait_lcore();
|
||||
|
||||
performance_dump(g_time_in_sec);
|
||||
|
||||
printf("done.\n");
|
||||
return 0;
|
||||
}
|
1
test/lib/event/subsystem/.gitignore
vendored
Normal file
1
test/lib/event/subsystem/.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
||||
subsystem_ut
|
57
test/lib/event/subsystem/Makefile
Normal file
57
test/lib/event/subsystem/Makefile
Normal file
@ -0,0 +1,57 @@
|
||||
#
|
||||
# BSD LICENSE
|
||||
#
|
||||
# Copyright (c) Intel Corporation.
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions
|
||||
# are met:
|
||||
#
|
||||
# * Redistributions of source code must retain the above copyright
|
||||
# notice, this list of conditions and the following disclaimer.
|
||||
# * Redistributions in binary form must reproduce the above copyright
|
||||
# notice, this list of conditions and the following disclaimer in
|
||||
# the documentation and/or other materials provided with the
|
||||
# distribution.
|
||||
# * Neither the name of Intel Corporation nor the names of its
|
||||
# contributors may be used to endorse or promote products derived
|
||||
# from this software without specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#
|
||||
|
||||
SPDK_ROOT_DIR := $(abspath $(CURDIR)/../../../..)
|
||||
include $(SPDK_ROOT_DIR)/mk/spdk.common.mk
|
||||
|
||||
CFLAGS += -I$(SPDK_ROOT_DIR)/lib/event
|
||||
APP = subsystem_ut
|
||||
C_SRCS := subsystem_ut.c
|
||||
|
||||
SPDK_LIBS += $(SPDK_ROOT_DIR)/lib/event/libspdk_event.a \
|
||||
$(SPDK_ROOT_DIR)/lib/trace/libspdk_trace.a \
|
||||
$(SPDK_ROOT_DIR)/lib/conf/libspdk_conf.a \
|
||||
$(SPDK_ROOT_DIR)/lib/util/libspdk_util.a \
|
||||
$(SPDK_ROOT_DIR)/lib/log/libspdk_log.a \
|
||||
|
||||
LIBS += $(SPDK_LIBS) -lpthread -lrt -lcunit
|
||||
|
||||
all : $(APP)
|
||||
|
||||
$(APP) : $(OBJS) $(SPDK_LIBS)
|
||||
$(LINK_C)
|
||||
|
||||
clean :
|
||||
$(CLEAN_C) $(APP)
|
||||
|
||||
include $(SPDK_ROOT_DIR)/mk/spdk.deps.mk
|
206
test/lib/event/subsystem/subsystem_ut.c
Normal file
206
test/lib/event/subsystem/subsystem_ut.c
Normal file
@ -0,0 +1,206 @@
|
||||
/*-
|
||||
* <COPYRIGHT_TAG>
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <CUnit/Basic.h>
|
||||
|
||||
#include "subsystem.c"
|
||||
|
||||
static struct spdk_subsystem g_ut_subsystems[8];
|
||||
static struct spdk_subsystem_depend g_ut_subsystem_deps[8];
|
||||
|
||||
static void
|
||||
set_up_subsystem(struct spdk_subsystem *subsystem, const char *name)
|
||||
{
|
||||
subsystem->init = NULL;
|
||||
subsystem->fini = NULL;
|
||||
subsystem->config = NULL;
|
||||
subsystem->name = name;
|
||||
}
|
||||
|
||||
static void
|
||||
set_up_depends(struct spdk_subsystem_depend *depend, const char *subsystem_name,
|
||||
const char *dpends_on_name)
|
||||
{
|
||||
depend->name = subsystem_name;
|
||||
depend->depends_on = dpends_on_name;
|
||||
}
|
||||
|
||||
static void
|
||||
subsystem_clear(void)
|
||||
{
|
||||
struct spdk_subsystem *subsystem, *subsystem_tmp;
|
||||
struct spdk_subsystem_depend *subsystem_dep, *subsystem_dep_tmp;
|
||||
|
||||
TAILQ_FOREACH_SAFE(subsystem, &g_subsystems, tailq, subsystem_tmp) {
|
||||
TAILQ_REMOVE(&g_subsystems, subsystem, tailq);
|
||||
}
|
||||
|
||||
TAILQ_FOREACH_SAFE(subsystem_dep, &g_depends, tailq, subsystem_dep_tmp) {
|
||||
TAILQ_REMOVE(&g_depends, subsystem_dep, tailq);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
subsystem_sort_test_depends_on_single(void)
|
||||
{
|
||||
struct spdk_subsystem *subsystem;
|
||||
int i;
|
||||
char subsystem_name[16];
|
||||
|
||||
spdk_subsystem_init();
|
||||
|
||||
i = 4;
|
||||
TAILQ_FOREACH(subsystem, &g_subsystems, tailq) {
|
||||
snprintf(subsystem_name, sizeof(subsystem_name), "subsystem%d", i);
|
||||
i--;
|
||||
CU_ASSERT(strcmp(subsystem_name, subsystem->name) == 0);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
subsystem_sort_test_depends_on_multiple(void)
|
||||
{
|
||||
int i;
|
||||
struct spdk_subsystem *subsystem;
|
||||
|
||||
subsystem_clear();
|
||||
set_up_subsystem(&g_ut_subsystems[0], "iscsi");
|
||||
set_up_subsystem(&g_ut_subsystems[1], "nvmf");
|
||||
set_up_subsystem(&g_ut_subsystems[2], "sock");
|
||||
set_up_subsystem(&g_ut_subsystems[3], "bdev");
|
||||
set_up_subsystem(&g_ut_subsystems[4], "rpc");
|
||||
set_up_subsystem(&g_ut_subsystems[5], "scsi");
|
||||
set_up_subsystem(&g_ut_subsystems[6], "interface");
|
||||
set_up_subsystem(&g_ut_subsystems[7], "copy");
|
||||
|
||||
for (i = 0; i < 8; i++) {
|
||||
spdk_add_subsystem(&g_ut_subsystems[i]);
|
||||
}
|
||||
|
||||
set_up_depends(&g_ut_subsystem_deps[0], "bdev", "copy");
|
||||
set_up_depends(&g_ut_subsystem_deps[1], "scsi", "bdev");
|
||||
set_up_depends(&g_ut_subsystem_deps[2], "rpc", "interface");
|
||||
set_up_depends(&g_ut_subsystem_deps[3], "sock", "interface");
|
||||
set_up_depends(&g_ut_subsystem_deps[4], "nvmf", "interface");
|
||||
set_up_depends(&g_ut_subsystem_deps[5], "iscsi", "scsi");
|
||||
set_up_depends(&g_ut_subsystem_deps[6], "iscsi", "sock");
|
||||
set_up_depends(&g_ut_subsystem_deps[7], "iscsi", "rpc");
|
||||
|
||||
for (i = 0; i < 8; i++) {
|
||||
spdk_add_subsystem_depend(&g_ut_subsystem_deps[i]);
|
||||
}
|
||||
|
||||
spdk_subsystem_init();
|
||||
|
||||
subsystem = TAILQ_FIRST(&g_subsystems);
|
||||
CU_ASSERT(strcmp(subsystem->name, "interface") == 0);
|
||||
TAILQ_REMOVE(&g_subsystems, subsystem, tailq);
|
||||
|
||||
subsystem = TAILQ_FIRST(&g_subsystems);
|
||||
CU_ASSERT(strcmp(subsystem->name, "copy") == 0);
|
||||
TAILQ_REMOVE(&g_subsystems, subsystem, tailq);
|
||||
|
||||
subsystem = TAILQ_FIRST(&g_subsystems);
|
||||
CU_ASSERT(strcmp(subsystem->name, "nvmf") == 0);
|
||||
TAILQ_REMOVE(&g_subsystems, subsystem, tailq);
|
||||
|
||||
subsystem = TAILQ_FIRST(&g_subsystems);
|
||||
CU_ASSERT(strcmp(subsystem->name, "sock") == 0);
|
||||
TAILQ_REMOVE(&g_subsystems, subsystem, tailq);
|
||||
|
||||
subsystem = TAILQ_FIRST(&g_subsystems);
|
||||
CU_ASSERT(strcmp(subsystem->name, "bdev") == 0);
|
||||
TAILQ_REMOVE(&g_subsystems, subsystem, tailq);
|
||||
|
||||
subsystem = TAILQ_FIRST(&g_subsystems);
|
||||
CU_ASSERT(strcmp(subsystem->name, "rpc") == 0);
|
||||
TAILQ_REMOVE(&g_subsystems, subsystem, tailq);
|
||||
|
||||
subsystem = TAILQ_FIRST(&g_subsystems);
|
||||
CU_ASSERT(strcmp(subsystem->name, "scsi") == 0);
|
||||
TAILQ_REMOVE(&g_subsystems, subsystem, tailq);
|
||||
|
||||
subsystem = TAILQ_FIRST(&g_subsystems);
|
||||
CU_ASSERT(strcmp(subsystem->name, "iscsi") == 0);
|
||||
TAILQ_REMOVE(&g_subsystems, subsystem, tailq);
|
||||
}
|
||||
|
||||
SPDK_SUBSYSTEM_REGISTER(subsystem1, NULL, NULL, NULL)
|
||||
SPDK_SUBSYSTEM_REGISTER(subsystem2, NULL, NULL, NULL)
|
||||
SPDK_SUBSYSTEM_REGISTER(subsystem3, NULL, NULL, NULL)
|
||||
SPDK_SUBSYSTEM_REGISTER(subsystem4, NULL, NULL, NULL)
|
||||
SPDK_SUBSYSTEM_DEPEND(subsystem1, subsystem2)
|
||||
SPDK_SUBSYSTEM_DEPEND(subsystem2, subsystem3)
|
||||
SPDK_SUBSYSTEM_DEPEND(subsystem3, subsystem4)
|
||||
|
||||
|
||||
static void
|
||||
subsystem_sort_test_missing_dependency(void)
|
||||
{
|
||||
/*
|
||||
* A depends on B, but B is missing
|
||||
*/
|
||||
|
||||
subsystem_clear();
|
||||
set_up_subsystem(&g_ut_subsystems[0], "A");
|
||||
spdk_add_subsystem(&g_ut_subsystems[0]);
|
||||
|
||||
set_up_depends(&g_ut_subsystem_deps[0], "A", "B");
|
||||
spdk_add_subsystem_depend(&g_ut_subsystem_deps[0]);
|
||||
|
||||
CU_ASSERT(spdk_subsystem_init() != 0);
|
||||
|
||||
/*
|
||||
* Dependency from C to A is defined, but C is missing
|
||||
*/
|
||||
|
||||
subsystem_clear();
|
||||
set_up_subsystem(&g_ut_subsystems[0], "A");
|
||||
spdk_add_subsystem(&g_ut_subsystems[0]);
|
||||
|
||||
set_up_depends(&g_ut_subsystem_deps[0], "C", "A");
|
||||
spdk_add_subsystem_depend(&g_ut_subsystem_deps[0]);
|
||||
|
||||
CU_ASSERT(spdk_subsystem_init() != 0);
|
||||
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
CU_pSuite suite = NULL;
|
||||
unsigned int num_failures;
|
||||
|
||||
if (CU_initialize_registry() != CUE_SUCCESS) {
|
||||
return CU_get_error();
|
||||
}
|
||||
|
||||
suite = CU_add_suite("subsystem_suite", NULL, NULL);
|
||||
if (suite == NULL) {
|
||||
CU_cleanup_registry();
|
||||
return CU_get_error();
|
||||
}
|
||||
|
||||
if (
|
||||
CU_add_test(suite, "subsystem_sort_test_depends_on_single",
|
||||
subsystem_sort_test_depends_on_single) == NULL
|
||||
|| CU_add_test(suite, "subsystem_sort_test_depends_on_multiple",
|
||||
subsystem_sort_test_depends_on_multiple) == NULL
|
||||
|| CU_add_test(suite, "subsystem_sort_test_missing_dependency",
|
||||
subsystem_sort_test_missing_dependency) == NULL
|
||||
) {
|
||||
CU_cleanup_registry();
|
||||
return CU_get_error();
|
||||
}
|
||||
|
||||
CU_basic_set_mode(CU_BRM_VERBOSE);
|
||||
CU_basic_run_tests();
|
||||
num_failures = CU_get_number_of_failures();
|
||||
CU_cleanup_registry();
|
||||
|
||||
return num_failures;
|
||||
}
|
Loading…
Reference in New Issue
Block a user