From 6903cf2efb83d8f916a5f3482b7b1e71a2dd6527 Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Mon, 16 Feb 2026 17:39:33 +1030 Subject: [PATCH] askrene: make "child.c" to be the explicit child entry point. The fork logic itself is pretty simple, so do that directly in askrene.c, and then call into "run_child()" almost as soon as we do the fork. Signed-off-by: Rusty Russell --- plugins/askrene/Makefile | 4 +- plugins/askrene/askrene.c | 72 +++++++++++++------- plugins/askrene/child/{entry.c => child.c} | 77 ++++++---------------- plugins/askrene/child/child.h | 36 ++++++++++ plugins/askrene/child/entry.h | 35 ---------- 5 files changed, 106 insertions(+), 118 deletions(-) rename plugins/askrene/child/{entry.c => child.c} (83%) create mode 100644 plugins/askrene/child/child.h delete mode 100644 plugins/askrene/child/entry.h diff --git a/plugins/askrene/Makefile b/plugins/askrene/Makefile index d676624e8..292059112 100644 --- a/plugins/askrene/Makefile +++ b/plugins/askrene/Makefile @@ -2,10 +2,10 @@ PLUGIN_ASKRENE_PARENT_SRC := \ plugins/askrene/askrene.c \ plugins/askrene/datastore_wire.c \ plugins/askrene/layer.c \ - plugins/askrene/reserve.c \ + plugins/askrene/reserve.c PLUGIN_ASKRENE_CHILD_SRC := \ - plugins/askrene/child/entry.c \ + plugins/askrene/child/child.c \ plugins/askrene/child/mcf.c \ plugins/askrene/child/dijkstra.c \ plugins/askrene/child/flow.c \ diff --git a/plugins/askrene/askrene.c b/plugins/askrene/askrene.c index 4910b858a..a5709c127 100644 --- a/plugins/askrene/askrene.c +++ b/plugins/askrene/askrene.c @@ -8,6 +8,7 @@ */ #include "config.h" #include +#include #include #include #include @@ -24,7 +25,8 @@ #include #include #include -#include +#include +#include #include #include #include @@ -522,12 +524,11 @@ static struct command_result *do_getroutes(struct command *cmd, bool include_fees; const char *err; struct timemono deadline; - int child_fd, log_fd; + int replyfds[2], logfds[2]; struct router_child *child; const struct layer **layers; s8 *biases; fp16_t *capacities; - int ecode; /* update the gossmap */ if (gossmap_refresh(askrene->gossmap)) { @@ -625,31 +626,56 @@ static struct command_result *do_getroutes(struct command *cmd, child->start = time_mono(); deadline = timemono_add(child->start, time_from_sec(askrene->route_seconds)); - child_fd = fork_router_child(askrene->gossmap, - layers, - biases, - info->additional_costs, - askrene->reserved, - take(capacities), - info->dev_algo == ALGO_SINGLE_PATH, - deadline, srcnode, dstnode, info->amount, - info->maxfee, info->finalcltv, info->maxdelay, info->maxparts, - include_fees, - cmd->id, cmd->filter, &log_fd, &child->pid); - /* Save this, as remove_localmods won't preserve it. */ - ecode = errno; - /* We don't need this any more. */ - gossmap_remove_localmods(askrene->gossmap, localmods); - if (child_fd == -1) { - err = tal_fmt(tmpctx, "failed to fork: %s", strerror(ecode)); - gossmap_remove_localmods(askrene->gossmap, localmods); + if (pipe(replyfds) != 0) { + err = tal_fmt(tmpctx, "failed to create pipes: %s", strerror(errno)); + goto fail_broken; + } + if (pipe(logfds) != 0) { + err = tal_fmt(tmpctx, "failed to create pipes: %s", strerror(errno)); + close_noerr(replyfds[0]); + close_noerr(replyfds[1]); + goto fail_broken; + } + child->pid = fork(); + if (child->pid < 0) { + err = tal_fmt(tmpctx, "failed to fork: %s", strerror(errno)); + close_noerr(replyfds[0]); + close_noerr(replyfds[1]); + close_noerr(logfds[0]); + close_noerr(logfds[1]); goto fail_broken; } - child->reply_conn = io_new_conn(child, child_fd, + if (child->pid == 0) { + /* We are the child. Run the algo */ + close(logfds[0]); + close(replyfds[0]); + set_child_log_fd(logfds[1]); + + /* Does not return! */ + run_child(askrene->gossmap, + layers, + biases, + info->additional_costs, + askrene->reserved, + take(capacities), + info->dev_algo == ALGO_SINGLE_PATH, + deadline, srcnode, dstnode, info->amount, + info->maxfee, info->finalcltv, info->maxdelay, info->maxparts, + include_fees, + cmd->id, cmd->filter, replyfds[1]); + abort(); + } + + close(logfds[1]); + close(replyfds[1]); + + /* We don't need this any more. */ + gossmap_remove_localmods(askrene->gossmap, localmods); + child->reply_conn = io_new_conn(child, replyfds[0], child_reply_init, child); - child->log_conn = io_new_conn(child, log_fd, child_log_init, child); + child->log_conn = io_new_conn(child, logfds[0], child_log_init, child); child->cmd = cmd; list_add_tail(&askrene->children, &child->list); diff --git a/plugins/askrene/child/entry.c b/plugins/askrene/child/child.c similarity index 83% rename from plugins/askrene/child/entry.c rename to plugins/askrene/child/child.c index 92dddd1af..8a4363d5f 100644 --- a/plugins/askrene/child/entry.c +++ b/plugins/askrene/child/child.c @@ -1,18 +1,16 @@ #include "config.h" #include #include -#include #include #include #include #include #include +#include #include -#include #include #include #include -#include /* A single route. */ struct route { @@ -195,26 +193,23 @@ static struct route_query *new_route_query(const tal_t *ctx, return rq; } -/* Returns fd to child */ -int fork_router_child(const struct gossmap *gossmap, - const struct layer **layers, - const s8 *biases, - const struct additional_cost_htable *additional_costs, - struct reserve_htable *reserved, - fp16_t *capacities TAKES, - bool single_path, - struct timemono deadline, - const struct gossmap_node *srcnode, - const struct gossmap_node *dstnode, - struct amount_msat amount, struct amount_msat maxfee, - u32 finalcltv, u32 maxdelay, size_t maxparts, - bool include_fees, - const char *cmd_id, - struct json_filter *cmd_filter, - int *log_fd, - int *child_pid) +void run_child(const struct gossmap *gossmap, + const struct layer **layers, + const s8 *biases, + const struct additional_cost_htable *additional_costs, + struct reserve_htable *reserved, + fp16_t *capacities TAKES, + bool single_path, + struct timemono deadline, + const struct gossmap_node *srcnode, + const struct gossmap_node *dstnode, + struct amount_msat amount, struct amount_msat maxfee, + u32 finalcltv, u32 maxdelay, size_t maxparts, + bool include_fees, + const char *cmd_id, + struct json_filter *cmd_filter, + int replyfd) { - int replyfds[2], logfds[2]; double probability; struct flow **flows; struct route **routes; @@ -223,35 +218,6 @@ int fork_router_child(const struct gossmap *gossmap, size_t len; struct route_query *rq; - if (pipe(replyfds) != 0) - goto parent_fail; - if (pipe(logfds) != 0) { - close_noerr(replyfds[0]); - close_noerr(replyfds[1]); - goto parent_fail; - } - *child_pid = fork(); - if (*child_pid < 0) { - close_noerr(replyfds[0]); - close_noerr(replyfds[1]); - close_noerr(logfds[0]); - close_noerr(logfds[1]); - goto parent_fail; - } - if (*child_pid != 0) { - close(logfds[1]); - close(replyfds[1]); - *log_fd = logfds[0]; - if (taken(capacities)) - tal_free(capacities); - return replyfds[0]; - } - - /* We are the child. Run the algo */ - close(logfds[0]); - close(replyfds[0]); - set_child_log_fd(logfds[1]); - /* We exit below, so we don't bother freeing this */ rq = new_route_query(NULL, gossmap, cmd_id, layers, biases, additional_costs, @@ -266,7 +232,7 @@ int fork_router_child(const struct gossmap *gossmap, maxparts, &flows, &probability); } if (err) { - write_all(replyfds[1], err, strlen(err)); + write_all(replyfd, err, strlen(err)); /* Non-zero exit tells parent this is an error string. */ exit(1); } @@ -305,13 +271,8 @@ int fork_router_child(const struct gossmap *gossmap, json_stream_close(js, NULL); p = json_out_contents(js->jout, &len); - if (!write_all(replyfds[1], p, len)) + if (!write_all(replyfd, p, len)) abort(); exit(0); - -parent_fail: - if (taken(capacities)) - tal_free(capacities); - return -1; } diff --git a/plugins/askrene/child/child.h b/plugins/askrene/child/child.h new file mode 100644 index 000000000..847bda99d --- /dev/null +++ b/plugins/askrene/child/child.h @@ -0,0 +1,36 @@ +#ifndef LIGHTNING_PLUGINS_ASKRENE_CHILD_CHILD_H +#define LIGHTNING_PLUGINS_ASKRENE_CHILD_CHILD_H +#include "config.h" +#include +#include +#include +#include +#include +#include + +struct additional_cost_htable; +struct gossmap; +struct json_filter; +struct layer; +struct reserve_htable; + +/* This is the child. Do the thing. */ +void run_child(const struct gossmap *gossmap, + const struct layer **layers, + const s8 *biases, + const struct additional_cost_htable *additional_costs, + struct reserve_htable *reserved, + fp16_t *capacities TAKES, + bool single_path, + struct timemono deadline, + const struct gossmap_node *srcnode, + const struct gossmap_node *dstnode, + struct amount_msat amount, struct amount_msat maxfee, + u32 finalcltv, u32 maxdelay, size_t maxparts, + bool include_fees, + const char *cmd_id, + struct json_filter *cmd_filter, + int reply_fd) NORETURN; + +#endif /* LIGHTNING_PLUGINS_ASKRENE_CHILD_CHILD_H */ + diff --git a/plugins/askrene/child/entry.h b/plugins/askrene/child/entry.h deleted file mode 100644 index 7484b6097..000000000 --- a/plugins/askrene/child/entry.h +++ /dev/null @@ -1,35 +0,0 @@ -#ifndef LIGHTNING_PLUGINS_ASKRENE_CHILD_ENTRY_H -#define LIGHTNING_PLUGINS_ASKRENE_CHILD_ENTRY_H -#include "config.h" -#include -#include -#include -#include -#include - -struct route_query; -struct gossmap_node; -struct json_filter; -struct layer; -struct reserve_htable; -struct additional_cost_htable; - -/* Entry point to the child process. */ -int fork_router_child(const struct gossmap *gossmap, - const struct layer **layers, - const s8 *biases, - const struct additional_cost_htable *additional_costs, - struct reserve_htable *reserved, - fp16_t *capacities TAKES, - bool single_path, - struct timemono deadline, - const struct gossmap_node *srcnode, - const struct gossmap_node *dstnode, - struct amount_msat amount, struct amount_msat maxfee, - u32 finalcltv, u32 maxdelay, size_t maxparts, - bool include_fees, - const char *cmd_id, - struct json_filter *cmd_filter, - int *log_fd, - int *child_pid); -#endif /* LIGHTNING_PLUGINS_ASKRENE_CHILD_ENTRY_H */