test: set up a timer to trigger SIGALRM

Xwayland uses a timer for the scheduler which means any of our syscalls
can trigger EINTR. Let's make sure we may catch bugs related to that by
setting up our test suite to hammer us with timers.

Can't guarantee this will trigger all bugs but over time it may help or
at least ensure that the low-hanging fruit are all fixed.
This commit is contained in:
Peter Hutterer 2023-10-18 12:54:59 +10:00
parent f558eedae2
commit 05d79f6e58
2 changed files with 86 additions and 11 deletions

View file

@ -25,9 +25,11 @@
#include "config.h"
#include <math.h>
#include <signal.h>
#include <stdlib.h>
#include <stdio.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <munit.h>
@ -35,13 +37,17 @@
#include "util-bits.h"
#include "util-color.h"
#include "util-io.h"
#include "util-mem.h"
#include "util-munit.h"
#include "util-tristate.h"
#include "util-logger.h"
#include "util-object.h"
#include "util-strings.h"
#include "util-time.h"
static bool enable_sigalarm;
DEFINE_TRISTATE(yes, no, unset);
struct peck {
@ -75,6 +81,8 @@ struct peck {
struct eis_client *eis_client;
uint32_t indent;
struct sigaction sigact;
};
static const uint32_t INDENTATION = 4;
@ -128,6 +136,12 @@ peck_destroy(struct peck *peck)
ei_unref(peck->ei);
eis_unref(peck->eis);
logger_unref(peck->logger);
if (enable_sigalarm) {
struct itimerval timer = {0};
setitimer(ITIMER_REAL, &timer, 0);
sigaction(SIGALRM, &peck->sigact, NULL);
}
}
static
@ -370,6 +384,12 @@ peck_log_handler(struct logger *logger,
fprintf(stderr, "%s", ansi_colorcode[RESET]);
}
static void
handle_sigalrm(int signo)
{
/* Nothing to do but this may cause a few EINTR */
}
static struct peck *
new_context(enum peck_ei_mode ei_mode)
{
@ -408,6 +428,36 @@ new_context(enum peck_ei_mode ei_mode)
logger_set_handler(peck->logger, peck_log_handler);
logger_set_priority(peck->logger, LOGGER_DEBUG);
if (enable_sigalarm) {
/* We set up SIGALRM to hammer us because libei is used by Xwayland which
* uses that for scheduling and we need to be able to handle that */
struct sigaction act;
sigaddset(&act.sa_mask, SIGALRM);
act.sa_flags = 0;
act.sa_handler = handle_sigalrm;
rc = xerrno(sigaction(SIGALRM, &act, &peck->sigact));
if (rc >= 0) {
struct itimerval timer = {
.it_interval = {
.tv_sec = 0,
.tv_usec = 5,
},
.it_value = {
.tv_sec = 0,
.tv_usec = 5,
}
};
rc = xerrno(setitimer(ITIMER_REAL, &timer, 0));
if (rc < 0) {
log_error(peck, "Failed to enable timer: %s\n", strerror(-rc));
munit_assert_int(rc, >=, 0);
}
} else {
log_error(peck, "Failed to enable SIGALRM: %s\n", strerror(-rc));
munit_assert_int(rc, >=, 0);
}
}
return peck;
}
@ -1307,3 +1357,20 @@ _peck_mark(struct peck *peck, const char *func, int line)
static uint32_t mark = 0;
log_debug(peck, "mark %3d: line %d in %s()\n", mark++, line, func);
}
MUNIT_GLOBAL_SETUP(init_sigalarm)
{
int argc = setup->argc;
char **argv = setup->argv;
for (int i = 0; i < argc; i++) {
if (streq(argv[i], "--enable-sigalrm") || streq(argv[i], "--enable-sigalarm")) {
enable_sigalarm = true;
for (int j = i + 1; j < setup->argc; j++) {
setup->argv[i] = setup->argv[j];
}
setup->argc--;
break;
}
}
}

View file

@ -63,17 +63,25 @@ lib_eierpecken = static_library('eierpecken',
dependencies: [munit, dep_libutil, dep_libei, dep_libeis],
)
eierpecken = executable('eierpecken',
'test-ei-device.c',
'test-ei-seat.c',
'test-ei.c',
'test-eis.c',
'test-main.c',
link_with: lib_eierpecken,
include_directories: [inc_builddir],
dependencies: [dep_unittest, dep_libei, dep_libeis])
test('eierpecken',
executable('eierpecken',
'test-ei-device.c',
'test-ei-seat.c',
'test-ei.c',
'test-eis.c',
'test-main.c',
link_with: lib_eierpecken,
include_directories: [inc_builddir],
dependencies: [dep_unittest, dep_libei, dep_libeis]),
args: ['--log-visible', 'debug'])
eierpecken,
args: ['--log-visible', 'debug', '--enable-sigalarm'],
suite: 'sigalrm')
test('eierpecken-no-sigalrm',
eierpecken,
args: ['--log-visible', 'debug'],
suite: 'nosigalrm')
valgrind = find_program('valgrind', required : false)
if valgrind.found() and meson.version().version_compare('> 0.57')
@ -82,7 +90,7 @@ if valgrind.found() and meson.version().version_compare('> 0.57')
'--leak-check=full',
'--gen-suppressions=all',
'--error-exitcode=3' ],
exclude_suites: ['python'], # we don't want to valgrind python tests
exclude_suites: ['python', 'sigalrm'], # we don't want to valgrind python and SIGALRM tests
timeout_multiplier : 100)
else
message('valgrind not found, disabling valgrind test suite')