mirror of
https://github.com/ElementsProject/lightning.git
synced 2024-11-19 09:54:16 +01:00
d5cb0d85b5
We force use of tal_wally_start/tal_wally_end around every wally allocation, and with "end" make the caller choose where to reparent everything. This is particularly powerful where we allocate a tx or a psbt: we want that tx or psbt to be the parent of the other allocations, so this way we can reparent the tx or psbt, then reparent everything else onto it. Implementing psbt_finalize (which uses a behavior flag antipattern) was tricky, so I ended up splitting that into 'psbt_finalize' and 'psbt_final_tx', which I think also makes the callers clearer. Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
179 lines
4.1 KiB
C
179 lines
4.1 KiB
C
#include <assert.h>
|
|
#include <backtrace-supported.h>
|
|
#include <backtrace.h>
|
|
#include <ccan/err/err.h>
|
|
#include <ccan/io/io.h>
|
|
#include <ccan/str/str.h>
|
|
#include <ccan/tal/str/str.h>
|
|
#include <common/daemon.h>
|
|
#include <common/memleak.h>
|
|
#include <common/setup.h>
|
|
#include <common/status.h>
|
|
#include <common/utils.h>
|
|
#include <common/version.h>
|
|
#include <signal.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <sys/types.h>
|
|
#include <unistd.h>
|
|
|
|
#if BACKTRACE_SUPPORTED
|
|
static void (*bt_print)(const char *fmt, ...) PRINTF_FMT(1,2);
|
|
static void (*bt_exit)(void);
|
|
|
|
static int backtrace_status(void *unused UNUSED, uintptr_t pc,
|
|
const char *filename, int lineno,
|
|
const char *function)
|
|
{
|
|
bt_print("backtrace: %s:%d (%s) %p",
|
|
filename, lineno, function, (void *)pc);
|
|
return 0;
|
|
}
|
|
|
|
void send_backtrace(const char *why)
|
|
{
|
|
/* We do stderr first, since it's most reliable. */
|
|
warnx("%s (version %s)", why, version());
|
|
if (backtrace_state)
|
|
backtrace_print(backtrace_state, 0, stderr);
|
|
|
|
/* Now send to parent. */
|
|
bt_print("%s (version %s)", why, version());
|
|
if (backtrace_state)
|
|
backtrace_full(backtrace_state, 0, backtrace_status, NULL, NULL);
|
|
}
|
|
|
|
static void crashdump(int sig)
|
|
{
|
|
char why[100];
|
|
|
|
snprintf(why, 100, "FATAL SIGNAL %d", sig);
|
|
send_backtrace(why);
|
|
|
|
/* Probably shouldn't return. */
|
|
bt_exit();
|
|
|
|
/* This time it will kill us instantly. */
|
|
kill(getpid(), sig);
|
|
}
|
|
|
|
static void crashlog_activate(void)
|
|
{
|
|
struct sigaction sa;
|
|
|
|
sa.sa_handler = crashdump;
|
|
sigemptyset(&sa.sa_mask);
|
|
|
|
/* We want to fall through to default handler */
|
|
sa.sa_flags = SA_RESETHAND;
|
|
sigaction(SIGILL, &sa, NULL);
|
|
sigaction(SIGABRT, &sa, NULL);
|
|
sigaction(SIGFPE, &sa, NULL);
|
|
sigaction(SIGSEGV, &sa, NULL);
|
|
sigaction(SIGBUS, &sa, NULL);
|
|
}
|
|
#else
|
|
void send_backtrace(const char *why)
|
|
{
|
|
}
|
|
#endif
|
|
|
|
int daemon_poll(struct pollfd *fds, nfds_t nfds, int timeout)
|
|
{
|
|
const char *t;
|
|
|
|
t = taken_any();
|
|
if (t)
|
|
errx(1, "Outstanding taken pointers: %s", t);
|
|
|
|
if (wally_tal_ctx)
|
|
errx(1, "Outstanding tal_wally_start!");
|
|
|
|
clean_tmpctx();
|
|
|
|
return poll(fds, nfds, timeout);
|
|
}
|
|
|
|
#if DEVELOPER && BACKTRACE_SUPPORTED
|
|
static void steal_notify(tal_t *child, enum tal_notify_type n, tal_t *newparent)
|
|
{
|
|
tal_t *p = newparent;
|
|
|
|
assert(tal_parent(child) == newparent);
|
|
while ((p = tal_parent(p)) != NULL)
|
|
assert(p != child);
|
|
}
|
|
|
|
static void add_steal_notifier(tal_t *parent UNUSED,
|
|
enum tal_notify_type type UNNEEDED,
|
|
void *child)
|
|
{
|
|
tal_add_notifier(child, TAL_NOTIFY_ADD_CHILD, add_steal_notifier);
|
|
tal_add_notifier(child, TAL_NOTIFY_STEAL, steal_notify);
|
|
}
|
|
|
|
static void add_steal_notifiers(const tal_t *root)
|
|
{
|
|
tal_add_notifier(root, TAL_NOTIFY_ADD_CHILD, add_steal_notifier);
|
|
|
|
for (const tal_t *i = tal_first(root); i; i = tal_next(i))
|
|
add_steal_notifiers(i);
|
|
}
|
|
#endif
|
|
|
|
void daemon_setup(const char *argv0,
|
|
void (*backtrace_print)(const char *fmt, ...),
|
|
void (*backtrace_exit)(void))
|
|
{
|
|
common_setup(argv0);
|
|
#if BACKTRACE_SUPPORTED
|
|
bt_print = backtrace_print;
|
|
bt_exit = backtrace_exit;
|
|
#if DEVELOPER
|
|
/* Suppresses backtrace (breaks valgrind) */
|
|
if (!getenv("LIGHTNINGD_DEV_NO_BACKTRACE"))
|
|
backtrace_state = backtrace_create_state(argv0, 0, NULL, NULL);
|
|
add_steal_notifiers(NULL);
|
|
#else
|
|
backtrace_state = backtrace_create_state(argv0, 0, NULL, NULL);
|
|
#endif
|
|
crashlog_activate();
|
|
#endif
|
|
|
|
#if DEVELOPER
|
|
/* This has significant overhead, so we only enable it if told */
|
|
if (getenv("LIGHTNINGD_DEV_MEMLEAK"))
|
|
memleak_init();
|
|
#endif
|
|
|
|
/* We handle write returning errors! */
|
|
signal(SIGPIPE, SIG_IGN);
|
|
|
|
io_poll_override(daemon_poll);
|
|
}
|
|
|
|
void daemon_shutdown(void)
|
|
{
|
|
common_shutdown();
|
|
}
|
|
|
|
void daemon_maybe_debug(char *argv[])
|
|
{
|
|
#if DEVELOPER
|
|
for (int i = 1; argv[i]; i++) {
|
|
if (!streq(argv[i], "--debugger"))
|
|
continue;
|
|
|
|
/* Don't let this mess up stdout, so redir to /dev/null */
|
|
char *cmd = tal_fmt(NULL, "${DEBUG_TERM:-gnome-terminal --} gdb -ex 'attach %u' %s >/dev/null &", getpid(), argv[0]);
|
|
fprintf(stderr, "Running %s\n", cmd);
|
|
/* warn_unused_result is fascist bullshit.
|
|
* https://gcc.gnu.org/bugzilla/show_bug.cgi?id=66425 */
|
|
if (system(cmd))
|
|
;
|
|
/* Continue in the debugger. */
|
|
kill(getpid(), SIGSTOP);
|
|
}
|
|
#endif /* DEVELOPER */
|
|
}
|