mirror of https://github.com/thesofproject/sof.git
logger: allow starting before the driver is loaded
Don't fail immediately when the driver is not loaded. Use inotify instead to wait for /sys/kernel/debug/sof/[e]trace to appear. This makes it possible to start before the driver is loaded which reduces considerably the chances of missing early logs. Fixes a small part of https://github.com/thesofproject/linux/issues/3275 Signed-off-by: Marc Herbert <marc.herbert@intel.com>
This commit is contained in:
parent
af6bd41a99
commit
dcf0577a77
|
@ -15,6 +15,12 @@
|
|||
#include <fcntl.h>
|
||||
#include <stdbool.h>
|
||||
#include <termios.h>
|
||||
#include <poll.h>
|
||||
#include <sys/inotify.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <dirent.h>
|
||||
|
||||
#include "convert.h"
|
||||
#include "misc.h"
|
||||
|
||||
|
@ -170,6 +176,93 @@ static int append_filter_config(struct convert_config *config, const char *input
|
|||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* This 5 minutes timeout is for "backward compatible safety" in case
|
||||
* any user/script of an earlier, pre-inotify version of sof-logger
|
||||
* (accidentally?) _expected_ the tool to quit when the driver was not
|
||||
* loaded. This expectation was always wrong but an infinite wait is too
|
||||
* severe of a punishment. This timeout cannot be too small otherwise it
|
||||
* would defeat the new feature.
|
||||
*/
|
||||
#ifndef SOF_LOGGER_WAIT_OPEN_TIMEOUT_SECS
|
||||
#define SOF_LOGGER_WAIT_OPEN_TIMEOUT_SECS (5 * 60)
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Using inotify, wait up to 5 minutes for 'expected_name' to appear in
|
||||
* 'watched_dir'. Then return opendir/fopen(expected_name). fopen() and
|
||||
* opendir() failures are NOT handled; e.g. NULL from fopen() is just
|
||||
* passed through.
|
||||
*
|
||||
* Returns a FILE * or DIR *
|
||||
*/
|
||||
static void *wait_open(const char *watched_dir, const char *expected_file)
|
||||
{
|
||||
if (access(watched_dir, R_OK)) {
|
||||
fprintf(stderr, "error: %s() cannot read %s\n", __func__, watched_dir);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const int iqueue = inotify_init();
|
||||
const int dwatch = inotify_add_watch(iqueue, watched_dir, IN_CREATE);
|
||||
struct stat expected_stat;
|
||||
void *ret_stream = NULL;
|
||||
|
||||
char * const fpath = malloc(strlen(watched_dir) + 1 + strlen(expected_file) + 1);
|
||||
|
||||
strcpy(fpath, watched_dir);
|
||||
strcat(fpath, "/");
|
||||
strcat(fpath, expected_file);
|
||||
|
||||
/* Not racy because the inotify watch was set first. */
|
||||
if (!access(fpath, F_OK))
|
||||
goto fopenit;
|
||||
|
||||
fprintf(stdout, "%s: waiting in %s/ for %s\n", APP_NAME, watched_dir, expected_file);
|
||||
fflush(stdout);
|
||||
|
||||
while (1) {
|
||||
char evlist[1 * sizeof(struct inotify_event)];
|
||||
struct pollfd pfd[1] = {{ .fd = iqueue, .events = POLLIN, .revents = 0 }};
|
||||
int pret = poll(pfd, sizeof(pfd) / sizeof(struct pollfd),
|
||||
SOF_LOGGER_WAIT_OPEN_TIMEOUT_SECS * 1000);
|
||||
|
||||
if (pret == 0) {
|
||||
fprintf(stderr, "error: no %s after waiting %d seconds\n",
|
||||
expected_file, SOF_LOGGER_WAIT_OPEN_TIMEOUT_SECS);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (pret < 0 || pfd[0].revents != POLLIN) {
|
||||
fprintf(stderr, "error: in %s, poll(%s) returned %d, %d\n",
|
||||
__func__, watched_dir, pret, pfd[0].revents);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/* Silence __attribute__((warn_unused_result)) which is
|
||||
* enabled by some Linux distros even when broken in gcc:
|
||||
* https://gcc.gnu.org/bugzilla/show_bug.cgi?id=66425
|
||||
*/
|
||||
(void)!read(iqueue, evlist, sizeof(evlist));
|
||||
|
||||
if (!access(fpath, F_OK))
|
||||
goto fopenit;
|
||||
}
|
||||
|
||||
fopenit:
|
||||
stat(fpath, &expected_stat);
|
||||
if ((expected_stat.st_mode & S_IFMT) == S_IFDIR)
|
||||
ret_stream = opendir(fpath);
|
||||
else
|
||||
ret_stream = fopen(fpath, "rb");
|
||||
|
||||
cleanup:
|
||||
free(fpath);
|
||||
inotify_rm_watch(iqueue, dwatch);
|
||||
|
||||
return ret_stream;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
static const char optstring[] = "ho:i:l:ps:c:u:tv:rd:Le:f:gF:n";
|
||||
|
@ -337,7 +430,26 @@ int main(int argc, char *argv[])
|
|||
goto out;
|
||||
}
|
||||
} else if (config.in_file) {
|
||||
config.in_fd = fopen(config.in_file, "rb");
|
||||
static const char sys_debug[] = "/sys/kernel/debug";
|
||||
static const char sys_debug_sof[] = "/sys/kernel/debug/sof";
|
||||
/* In the future we could add an option to force waiting
|
||||
* for _any_ input file, not just for /sys/kernel/debug/sof/[e]trace
|
||||
*/
|
||||
config.in_fd = NULL;
|
||||
if (strncmp(config.in_file, sys_debug, strlen(sys_debug))) {
|
||||
config.in_fd = fopen(config.in_file, "rb");
|
||||
} else {
|
||||
DIR *dbg_sof = (DIR *)wait_open(sys_debug, "sof");
|
||||
|
||||
if (dbg_sof) {
|
||||
closedir(dbg_sof);
|
||||
config.in_fd =
|
||||
(FILE *)wait_open(sys_debug_sof,
|
||||
config.in_file +
|
||||
strlen(sys_debug_sof) + 1);
|
||||
}
|
||||
}
|
||||
|
||||
if (!config.in_fd) {
|
||||
ret = errno;
|
||||
fprintf(stderr,
|
||||
|
|
Loading…
Reference in New Issue