Merge branch 'linus' into perf/core
Conflicts: tools/perf/Makefile tools/perf/builtin-test.c tools/perf/perf.h tools/perf/tests/parse-events.c tools/perf/util/evsel.h Signed-off-by: Ingo Molnar <mingo@kernel.org>
This commit is contained in:
commit
f0b9abfb04
1115 changed files with 13320 additions and 8061 deletions
|
@ -169,7 +169,35 @@ endif
|
|||
|
||||
### --- END CONFIGURATION SECTION ---
|
||||
|
||||
BASIC_CFLAGS = -Iutil/include -Iarch/$(ARCH)/include -I$(OUTPUT)util -Iutil -I. -I$(TRACE_EVENT_DIR) -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE
|
||||
ifeq ($(srctree),)
|
||||
srctree := $(patsubst %/,%,$(dir $(shell pwd)))
|
||||
srctree := $(patsubst %/,%,$(dir $(srctree)))
|
||||
#$(info Determined 'srctree' to be $(srctree))
|
||||
endif
|
||||
|
||||
ifneq ($(objtree),)
|
||||
#$(info Determined 'objtree' to be $(objtree))
|
||||
endif
|
||||
|
||||
ifneq ($(OUTPUT),)
|
||||
#$(info Determined 'OUTPUT' to be $(OUTPUT))
|
||||
endif
|
||||
|
||||
BASIC_CFLAGS = \
|
||||
-Iutil/include \
|
||||
-Iarch/$(ARCH)/include \
|
||||
$(if $(objtree),-I$(objtree)/arch/$(ARCH)/include/generated/uapi) \
|
||||
-I$(srctree)/arch/$(ARCH)/include/uapi \
|
||||
-I$(srctree)/arch/$(ARCH)/include \
|
||||
$(if $(objtree),-I$(objtree)/include/generated/uapi) \
|
||||
-I$(srctree)/include/uapi \
|
||||
-I$(srctree)/include \
|
||||
-I$(OUTPUT)util \
|
||||
-Iutil \
|
||||
-I. \
|
||||
-I$(TRACE_EVENT_DIR) \
|
||||
-D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE
|
||||
|
||||
BASIC_LDFLAGS =
|
||||
|
||||
ifeq ($(call try-cc,$(SOURCE_BIONIC),$(CFLAGS),bionic),y)
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
|
||||
#include <stdlib.h>
|
||||
#include "../../util/types.h"
|
||||
#include "../../../../../arch/x86/include/asm/perf_regs.h"
|
||||
#include <asm/perf_regs.h>
|
||||
|
||||
#ifndef ARCH_X86_64
|
||||
#define PERF_REGS_MASK ((1ULL << PERF_REG_X86_32_MAX) - 1)
|
||||
|
|
|
@ -22,9 +22,10 @@
|
|||
#include <pthread.h>
|
||||
#include <math.h>
|
||||
|
||||
#include "../../arch/x86/include/asm/svm.h"
|
||||
#include "../../arch/x86/include/asm/vmx.h"
|
||||
#include "../../arch/x86/include/asm/kvm.h"
|
||||
#if defined(__i386__) || defined(__x86_64__)
|
||||
#include <asm/svm.h>
|
||||
#include <asm/vmx.h>
|
||||
#include <asm/kvm.h>
|
||||
|
||||
struct event_key {
|
||||
#define INVALID_KEY (~0ULL)
|
||||
|
@ -58,7 +59,7 @@ struct kvm_event_key {
|
|||
};
|
||||
|
||||
|
||||
struct perf_kvm;
|
||||
struct perf_kvm_stat;
|
||||
|
||||
struct kvm_events_ops {
|
||||
bool (*is_begin_event)(struct perf_evsel *evsel,
|
||||
|
@ -66,7 +67,7 @@ struct kvm_events_ops {
|
|||
struct event_key *key);
|
||||
bool (*is_end_event)(struct perf_evsel *evsel,
|
||||
struct perf_sample *sample, struct event_key *key);
|
||||
void (*decode_key)(struct perf_kvm *kvm, struct event_key *key,
|
||||
void (*decode_key)(struct perf_kvm_stat *kvm, struct event_key *key,
|
||||
char decode[20]);
|
||||
const char *name;
|
||||
};
|
||||
|
@ -79,7 +80,7 @@ struct exit_reasons_table {
|
|||
#define EVENTS_BITS 12
|
||||
#define EVENTS_CACHE_SIZE (1UL << EVENTS_BITS)
|
||||
|
||||
struct perf_kvm {
|
||||
struct perf_kvm_stat {
|
||||
struct perf_tool tool;
|
||||
struct perf_session *session;
|
||||
|
||||
|
@ -146,7 +147,7 @@ static struct exit_reasons_table svm_exit_reasons[] = {
|
|||
SVM_EXIT_REASONS
|
||||
};
|
||||
|
||||
static const char *get_exit_reason(struct perf_kvm *kvm, u64 exit_code)
|
||||
static const char *get_exit_reason(struct perf_kvm_stat *kvm, u64 exit_code)
|
||||
{
|
||||
int i = kvm->exit_reasons_size;
|
||||
struct exit_reasons_table *tbl = kvm->exit_reasons;
|
||||
|
@ -162,7 +163,7 @@ static const char *get_exit_reason(struct perf_kvm *kvm, u64 exit_code)
|
|||
return "UNKNOWN";
|
||||
}
|
||||
|
||||
static void exit_event_decode_key(struct perf_kvm *kvm,
|
||||
static void exit_event_decode_key(struct perf_kvm_stat *kvm,
|
||||
struct event_key *key,
|
||||
char decode[20])
|
||||
{
|
||||
|
@ -228,7 +229,7 @@ static bool mmio_event_end(struct perf_evsel *evsel, struct perf_sample *sample,
|
|||
return false;
|
||||
}
|
||||
|
||||
static void mmio_event_decode_key(struct perf_kvm *kvm __maybe_unused,
|
||||
static void mmio_event_decode_key(struct perf_kvm_stat *kvm __maybe_unused,
|
||||
struct event_key *key,
|
||||
char decode[20])
|
||||
{
|
||||
|
@ -271,7 +272,7 @@ static bool ioport_event_end(struct perf_evsel *evsel,
|
|||
return kvm_entry_event(evsel);
|
||||
}
|
||||
|
||||
static void ioport_event_decode_key(struct perf_kvm *kvm __maybe_unused,
|
||||
static void ioport_event_decode_key(struct perf_kvm_stat *kvm __maybe_unused,
|
||||
struct event_key *key,
|
||||
char decode[20])
|
||||
{
|
||||
|
@ -286,7 +287,7 @@ static struct kvm_events_ops ioport_events = {
|
|||
.name = "IO Port Access"
|
||||
};
|
||||
|
||||
static bool register_kvm_events_ops(struct perf_kvm *kvm)
|
||||
static bool register_kvm_events_ops(struct perf_kvm_stat *kvm)
|
||||
{
|
||||
bool ret = true;
|
||||
|
||||
|
@ -311,7 +312,7 @@ struct vcpu_event_record {
|
|||
};
|
||||
|
||||
|
||||
static void init_kvm_event_record(struct perf_kvm *kvm)
|
||||
static void init_kvm_event_record(struct perf_kvm_stat *kvm)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
|
@ -360,7 +361,7 @@ static struct kvm_event *kvm_alloc_init_event(struct event_key *key)
|
|||
return event;
|
||||
}
|
||||
|
||||
static struct kvm_event *find_create_kvm_event(struct perf_kvm *kvm,
|
||||
static struct kvm_event *find_create_kvm_event(struct perf_kvm_stat *kvm,
|
||||
struct event_key *key)
|
||||
{
|
||||
struct kvm_event *event;
|
||||
|
@ -382,7 +383,7 @@ static struct kvm_event *find_create_kvm_event(struct perf_kvm *kvm,
|
|||
return event;
|
||||
}
|
||||
|
||||
static bool handle_begin_event(struct perf_kvm *kvm,
|
||||
static bool handle_begin_event(struct perf_kvm_stat *kvm,
|
||||
struct vcpu_event_record *vcpu_record,
|
||||
struct event_key *key, u64 timestamp)
|
||||
{
|
||||
|
@ -429,7 +430,7 @@ static bool update_kvm_event(struct kvm_event *event, int vcpu_id,
|
|||
return true;
|
||||
}
|
||||
|
||||
static bool handle_end_event(struct perf_kvm *kvm,
|
||||
static bool handle_end_event(struct perf_kvm_stat *kvm,
|
||||
struct vcpu_event_record *vcpu_record,
|
||||
struct event_key *key,
|
||||
u64 timestamp)
|
||||
|
@ -496,7 +497,7 @@ struct vcpu_event_record *per_vcpu_record(struct thread *thread,
|
|||
return thread->priv;
|
||||
}
|
||||
|
||||
static bool handle_kvm_event(struct perf_kvm *kvm,
|
||||
static bool handle_kvm_event(struct perf_kvm_stat *kvm,
|
||||
struct thread *thread,
|
||||
struct perf_evsel *evsel,
|
||||
struct perf_sample *sample)
|
||||
|
@ -556,7 +557,7 @@ static struct kvm_event_key keys[] = {
|
|||
{ NULL, NULL }
|
||||
};
|
||||
|
||||
static bool select_key(struct perf_kvm *kvm)
|
||||
static bool select_key(struct perf_kvm_stat *kvm)
|
||||
{
|
||||
int i;
|
||||
|
||||
|
@ -592,7 +593,8 @@ static void insert_to_result(struct rb_root *result, struct kvm_event *event,
|
|||
rb_insert_color(&event->rb, result);
|
||||
}
|
||||
|
||||
static void update_total_count(struct perf_kvm *kvm, struct kvm_event *event)
|
||||
static void
|
||||
update_total_count(struct perf_kvm_stat *kvm, struct kvm_event *event)
|
||||
{
|
||||
int vcpu = kvm->trace_vcpu;
|
||||
|
||||
|
@ -605,7 +607,7 @@ static bool event_is_valid(struct kvm_event *event, int vcpu)
|
|||
return !!get_event_count(event, vcpu);
|
||||
}
|
||||
|
||||
static void sort_result(struct perf_kvm *kvm)
|
||||
static void sort_result(struct perf_kvm_stat *kvm)
|
||||
{
|
||||
unsigned int i;
|
||||
int vcpu = kvm->trace_vcpu;
|
||||
|
@ -644,7 +646,7 @@ static void print_vcpu_info(int vcpu)
|
|||
pr_info("VCPU %d:\n\n", vcpu);
|
||||
}
|
||||
|
||||
static void print_result(struct perf_kvm *kvm)
|
||||
static void print_result(struct perf_kvm_stat *kvm)
|
||||
{
|
||||
char decode[20];
|
||||
struct kvm_event *event;
|
||||
|
@ -687,7 +689,8 @@ static int process_sample_event(struct perf_tool *tool,
|
|||
struct machine *machine)
|
||||
{
|
||||
struct thread *thread = machine__findnew_thread(machine, sample->tid);
|
||||
struct perf_kvm *kvm = container_of(tool, struct perf_kvm, tool);
|
||||
struct perf_kvm_stat *kvm = container_of(tool, struct perf_kvm_stat,
|
||||
tool);
|
||||
|
||||
if (thread == NULL) {
|
||||
pr_debug("problem processing %d event, skipping it.\n",
|
||||
|
@ -718,7 +721,7 @@ static int get_cpu_isa(struct perf_session *session)
|
|||
return isa;
|
||||
}
|
||||
|
||||
static int read_events(struct perf_kvm *kvm)
|
||||
static int read_events(struct perf_kvm_stat *kvm)
|
||||
{
|
||||
int ret;
|
||||
|
||||
|
@ -767,7 +770,7 @@ static bool verify_vcpu(int vcpu)
|
|||
return true;
|
||||
}
|
||||
|
||||
static int kvm_events_report_vcpu(struct perf_kvm *kvm)
|
||||
static int kvm_events_report_vcpu(struct perf_kvm_stat *kvm)
|
||||
{
|
||||
int ret = -EINVAL;
|
||||
int vcpu = kvm->trace_vcpu;
|
||||
|
@ -815,7 +818,8 @@ static const char * const record_args[] = {
|
|||
_p; \
|
||||
})
|
||||
|
||||
static int kvm_events_record(struct perf_kvm *kvm, int argc, const char **argv)
|
||||
static int
|
||||
kvm_events_record(struct perf_kvm_stat *kvm, int argc, const char **argv)
|
||||
{
|
||||
unsigned int rec_argc, i, j;
|
||||
const char **rec_argv;
|
||||
|
@ -838,7 +842,8 @@ static int kvm_events_record(struct perf_kvm *kvm, int argc, const char **argv)
|
|||
return cmd_record(i, rec_argv, NULL);
|
||||
}
|
||||
|
||||
static int kvm_events_report(struct perf_kvm *kvm, int argc, const char **argv)
|
||||
static int
|
||||
kvm_events_report(struct perf_kvm_stat *kvm, int argc, const char **argv)
|
||||
{
|
||||
const struct option kvm_events_report_options[] = {
|
||||
OPT_STRING(0, "event", &kvm->report_event, "report event",
|
||||
|
@ -881,24 +886,37 @@ static void print_kvm_stat_usage(void)
|
|||
printf("\nOtherwise, it is the alias of 'perf stat':\n");
|
||||
}
|
||||
|
||||
static int kvm_cmd_stat(struct perf_kvm *kvm, int argc, const char **argv)
|
||||
static int kvm_cmd_stat(const char *file_name, int argc, const char **argv)
|
||||
{
|
||||
struct perf_kvm_stat kvm = {
|
||||
.file_name = file_name,
|
||||
|
||||
.trace_vcpu = -1,
|
||||
.report_event = "vmexit",
|
||||
.sort_key = "sample",
|
||||
|
||||
.exit_reasons = svm_exit_reasons,
|
||||
.exit_reasons_size = ARRAY_SIZE(svm_exit_reasons),
|
||||
.exit_reasons_isa = "SVM",
|
||||
};
|
||||
|
||||
if (argc == 1) {
|
||||
print_kvm_stat_usage();
|
||||
goto perf_stat;
|
||||
}
|
||||
|
||||
if (!strncmp(argv[1], "rec", 3))
|
||||
return kvm_events_record(kvm, argc - 1, argv + 1);
|
||||
return kvm_events_record(&kvm, argc - 1, argv + 1);
|
||||
|
||||
if (!strncmp(argv[1], "rep", 3))
|
||||
return kvm_events_report(kvm, argc - 1 , argv + 1);
|
||||
return kvm_events_report(&kvm, argc - 1 , argv + 1);
|
||||
|
||||
perf_stat:
|
||||
return cmd_stat(argc, argv, NULL);
|
||||
}
|
||||
#endif
|
||||
|
||||
static int __cmd_record(struct perf_kvm *kvm, int argc, const char **argv)
|
||||
static int __cmd_record(const char *file_name, int argc, const char **argv)
|
||||
{
|
||||
int rec_argc, i = 0, j;
|
||||
const char **rec_argv;
|
||||
|
@ -907,7 +925,7 @@ static int __cmd_record(struct perf_kvm *kvm, int argc, const char **argv)
|
|||
rec_argv = calloc(rec_argc + 1, sizeof(char *));
|
||||
rec_argv[i++] = strdup("record");
|
||||
rec_argv[i++] = strdup("-o");
|
||||
rec_argv[i++] = strdup(kvm->file_name);
|
||||
rec_argv[i++] = strdup(file_name);
|
||||
for (j = 1; j < argc; j++, i++)
|
||||
rec_argv[i] = argv[j];
|
||||
|
||||
|
@ -916,7 +934,7 @@ static int __cmd_record(struct perf_kvm *kvm, int argc, const char **argv)
|
|||
return cmd_record(i, rec_argv, NULL);
|
||||
}
|
||||
|
||||
static int __cmd_report(struct perf_kvm *kvm, int argc, const char **argv)
|
||||
static int __cmd_report(const char *file_name, int argc, const char **argv)
|
||||
{
|
||||
int rec_argc, i = 0, j;
|
||||
const char **rec_argv;
|
||||
|
@ -925,7 +943,7 @@ static int __cmd_report(struct perf_kvm *kvm, int argc, const char **argv)
|
|||
rec_argv = calloc(rec_argc + 1, sizeof(char *));
|
||||
rec_argv[i++] = strdup("report");
|
||||
rec_argv[i++] = strdup("-i");
|
||||
rec_argv[i++] = strdup(kvm->file_name);
|
||||
rec_argv[i++] = strdup(file_name);
|
||||
for (j = 1; j < argc; j++, i++)
|
||||
rec_argv[i] = argv[j];
|
||||
|
||||
|
@ -934,7 +952,8 @@ static int __cmd_report(struct perf_kvm *kvm, int argc, const char **argv)
|
|||
return cmd_report(i, rec_argv, NULL);
|
||||
}
|
||||
|
||||
static int __cmd_buildid_list(struct perf_kvm *kvm, int argc, const char **argv)
|
||||
static int
|
||||
__cmd_buildid_list(const char *file_name, int argc, const char **argv)
|
||||
{
|
||||
int rec_argc, i = 0, j;
|
||||
const char **rec_argv;
|
||||
|
@ -943,7 +962,7 @@ static int __cmd_buildid_list(struct perf_kvm *kvm, int argc, const char **argv)
|
|||
rec_argv = calloc(rec_argc + 1, sizeof(char *));
|
||||
rec_argv[i++] = strdup("buildid-list");
|
||||
rec_argv[i++] = strdup("-i");
|
||||
rec_argv[i++] = strdup(kvm->file_name);
|
||||
rec_argv[i++] = strdup(file_name);
|
||||
for (j = 1; j < argc; j++, i++)
|
||||
rec_argv[i] = argv[j];
|
||||
|
||||
|
@ -954,20 +973,12 @@ static int __cmd_buildid_list(struct perf_kvm *kvm, int argc, const char **argv)
|
|||
|
||||
int cmd_kvm(int argc, const char **argv, const char *prefix __maybe_unused)
|
||||
{
|
||||
struct perf_kvm kvm = {
|
||||
.trace_vcpu = -1,
|
||||
.report_event = "vmexit",
|
||||
.sort_key = "sample",
|
||||
|
||||
.exit_reasons = svm_exit_reasons,
|
||||
.exit_reasons_size = ARRAY_SIZE(svm_exit_reasons),
|
||||
.exit_reasons_isa = "SVM",
|
||||
};
|
||||
const char *file_name;
|
||||
|
||||
const struct option kvm_options[] = {
|
||||
OPT_STRING('i', "input", &kvm.file_name, "file",
|
||||
OPT_STRING('i', "input", &file_name, "file",
|
||||
"Input file name"),
|
||||
OPT_STRING('o', "output", &kvm.file_name, "file",
|
||||
OPT_STRING('o', "output", &file_name, "file",
|
||||
"Output file name"),
|
||||
OPT_BOOLEAN(0, "guest", &perf_guest,
|
||||
"Collect guest os data"),
|
||||
|
@ -1002,32 +1013,34 @@ int cmd_kvm(int argc, const char **argv, const char *prefix __maybe_unused)
|
|||
if (!perf_host)
|
||||
perf_guest = 1;
|
||||
|
||||
if (!kvm.file_name) {
|
||||
if (!file_name) {
|
||||
if (perf_host && !perf_guest)
|
||||
kvm.file_name = strdup("perf.data.host");
|
||||
file_name = strdup("perf.data.host");
|
||||
else if (!perf_host && perf_guest)
|
||||
kvm.file_name = strdup("perf.data.guest");
|
||||
file_name = strdup("perf.data.guest");
|
||||
else
|
||||
kvm.file_name = strdup("perf.data.kvm");
|
||||
file_name = strdup("perf.data.kvm");
|
||||
|
||||
if (!kvm.file_name) {
|
||||
if (!file_name) {
|
||||
pr_err("Failed to allocate memory for filename\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
}
|
||||
|
||||
if (!strncmp(argv[0], "rec", 3))
|
||||
return __cmd_record(&kvm, argc, argv);
|
||||
return __cmd_record(file_name, argc, argv);
|
||||
else if (!strncmp(argv[0], "rep", 3))
|
||||
return __cmd_report(&kvm, argc, argv);
|
||||
return __cmd_report(file_name, argc, argv);
|
||||
else if (!strncmp(argv[0], "diff", 4))
|
||||
return cmd_diff(argc, argv, NULL);
|
||||
else if (!strncmp(argv[0], "top", 3))
|
||||
return cmd_top(argc, argv, NULL);
|
||||
else if (!strncmp(argv[0], "buildid-list", 12))
|
||||
return __cmd_buildid_list(&kvm, argc, argv);
|
||||
return __cmd_buildid_list(file_name, argc, argv);
|
||||
#if defined(__i386__) || defined(__x86_64__)
|
||||
else if (!strncmp(argv[0], "stat", 4))
|
||||
return kvm_cmd_stat(&kvm, argc, argv);
|
||||
return kvm_cmd_stat(file_name, argc, argv);
|
||||
#endif
|
||||
else
|
||||
usage_with_options(kvm_usage, kvm_options);
|
||||
|
||||
|
|
|
@ -5,8 +5,9 @@ struct winsize;
|
|||
|
||||
void get_term_dimensions(struct winsize *ws);
|
||||
|
||||
#include <asm/unistd.h>
|
||||
|
||||
#if defined(__i386__)
|
||||
#include "../../arch/x86/include/asm/unistd.h"
|
||||
#define rmb() asm volatile("lock; addl $0,0(%%esp)" ::: "memory")
|
||||
#define cpu_relax() asm volatile("rep; nop" ::: "memory");
|
||||
#define CPUINFO_PROC "model name"
|
||||
|
@ -16,7 +17,6 @@ void get_term_dimensions(struct winsize *ws);
|
|||
#endif
|
||||
|
||||
#if defined(__x86_64__)
|
||||
#include "../../arch/x86/include/asm/unistd.h"
|
||||
#define rmb() asm volatile("lfence" ::: "memory")
|
||||
#define cpu_relax() asm volatile("rep; nop" ::: "memory");
|
||||
#define CPUINFO_PROC "model name"
|
||||
|
@ -33,13 +33,11 @@ void get_term_dimensions(struct winsize *ws);
|
|||
#endif
|
||||
|
||||
#ifdef __s390__
|
||||
#include "../../arch/s390/include/asm/unistd.h"
|
||||
#define rmb() asm volatile("bcr 15,0" ::: "memory")
|
||||
#define cpu_relax() asm volatile("" ::: "memory");
|
||||
#endif
|
||||
|
||||
#ifdef __sh__
|
||||
#include "../../arch/sh/include/asm/unistd.h"
|
||||
#if defined(__SH4A__) || defined(__SH5__)
|
||||
# define rmb() asm volatile("synco" ::: "memory")
|
||||
#else
|
||||
|
@ -50,35 +48,30 @@ void get_term_dimensions(struct winsize *ws);
|
|||
#endif
|
||||
|
||||
#ifdef __hppa__
|
||||
#include "../../arch/parisc/include/asm/unistd.h"
|
||||
#define rmb() asm volatile("" ::: "memory")
|
||||
#define cpu_relax() asm volatile("" ::: "memory");
|
||||
#define CPUINFO_PROC "cpu"
|
||||
#endif
|
||||
|
||||
#ifdef __sparc__
|
||||
#include "../../arch/sparc/include/uapi/asm/unistd.h"
|
||||
#define rmb() asm volatile("":::"memory")
|
||||
#define cpu_relax() asm volatile("":::"memory")
|
||||
#define CPUINFO_PROC "cpu"
|
||||
#endif
|
||||
|
||||
#ifdef __alpha__
|
||||
#include "../../arch/alpha/include/asm/unistd.h"
|
||||
#define rmb() asm volatile("mb" ::: "memory")
|
||||
#define cpu_relax() asm volatile("" ::: "memory")
|
||||
#define CPUINFO_PROC "cpu model"
|
||||
#endif
|
||||
|
||||
#ifdef __ia64__
|
||||
#include "../../arch/ia64/include/asm/unistd.h"
|
||||
#define rmb() asm volatile ("mf" ::: "memory")
|
||||
#define cpu_relax() asm volatile ("hint @pause" ::: "memory")
|
||||
#define CPUINFO_PROC "model name"
|
||||
#endif
|
||||
|
||||
#ifdef __arm__
|
||||
#include "../../arch/arm/include/asm/unistd.h"
|
||||
/*
|
||||
* Use the __kuser_memory_barrier helper in the CPU helper page. See
|
||||
* arch/arm/kernel/entry-armv.S in the kernel source for details.
|
||||
|
@ -89,13 +82,11 @@ void get_term_dimensions(struct winsize *ws);
|
|||
#endif
|
||||
|
||||
#ifdef __aarch64__
|
||||
#include "../../arch/arm64/include/asm/unistd.h"
|
||||
#define rmb() asm volatile("dmb ld" ::: "memory")
|
||||
#define cpu_relax() asm volatile("yield" ::: "memory")
|
||||
#endif
|
||||
|
||||
#ifdef __mips__
|
||||
#include "../../arch/mips/include/asm/unistd.h"
|
||||
#define rmb() asm volatile( \
|
||||
".set mips2\n\t" \
|
||||
"sync\n\t" \
|
||||
|
@ -112,7 +103,7 @@ void get_term_dimensions(struct winsize *ws);
|
|||
#include <sys/types.h>
|
||||
#include <sys/syscall.h>
|
||||
|
||||
#include "../../include/uapi/linux/perf_event.h"
|
||||
#include <linux/perf_event.h>
|
||||
#include "util/types.h"
|
||||
#include <stdbool.h>
|
||||
|
||||
|
|
|
@ -3,8 +3,8 @@
|
|||
#include "evsel.h"
|
||||
#include "evlist.h"
|
||||
#include "sysfs.h"
|
||||
#include "../../../include/linux/hw_breakpoint.h"
|
||||
#include "tests.h"
|
||||
#include <linux/hw_breakpoint.h>
|
||||
|
||||
#define TEST_ASSERT_VAL(text, cond) \
|
||||
do { \
|
||||
|
|
|
@ -18,8 +18,8 @@
|
|||
#include "cpumap.h"
|
||||
#include "thread_map.h"
|
||||
#include "target.h"
|
||||
#include "../../../include/linux/hw_breakpoint.h"
|
||||
#include "../../../include/uapi/linux/perf_event.h"
|
||||
#include <linux/hw_breakpoint.h>
|
||||
#include <linux/perf_event.h>
|
||||
#include "perf_regs.h"
|
||||
|
||||
#define FD(e, x, y) (*(int *)xyarray__entry(e->fd, x, y))
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
#include <linux/list.h>
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include "../../../include/uapi/linux/perf_event.h"
|
||||
#include <linux/perf_event.h>
|
||||
#include "types.h"
|
||||
#include "xyarray.h"
|
||||
#include "cgroup.h"
|
||||
|
|
|
@ -1379,6 +1379,8 @@ static void print_numa_topology(struct perf_header *ph, int fd __maybe_unused,
|
|||
|
||||
str = tmp + 1;
|
||||
fprintf(fp, "# node%u cpu list : %s\n", c, str);
|
||||
|
||||
str += strlen(str) + 1;
|
||||
}
|
||||
return;
|
||||
error:
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#ifndef __PERF_HEADER_H
|
||||
#define __PERF_HEADER_H
|
||||
|
||||
#include "../../../include/uapi/linux/perf_event.h"
|
||||
#include <linux/perf_event.h>
|
||||
#include <sys/types.h>
|
||||
#include <stdbool.h>
|
||||
#include "types.h"
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#include "../../../include/linux/hw_breakpoint.h"
|
||||
#include <linux/hw_breakpoint.h>
|
||||
#include "util.h"
|
||||
#include "../perf.h"
|
||||
#include "evlist.h"
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
#include <linux/list.h>
|
||||
#include <stdbool.h>
|
||||
#include "types.h"
|
||||
#include "../../../include/uapi/linux/perf_event.h"
|
||||
#include <linux/perf_event.h>
|
||||
#include "types.h"
|
||||
|
||||
struct list_head;
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
#define __PMU_H
|
||||
|
||||
#include <linux/bitops.h>
|
||||
#include "../../../include/uapi/linux/perf_event.h"
|
||||
#include <linux/perf_event.h>
|
||||
|
||||
enum {
|
||||
PERF_PMU_FORMAT_VALUE_CONFIG,
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
#include "symbol.h"
|
||||
#include "thread.h"
|
||||
#include <linux/rbtree.h>
|
||||
#include "../../../include/uapi/linux/perf_event.h"
|
||||
#include <linux/perf_event.h>
|
||||
|
||||
struct sample_queue;
|
||||
struct ip_callchain;
|
||||
|
|
|
@ -90,17 +90,17 @@ void strbuf_addf(struct strbuf *sb, const char *fmt, ...)
|
|||
if (!strbuf_avail(sb))
|
||||
strbuf_grow(sb, 64);
|
||||
va_start(ap, fmt);
|
||||
len = vscnprintf(sb->buf + sb->len, sb->alloc - sb->len, fmt, ap);
|
||||
len = vsnprintf(sb->buf + sb->len, sb->alloc - sb->len, fmt, ap);
|
||||
va_end(ap);
|
||||
if (len < 0)
|
||||
die("your vscnprintf is broken");
|
||||
die("your vsnprintf is broken");
|
||||
if (len > strbuf_avail(sb)) {
|
||||
strbuf_grow(sb, len);
|
||||
va_start(ap, fmt);
|
||||
len = vscnprintf(sb->buf + sb->len, sb->alloc - sb->len, fmt, ap);
|
||||
len = vsnprintf(sb->buf + sb->len, sb->alloc - sb->len, fmt, ap);
|
||||
va_end(ap);
|
||||
if (len > strbuf_avail(sb)) {
|
||||
die("this should not happen, your snprintf is broken");
|
||||
die("this should not happen, your vsnprintf is broken");
|
||||
}
|
||||
}
|
||||
strbuf_setlen(sb, sb->len + len);
|
||||
|
|
|
@ -206,8 +206,10 @@ int get_msr(int cpu, off_t offset, unsigned long long *msr)
|
|||
retval = pread(fd, msr, sizeof *msr, offset);
|
||||
close(fd);
|
||||
|
||||
if (retval != sizeof *msr)
|
||||
if (retval != sizeof *msr) {
|
||||
fprintf(stderr, "%s offset 0x%zx read failed\n", pathname, offset);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -1101,7 +1103,9 @@ void turbostat_loop()
|
|||
|
||||
restart:
|
||||
retval = for_all_cpus(get_counters, EVEN_COUNTERS);
|
||||
if (retval) {
|
||||
if (retval < -1) {
|
||||
exit(retval);
|
||||
} else if (retval == -1) {
|
||||
re_initialize();
|
||||
goto restart;
|
||||
}
|
||||
|
@ -1114,7 +1118,9 @@ restart:
|
|||
}
|
||||
sleep(interval_sec);
|
||||
retval = for_all_cpus(get_counters, ODD_COUNTERS);
|
||||
if (retval) {
|
||||
if (retval < -1) {
|
||||
exit(retval);
|
||||
} else if (retval == -1) {
|
||||
re_initialize();
|
||||
goto restart;
|
||||
}
|
||||
|
@ -1126,7 +1132,9 @@ restart:
|
|||
flush_stdout();
|
||||
sleep(interval_sec);
|
||||
retval = for_all_cpus(get_counters, EVEN_COUNTERS);
|
||||
if (retval) {
|
||||
if (retval < -1) {
|
||||
exit(retval);
|
||||
} else if (retval == -1) {
|
||||
re_initialize();
|
||||
goto restart;
|
||||
}
|
||||
|
@ -1545,8 +1553,11 @@ void turbostat_init()
|
|||
int fork_it(char **argv)
|
||||
{
|
||||
pid_t child_pid;
|
||||
int status;
|
||||
|
||||
for_all_cpus(get_counters, EVEN_COUNTERS);
|
||||
status = for_all_cpus(get_counters, EVEN_COUNTERS);
|
||||
if (status)
|
||||
exit(status);
|
||||
/* clear affinity side-effect of get_counters() */
|
||||
sched_setaffinity(0, cpu_present_setsize, cpu_present_set);
|
||||
gettimeofday(&tv_even, (struct timezone *)NULL);
|
||||
|
@ -1556,7 +1567,6 @@ int fork_it(char **argv)
|
|||
/* child */
|
||||
execvp(argv[0], argv);
|
||||
} else {
|
||||
int status;
|
||||
|
||||
/* parent */
|
||||
if (child_pid == -1) {
|
||||
|
@ -1568,7 +1578,7 @@ int fork_it(char **argv)
|
|||
signal(SIGQUIT, SIG_IGN);
|
||||
if (waitpid(child_pid, &status, 0) == -1) {
|
||||
perror("wait");
|
||||
exit(1);
|
||||
exit(status);
|
||||
}
|
||||
}
|
||||
/*
|
||||
|
@ -1585,7 +1595,7 @@ int fork_it(char **argv)
|
|||
|
||||
fprintf(stderr, "%.6f sec\n", tv_delta.tv_sec + tv_delta.tv_usec/1000000.0);
|
||||
|
||||
return 0;
|
||||
return status;
|
||||
}
|
||||
|
||||
void cmdline(int argc, char **argv)
|
||||
|
@ -1594,7 +1604,7 @@ void cmdline(int argc, char **argv)
|
|||
|
||||
progname = argv[0];
|
||||
|
||||
while ((opt = getopt(argc, argv, "+pPSvisc:sC:m:M:")) != -1) {
|
||||
while ((opt = getopt(argc, argv, "+pPSvi:sc:sC:m:M:")) != -1) {
|
||||
switch (opt) {
|
||||
case 'p':
|
||||
show_core_only++;
|
||||
|
|
|
@ -1740,8 +1740,10 @@ sub install {
|
|||
open(IN, "$output_config") or dodie("Can't read config file");
|
||||
while (<IN>) {
|
||||
if (/CONFIG_MODULES(=y)?/) {
|
||||
$install_mods = 1 if (defined($1));
|
||||
last;
|
||||
if (defined($1)) {
|
||||
$install_mods = 1;
|
||||
last;
|
||||
}
|
||||
}
|
||||
}
|
||||
close(IN);
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
TARGETS = breakpoints kcmp mqueue vm cpu-hotplug memory-hotplug epoll
|
||||
TARGETS = breakpoints kcmp mqueue vm cpu-hotplug memory-hotplug
|
||||
|
||||
all:
|
||||
for TARGET in $(TARGETS); do \
|
||||
|
|
|
@ -1,11 +0,0 @@
|
|||
# Makefile for epoll selftests
|
||||
|
||||
all: test_epoll
|
||||
%: %.c
|
||||
gcc -pthread -g -o $@ $^
|
||||
|
||||
run_tests: all
|
||||
./test_epoll
|
||||
|
||||
clean:
|
||||
$(RM) test_epoll
|
|
@ -1,344 +0,0 @@
|
|||
/*
|
||||
* tools/testing/selftests/epoll/test_epoll.c
|
||||
*
|
||||
* Copyright 2012 Adobe Systems Incorporated
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Paton J. Lewis <palewis@adobe.com>
|
||||
*
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <pthread.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/epoll.h>
|
||||
#include <sys/socket.h>
|
||||
|
||||
/*
|
||||
* A pointer to an epoll_item_private structure will be stored in the epoll
|
||||
* item's event structure so that we can get access to the epoll_item_private
|
||||
* data after calling epoll_wait:
|
||||
*/
|
||||
struct epoll_item_private {
|
||||
int index; /* Position of this struct within the epoll_items array. */
|
||||
int fd;
|
||||
uint32_t events;
|
||||
pthread_mutex_t mutex; /* Guards the following variables... */
|
||||
int stop;
|
||||
int status; /* Stores any error encountered while handling item. */
|
||||
/* The following variable allows us to test whether we have encountered
|
||||
a problem while attempting to cancel and delete the associated
|
||||
event. When the test program exits, 'deleted' should be exactly
|
||||
one. If it is greater than one, then the failed test reflects a real
|
||||
world situation where we would have tried to access the epoll item's
|
||||
private data after deleting it: */
|
||||
int deleted;
|
||||
};
|
||||
|
||||
struct epoll_item_private *epoll_items;
|
||||
|
||||
/*
|
||||
* Delete the specified item from the epoll set. In a real-world secneario this
|
||||
* is where we would free the associated data structure, but in this testing
|
||||
* environment we retain the structure so that we can test for double-deletion:
|
||||
*/
|
||||
void delete_item(int index)
|
||||
{
|
||||
__sync_fetch_and_add(&epoll_items[index].deleted, 1);
|
||||
}
|
||||
|
||||
/*
|
||||
* A pointer to a read_thread_data structure will be passed as the argument to
|
||||
* each read thread:
|
||||
*/
|
||||
struct read_thread_data {
|
||||
int stop;
|
||||
int status; /* Indicates any error encountered by the read thread. */
|
||||
int epoll_set;
|
||||
};
|
||||
|
||||
/*
|
||||
* The function executed by the read threads:
|
||||
*/
|
||||
void *read_thread_function(void *function_data)
|
||||
{
|
||||
struct read_thread_data *thread_data =
|
||||
(struct read_thread_data *)function_data;
|
||||
struct epoll_event event_data;
|
||||
struct epoll_item_private *item_data;
|
||||
char socket_data;
|
||||
|
||||
/* Handle events until we encounter an error or this thread's 'stop'
|
||||
condition is set: */
|
||||
while (1) {
|
||||
int result = epoll_wait(thread_data->epoll_set,
|
||||
&event_data,
|
||||
1, /* Number of desired events */
|
||||
1000); /* Timeout in ms */
|
||||
if (result < 0) {
|
||||
/* Breakpoints signal all threads. Ignore that while
|
||||
debugging: */
|
||||
if (errno == EINTR)
|
||||
continue;
|
||||
thread_data->status = errno;
|
||||
return 0;
|
||||
} else if (thread_data->stop)
|
||||
return 0;
|
||||
else if (result == 0) /* Timeout */
|
||||
continue;
|
||||
|
||||
/* We need the mutex here because checking for the stop
|
||||
condition and re-enabling the epoll item need to be done
|
||||
together as one atomic operation when EPOLL_CTL_DISABLE is
|
||||
available: */
|
||||
item_data = (struct epoll_item_private *)event_data.data.ptr;
|
||||
pthread_mutex_lock(&item_data->mutex);
|
||||
|
||||
/* Remove the item from the epoll set if we want to stop
|
||||
handling that event: */
|
||||
if (item_data->stop)
|
||||
delete_item(item_data->index);
|
||||
else {
|
||||
/* Clear the data that was written to the other end of
|
||||
our non-blocking socket: */
|
||||
do {
|
||||
if (read(item_data->fd, &socket_data, 1) < 1) {
|
||||
if ((errno == EAGAIN) ||
|
||||
(errno == EWOULDBLOCK))
|
||||
break;
|
||||
else
|
||||
goto error_unlock;
|
||||
}
|
||||
} while (item_data->events & EPOLLET);
|
||||
|
||||
/* The item was one-shot, so re-enable it: */
|
||||
event_data.events = item_data->events;
|
||||
if (epoll_ctl(thread_data->epoll_set,
|
||||
EPOLL_CTL_MOD,
|
||||
item_data->fd,
|
||||
&event_data) < 0)
|
||||
goto error_unlock;
|
||||
}
|
||||
|
||||
pthread_mutex_unlock(&item_data->mutex);
|
||||
}
|
||||
|
||||
error_unlock:
|
||||
thread_data->status = item_data->status = errno;
|
||||
pthread_mutex_unlock(&item_data->mutex);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* A pointer to a write_thread_data structure will be passed as the argument to
|
||||
* the write thread:
|
||||
*/
|
||||
struct write_thread_data {
|
||||
int stop;
|
||||
int status; /* Indicates any error encountered by the write thread. */
|
||||
int n_fds;
|
||||
int *fds;
|
||||
};
|
||||
|
||||
/*
|
||||
* The function executed by the write thread. It writes a single byte to each
|
||||
* socket in turn until the stop condition for this thread is set. If writing to
|
||||
* a socket would block (i.e. errno was EAGAIN), we leave that socket alone for
|
||||
* the moment and just move on to the next socket in the list. We don't care
|
||||
* about the order in which we deliver events to the epoll set. In fact we don't
|
||||
* care about the data we're writing to the pipes at all; we just want to
|
||||
* trigger epoll events:
|
||||
*/
|
||||
void *write_thread_function(void *function_data)
|
||||
{
|
||||
const char data = 'X';
|
||||
int index;
|
||||
struct write_thread_data *thread_data =
|
||||
(struct write_thread_data *)function_data;
|
||||
while (!write_thread_data->stop)
|
||||
for (index = 0;
|
||||
!thread_data->stop && (index < thread_data->n_fds);
|
||||
++index)
|
||||
if ((write(thread_data->fds[index], &data, 1) < 1) &&
|
||||
(errno != EAGAIN) &&
|
||||
(errno != EWOULDBLOCK)) {
|
||||
write_thread_data->status = errno;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Arguments are currently ignored:
|
||||
*/
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
const int n_read_threads = 100;
|
||||
const int n_epoll_items = 500;
|
||||
int index;
|
||||
int epoll_set = epoll_create1(0);
|
||||
struct write_thread_data write_thread_data = {
|
||||
0, 0, n_epoll_items, malloc(n_epoll_items * sizeof(int))
|
||||
};
|
||||
struct read_thread_data *read_thread_data =
|
||||
malloc(n_read_threads * sizeof(struct read_thread_data));
|
||||
pthread_t *read_threads = malloc(n_read_threads * sizeof(pthread_t));
|
||||
pthread_t write_thread;
|
||||
|
||||
printf("-----------------\n");
|
||||
printf("Runing test_epoll\n");
|
||||
printf("-----------------\n");
|
||||
|
||||
epoll_items = malloc(n_epoll_items * sizeof(struct epoll_item_private));
|
||||
|
||||
if (epoll_set < 0 || epoll_items == 0 || write_thread_data.fds == 0 ||
|
||||
read_thread_data == 0 || read_threads == 0)
|
||||
goto error;
|
||||
|
||||
if (sysconf(_SC_NPROCESSORS_ONLN) < 2) {
|
||||
printf("Error: please run this test on a multi-core system.\n");
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* Create the socket pairs and epoll items: */
|
||||
for (index = 0; index < n_epoll_items; ++index) {
|
||||
int socket_pair[2];
|
||||
struct epoll_event event_data;
|
||||
if (socketpair(AF_UNIX,
|
||||
SOCK_STREAM | SOCK_NONBLOCK,
|
||||
0,
|
||||
socket_pair) < 0)
|
||||
goto error;
|
||||
write_thread_data.fds[index] = socket_pair[0];
|
||||
epoll_items[index].index = index;
|
||||
epoll_items[index].fd = socket_pair[1];
|
||||
if (pthread_mutex_init(&epoll_items[index].mutex, NULL) != 0)
|
||||
goto error;
|
||||
/* We always use EPOLLONESHOT because this test is currently
|
||||
structured to demonstrate the need for EPOLL_CTL_DISABLE,
|
||||
which only produces useful information in the EPOLLONESHOT
|
||||
case (without EPOLLONESHOT, calling epoll_ctl with
|
||||
EPOLL_CTL_DISABLE will never return EBUSY). If support for
|
||||
testing events without EPOLLONESHOT is desired, it should
|
||||
probably be implemented in a separate unit test. */
|
||||
epoll_items[index].events = EPOLLIN | EPOLLONESHOT;
|
||||
if (index < n_epoll_items / 2)
|
||||
epoll_items[index].events |= EPOLLET;
|
||||
epoll_items[index].stop = 0;
|
||||
epoll_items[index].status = 0;
|
||||
epoll_items[index].deleted = 0;
|
||||
event_data.events = epoll_items[index].events;
|
||||
event_data.data.ptr = &epoll_items[index];
|
||||
if (epoll_ctl(epoll_set,
|
||||
EPOLL_CTL_ADD,
|
||||
epoll_items[index].fd,
|
||||
&event_data) < 0)
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* Create and start the read threads: */
|
||||
for (index = 0; index < n_read_threads; ++index) {
|
||||
read_thread_data[index].stop = 0;
|
||||
read_thread_data[index].status = 0;
|
||||
read_thread_data[index].epoll_set = epoll_set;
|
||||
if (pthread_create(&read_threads[index],
|
||||
NULL,
|
||||
read_thread_function,
|
||||
&read_thread_data[index]) != 0)
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (pthread_create(&write_thread,
|
||||
NULL,
|
||||
write_thread_function,
|
||||
&write_thread_data) != 0)
|
||||
goto error;
|
||||
|
||||
/* Cancel all event pollers: */
|
||||
#ifdef EPOLL_CTL_DISABLE
|
||||
for (index = 0; index < n_epoll_items; ++index) {
|
||||
pthread_mutex_lock(&epoll_items[index].mutex);
|
||||
++epoll_items[index].stop;
|
||||
if (epoll_ctl(epoll_set,
|
||||
EPOLL_CTL_DISABLE,
|
||||
epoll_items[index].fd,
|
||||
NULL) == 0)
|
||||
delete_item(index);
|
||||
else if (errno != EBUSY) {
|
||||
pthread_mutex_unlock(&epoll_items[index].mutex);
|
||||
goto error;
|
||||
}
|
||||
/* EBUSY means events were being handled; allow the other thread
|
||||
to delete the item. */
|
||||
pthread_mutex_unlock(&epoll_items[index].mutex);
|
||||
}
|
||||
#else
|
||||
for (index = 0; index < n_epoll_items; ++index) {
|
||||
pthread_mutex_lock(&epoll_items[index].mutex);
|
||||
++epoll_items[index].stop;
|
||||
pthread_mutex_unlock(&epoll_items[index].mutex);
|
||||
/* Wait in case a thread running read_thread_function is
|
||||
currently executing code between epoll_wait and
|
||||
pthread_mutex_lock with this item. Note that a longer delay
|
||||
would make double-deletion less likely (at the expense of
|
||||
performance), but there is no guarantee that any delay would
|
||||
ever be sufficient. Note also that we delete all event
|
||||
pollers at once for testing purposes, but in a real-world
|
||||
environment we are likely to want to be able to cancel event
|
||||
pollers at arbitrary times. Therefore we can't improve this
|
||||
situation by just splitting this loop into two loops
|
||||
(i.e. signal 'stop' for all items, sleep, and then delete all
|
||||
items). We also can't fix the problem via EPOLL_CTL_DEL
|
||||
because that command can't prevent the case where some other
|
||||
thread is executing read_thread_function within the region
|
||||
mentioned above: */
|
||||
usleep(1);
|
||||
pthread_mutex_lock(&epoll_items[index].mutex);
|
||||
if (!epoll_items[index].deleted)
|
||||
delete_item(index);
|
||||
pthread_mutex_unlock(&epoll_items[index].mutex);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Shut down the read threads: */
|
||||
for (index = 0; index < n_read_threads; ++index)
|
||||
__sync_fetch_and_add(&read_thread_data[index].stop, 1);
|
||||
for (index = 0; index < n_read_threads; ++index) {
|
||||
if (pthread_join(read_threads[index], NULL) != 0)
|
||||
goto error;
|
||||
if (read_thread_data[index].status)
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* Shut down the write thread: */
|
||||
__sync_fetch_and_add(&write_thread_data.stop, 1);
|
||||
if ((pthread_join(write_thread, NULL) != 0) || write_thread_data.status)
|
||||
goto error;
|
||||
|
||||
/* Check for final error conditions: */
|
||||
for (index = 0; index < n_epoll_items; ++index) {
|
||||
if (epoll_items[index].status != 0)
|
||||
goto error;
|
||||
if (pthread_mutex_destroy(&epoll_items[index].mutex) < 0)
|
||||
goto error;
|
||||
}
|
||||
for (index = 0; index < n_epoll_items; ++index)
|
||||
if (epoll_items[index].deleted != 1) {
|
||||
printf("Error: item data deleted %1d times.\n",
|
||||
epoll_items[index].deleted);
|
||||
goto error;
|
||||
}
|
||||
|
||||
printf("[PASS]\n");
|
||||
return 0;
|
||||
|
||||
error:
|
||||
printf("[FAIL]\n");
|
||||
return errno;
|
||||
}
|
|
@ -35,7 +35,7 @@
|
|||
#include <sys/mount.h>
|
||||
#include <sys/statfs.h>
|
||||
#include "../../include/uapi/linux/magic.h"
|
||||
#include "../../include/linux/kernel-page-flags.h"
|
||||
#include "../../include/uapi/linux/kernel-page-flags.h"
|
||||
|
||||
|
||||
#ifndef MAX_PATH
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue