mirror of
https://github.com/ElementsProject/lightning.git
synced 2024-11-20 10:39:49 +01:00
7401b26824
Before: Ten builds, laptop -j5, no ccache: ``` real 0m36.686000-38.956000(38.608+/-0.65)s user 2m32.864000-42.253000(40.7545+/-2.7)s sys 0m16.618000-18.316000(17.8531+/-0.48)s ``` Ten builds, laptop -j5, ccache (warm): ``` real 0m8.212000-8.577000(8.39989+/-0.13)s user 0m12.731000-13.212000(12.9751+/-0.17)s sys 0m3.697000-3.902000(3.83722+/-0.064)s ``` After: Ten builds, laptop -j5, no ccache: 8% faster ``` real 0m33.802000-35.773000(35.468+/-0.54)s user 2m19.073000-27.754000(26.2542+/-2.3)s sys 0m15.784000-17.173000(16.7165+/-0.37)s ``` Ten builds, laptop -j5, ccache (warm): 1% faster ``` real 0m8.200000-8.485000(8.30138+/-0.097)s user 0m12.485000-13.100000(12.7344+/-0.19)s sys 0m3.702000-3.889000(3.78787+/-0.056)s ``` Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
153 lines
3.6 KiB
C
153 lines
3.6 KiB
C
#include <ccan/fdpass/fdpass.h>
|
|
#include <ccan/io/fdpass/fdpass.h>
|
|
#include <common/daemon_conn.h>
|
|
#include <wire/wire_io.h>
|
|
#include <wire/wire_sync.h>
|
|
|
|
struct daemon_conn {
|
|
/* Last message we received */
|
|
u8 *msg_in;
|
|
|
|
/* Queue of outgoing messages */
|
|
struct msg_queue *out;
|
|
|
|
/* Underlying connection: we're freed if it closes, and vice versa */
|
|
struct io_conn *conn;
|
|
|
|
/* Callback for incoming messages */
|
|
struct io_plan *(*recv)(struct io_conn *conn, const u8 *, void *);
|
|
|
|
/* Called whenever we've cleared the msg_out queue. */
|
|
void (*outq_empty)(void *);
|
|
|
|
/* Arg for both callbacks. */
|
|
void *arg;
|
|
};
|
|
|
|
static struct io_plan *handle_read(struct io_conn *conn,
|
|
struct daemon_conn *dc)
|
|
{
|
|
return dc->recv(conn, dc->msg_in, dc->arg);
|
|
}
|
|
|
|
struct io_plan *daemon_conn_read_next(struct io_conn *conn,
|
|
struct daemon_conn *dc)
|
|
{
|
|
/* FIXME: We could use disposable parent instead, and recv() could
|
|
* tal_steal() it? If they did that now, we'd free it here. */
|
|
tal_free(dc->msg_in);
|
|
return io_read_wire(conn, dc, &dc->msg_in, handle_read, dc);
|
|
}
|
|
|
|
static struct io_plan *daemon_conn_write_next(struct io_conn *conn,
|
|
struct daemon_conn *dc)
|
|
{
|
|
const u8 *msg;
|
|
|
|
msg = msg_dequeue(dc->out);
|
|
|
|
/* If nothing in queue, give empty callback a chance to queue somthing */
|
|
if (!msg && dc->outq_empty) {
|
|
dc->outq_empty(dc->arg);
|
|
msg = msg_dequeue(dc->out);
|
|
}
|
|
|
|
if (msg) {
|
|
int fd = msg_extract_fd(msg);
|
|
if (fd >= 0) {
|
|
tal_free(msg);
|
|
return io_send_fd(conn, fd, true,
|
|
daemon_conn_write_next, dc);
|
|
}
|
|
return io_write_wire(conn, take(msg), daemon_conn_write_next,
|
|
dc);
|
|
}
|
|
return msg_queue_wait(conn, dc->out, daemon_conn_write_next, dc);
|
|
}
|
|
|
|
bool daemon_conn_sync_flush(struct daemon_conn *dc)
|
|
{
|
|
const u8 *msg;
|
|
int daemon_fd;
|
|
|
|
/* Flush any current packet. */
|
|
if (!io_flush_sync(dc->conn))
|
|
return false;
|
|
|
|
/* Make fd blocking for the duration */
|
|
daemon_fd = io_conn_fd(dc->conn);
|
|
if (!io_fd_block(daemon_fd, true))
|
|
return false;
|
|
|
|
/* Flush existing messages. */
|
|
while ((msg = msg_dequeue(dc->out)) != NULL) {
|
|
int fd = msg_extract_fd(msg);
|
|
if (fd >= 0) {
|
|
tal_free(msg);
|
|
if (!fdpass_send(daemon_fd, fd))
|
|
break;
|
|
} else if (!wire_sync_write(daemon_fd, take(msg)))
|
|
break;
|
|
}
|
|
io_fd_block(daemon_fd, false);
|
|
|
|
/* Success if and only if we flushed them all. */
|
|
return msg == NULL;
|
|
}
|
|
|
|
static struct io_plan *daemon_conn_start(struct io_conn *conn,
|
|
struct daemon_conn *dc)
|
|
{
|
|
return io_duplex(conn, daemon_conn_read_next(conn, dc),
|
|
/* Could call daemon_conn_write_next, but we don't
|
|
* want it to call empty_cb just yet! */
|
|
msg_queue_wait(conn, dc->out,
|
|
daemon_conn_write_next, dc));
|
|
}
|
|
|
|
static void destroy_dc_from_conn(struct io_conn *conn, struct daemon_conn *dc)
|
|
{
|
|
/* Harmless free loop if conn is being destroyed because dc freed */
|
|
tal_free(dc);
|
|
}
|
|
|
|
struct daemon_conn *daemon_conn_new_(const tal_t *ctx, int fd,
|
|
struct io_plan *(*recv)(struct io_conn *,
|
|
const u8 *,
|
|
void *),
|
|
void (*outq_empty)(void *),
|
|
void *arg)
|
|
{
|
|
struct daemon_conn *dc = tal(NULL, struct daemon_conn);
|
|
|
|
dc->recv = recv;
|
|
dc->outq_empty = outq_empty;
|
|
dc->arg = arg;
|
|
dc->msg_in = NULL;
|
|
dc->out = msg_queue_new(dc);
|
|
|
|
dc->conn = io_new_conn(dc, fd, daemon_conn_start, dc);
|
|
tal_add_destructor2(dc->conn, destroy_dc_from_conn, dc);
|
|
return dc;
|
|
}
|
|
|
|
void daemon_conn_send(struct daemon_conn *dc, const u8 *msg)
|
|
{
|
|
msg_enqueue(dc->out, msg);
|
|
}
|
|
|
|
void daemon_conn_send_fd(struct daemon_conn *dc, int fd)
|
|
{
|
|
msg_enqueue_fd(dc->out, fd);
|
|
}
|
|
|
|
void daemon_conn_wake(struct daemon_conn *dc)
|
|
{
|
|
msg_wake(dc->out);
|
|
}
|
|
|
|
size_t daemon_conn_queue_length(const struct daemon_conn *dc)
|
|
{
|
|
return msg_queue_length(dc->out);
|
|
}
|