Commit 3fef97c6 authored by Philippe Gerum's avatar Philippe Gerum
Browse files

lib: convert to HM diagnostic messages



Since ABI 23, the core is able to channel T_WOSS, T_WOLI and T_WOSX
error notifications through the offender's observable component if
present.

Convert all SIGDEBUG_xxx cause codes to the new EVL_HMDIAG_xxx naming,
so that we have a single nomenclature for these errors regardless of
whether threads are notified via SIGDEBUG or their observable
component.

The API rev. is bumped to #17 as a result of these changes.
Signed-off-by: Philippe Gerum's avatarPhilippe Gerum <rpm@xenomai.org>
parent f27fc993
......@@ -891,17 +891,17 @@ static void sigdebug_handler(int sig, siginfo_t *si, void *context)
{
if (sigdebug_marked(si)) {
switch (sigdebug_cause(si)) {
case SIGDEBUG_MIGRATE_SIGNAL:
case SIGDEBUG_MIGRATE_SYSCALL:
case SIGDEBUG_MIGRATE_FAULT:
case SIGDEBUG_MIGRATE_PRIOINV:
case EVL_HMDIAG_SIGDEMOTE:
case EVL_HMDIAG_SYSDEMOTE:
case EVL_HMDIAG_EXDEMOTE:
case EVL_HMDIAG_LKDEPEND:
spurious_inband_switches++;
if (abort_on_switch)
kill(getpid(), SIGHUP);
break;
case SIGDEBUG_WATCHDOG:
case SIGDEBUG_MUTEX_IMBALANCE:
case SIGDEBUG_MUTEX_SLEEP:
case EVL_HMDIAG_WATCHDOG:
case EVL_HMDIAG_LKIMBALANCE:
case EVL_HMDIAG_LKSLEEP:
default:
exit(99);
}
......
......@@ -20,7 +20,7 @@
#include <evl/poll.h>
#include <evl/proxy.h>
#define __EVL__ 16 /* API version */
#define __EVL__ 17 /* API version */
#define EVL_ABI_PREREQ 23
......
......@@ -148,14 +148,14 @@ fail:
} while (0)
static const char *sigdebug_msg[] = {
[SIGDEBUG_MIGRATE_SIGNAL] = "switched inband (signal)\n",
[SIGDEBUG_MIGRATE_SYSCALL] = "switched inband (syscall)\n",
[SIGDEBUG_MIGRATE_FAULT] = "switched inband (fault)\n",
[SIGDEBUG_MIGRATE_PRIOINV] = "switched inband while holding mutex\n",
[SIGDEBUG_WATCHDOG] = "watchdog triggered\n",
[SIGDEBUG_MUTEX_IMBALANCE] = "mutex lock/unlock imbalance\n",
[SIGDEBUG_MUTEX_SLEEP] = "attempt to sleep while holding a mutex\n",
[SIGDEBUG_STAGE_LOCKED] = "locked out from out-of-band stage (stax)\n",
[EVL_HMDIAG_SIGDEMOTE] = "switched inband (signal)\n",
[EVL_HMDIAG_SYSDEMOTE] = "switched inband (syscall)\n",
[EVL_HMDIAG_EXDEMOTE] = "switched inband (fault)\n",
[EVL_HMDIAG_LKDEPEND] = "switched inband while holding mutex\n",
[EVL_HMDIAG_WATCHDOG] = "watchdog triggered\n",
[EVL_HMDIAG_LKIMBALANCE] = "mutex lock/unlock imbalance\n",
[EVL_HMDIAG_LKSLEEP] = "attempt to sleep while holding a mutex\n",
[EVL_HMDIAG_STAGEX] = "locked out from out-of-band stage (stax)\n",
};
/* A basic SIGDEBUG handler which only prints out the cause. */
......@@ -164,14 +164,14 @@ void evl_sigdebug_handler(int sig, siginfo_t *si, void *ctxt)
{
if (sigdebug_marked(si)) {
switch (sigdebug_cause(si)) {
case SIGDEBUG_MIGRATE_SIGNAL:
case SIGDEBUG_MIGRATE_SYSCALL:
case SIGDEBUG_MIGRATE_FAULT:
case SIGDEBUG_MIGRATE_PRIOINV:
case SIGDEBUG_WATCHDOG:
case SIGDEBUG_MUTEX_IMBALANCE:
case SIGDEBUG_MUTEX_SLEEP:
case SIGDEBUG_STAGE_LOCKED:
case EVL_HMDIAG_SIGDEMOTE:
case EVL_HMDIAG_SYSDEMOTE:
case EVL_HMDIAG_EXDEMOTE:
case EVL_HMDIAG_LKDEPEND:
case EVL_HMDIAG_WATCHDOG:
case EVL_HMDIAG_LKIMBALANCE:
case EVL_HMDIAG_LKSLEEP:
case EVL_HMDIAG_STAGEX:
raw_write_out(sigdebug_msg[sigdebug_cause(si)]);
break;
}
......
......@@ -7,7 +7,7 @@
* follows a plain fork() [and no exec()]. If that action unexpectedly
* triggers a FPU trap for which a transition to inband mode is
* required, we would be notified via the SIGDEBUG handler (cause ==
* SIGDEBUG_MIGRATE_FAULT).
* EVL_HMDIAG_EXDEMOTE).
*/
#include <sys/types.h>
......
/*
* SPDX-License-Identifier: MIT
*/
#include <sys/types.h>
#include <unistd.h>
#include <signal.h>
#include <sched.h>
#include <pthread.h>
#include <errno.h>
#include <evl/thread.h>
#include <evl/observable.h>
#include "helpers.h"
static void sigdebug_handler(int sig, siginfo_t *si, void *context)
{
__Texpr_assert(0); /* Bummer. */
}
int main(int argc, char *argv[])
{
struct __evl_notification _nf;
struct evl_notification nf;
struct sched_param param;
struct sigaction sa;
int oldmask, tfd;
ssize_t ret;
/* Install a handler for a signal we don't want to receive. */
sigemptyset(&sa.sa_mask);
sa.sa_sigaction = sigdebug_handler;
sa.sa_flags = SA_SIGINFO;
sigaction(SIGDEBUG, &sa, NULL);
param.sched_priority = 1;
__Texpr_assert(pthread_setschedparam(pthread_self(),
SCHED_FIFO, &param) == 0);
__Tcall_assert(tfd, evl_attach_thread(EVL_CLONE_OBSERVABLE|EVL_CLONE_NONBLOCK,
"observable-hm:%d", getpid()));
__Fcall_assert(ret, evl_read_observable(tfd, &nf, 1));
__Texpr_assert(ret == -ENXIO);
/* Introspection: monitor ourselves for HM events. */
__Tcall_assert(ret, evl_subscribe(tfd, 16, 0));
/* Enable stage switch notifications only via observable. */
__Tcall_assert(ret, evl_set_thread_mode(tfd, T_WOSS|T_HMOBS, &oldmask));
__Texpr_assert(oldmask == 0);
/*
* We are still in-band in the wake of evl_subscribe(), switch
* oob. Don't do that in your apps, this is most often useless
* since the core switches threads to the right stage. We need
* that only for the purpose of checking how the core behaves.
*/
__Tcall_assert(ret, evl_switch_oob());
/*
* Hack: we ask for the next pending notification from our HM
* queue using an in-band read() syscall, which should switch
* us in-band and trigger the notification we expect about
* having been demoted in the same move. We can only do that
* via the internal interface, since evl_read_observable()
* would use oob_read() instead. For the purpose of testing
* only, you should you really not do that in your apps.
*/
__Tcall_errno_assert(ret, read(tfd, &_nf, sizeof(_nf)));
__Texpr_assert(_nf.tag == EVL_HMDIAG_SYSDEMOTE);
/* Nothing else afterwards. */
__Fcall_assert(ret, evl_read_observable(tfd, &nf, 1));
__Texpr_assert(ret == -EAGAIN);
return 0;
}
/*
* SPDX-License-Identifier: MIT
*
* Make sure we receive SIGDEBUG_STAGE_LOCKED when locked out from the
* Make sure we receive EVL_HMDIAG_STAGEX when locked out from the
* out-of-band stage because of a stax-based serialization.
*/
......@@ -26,7 +26,7 @@ static volatile sig_atomic_t notified;
static void sigdebug_handler(int sig, siginfo_t *si, void *context)
{
if (sigdebug_marked(si) &&
sigdebug_cause(si) == SIGDEBUG_STAGE_LOCKED) {
sigdebug_cause(si) == EVL_HMDIAG_STAGEX) {
notified = true;
return;
}
......
......@@ -26,11 +26,25 @@ int main(int argc, char *argv[])
__Tcall_assert(ret, evl_set_thread_mode(tfd, T_WOSS|T_WOLI|T_WOSX, &oldmask));
__Texpr_assert(oldmask == 0);
__Tcall_assert(ret, evl_set_thread_mode(tfd, 0, &oldmask));
__Texpr_assert(oldmask == (T_WOSS|T_WOLI|T_WOSX));
__Texpr_assert(oldmask == (T_WOSS|T_WOLI|T_WOSX|T_HMSIG));
__Tcall_assert(ret, evl_clear_thread_mode(tfd, T_WOSS, &oldmask));
__Texpr_assert(oldmask == (T_WOSS|T_WOLI|T_WOSX));
__Texpr_assert(oldmask == (T_WOSS|T_WOLI|T_WOSX|T_HMSIG));
__Tcall_assert(ret, evl_clear_thread_mode(tfd, T_WOLI|T_WOSX, &oldmask));
__Texpr_assert(oldmask == (T_WOLI|T_WOSX));
__Texpr_assert(oldmask == (T_WOLI|T_WOSX|T_HMSIG));
__Fcall_assert(ret, evl_set_thread_mode(tfd, T_WOSS|T_WOLI|T_WOSX|T_HMOBS, &oldmask));
__Texpr_assert(ret == -EINVAL); /* T_HMOBS should fail if self is !observable */
__Tcall_assert(ret, evl_detach_self());
__Tcall_assert(tfd, evl_attach_thread(EVL_CLONE_OBSERVABLE,
"thread-mode-bits:%d", getpid()));
__Tcall_assert(ret, evl_set_thread_mode(tfd, T_WOSS|T_WOLI|T_WOSX|T_HMOBS, &oldmask));
__Texpr_assert(oldmask == 0);
__Tcall_assert(ret, evl_set_thread_mode(tfd, T_HMSIG, &oldmask));
__Texpr_assert(oldmask == (T_WOSS|T_WOLI|T_WOSX|T_HMOBS));
__Tcall_assert(ret, evl_clear_thread_mode(tfd, T_HMSIG|T_HMOBS, &oldmask));
__Tcall_assert(ret, evl_set_thread_mode(tfd, 0, &oldmask));
__Texpr_assert(oldmask == 0);
__Tcall_assert(ret, evl_set_thread_mode(tfd, 0, NULL));
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment