Commit 4ec43aa1 authored by Jan Maria Matejka's avatar Jan Maria Matejka
Browse files

Conf: use coroutine to read new config

parent 642acc1b
Loading
Loading
Loading
Loading
+3 −12
Original line number Diff line number Diff line
@@ -330,12 +330,6 @@ cf_hash(byte *c)
  return h;
}

static void
cf_init_state(struct cf_context *ctx, struct conf_state *cs)
{
  cs->buffer = yy_create_buffer(NULL, YY_BUF_SIZE, ctx->yyscanner);
}

struct conf_state *
cf_new_state(struct cf_context *ctx, const char *name)
{
@@ -344,7 +338,7 @@ cf_new_state(struct cf_context *ctx, const char *name)
    .name = cfg_strdup(name),
    .lino = 1,
  };
  cf_init_state(ctx, cs);
  cs->buffer = yy_create_buffer(NULL, YY_BUF_SIZE, ctx->yyscanner);
  return cs;
}

@@ -400,7 +394,7 @@ cf_init_kh(void)
 * parsing of a new input.
 */
struct cf_context *
cf_new_context(int is_cli, struct conf_order *order)
cf_new_context(struct conf_order *order)
{
  struct cf_context *ctx = order->ctx = lp_allocz(order->new_config->mem, sizeof(struct cf_context));
  *ctx = (struct cf_context) {
@@ -412,10 +406,7 @@ cf_new_context(int is_cli, struct conf_order *order)
  cfx_lex_init_extra(ctx, &(ctx->yyscanner));
  struct yyguts_t *yyg = ctx->yyscanner;

  cf_init_state(ctx, order->state);
  yy_switch_to_buffer(order->state->buffer, yyg);

  if (is_cli)
  if (order->flags & CO_CLI)
    BEGIN(CLI);
  else
    BEGIN(INITIAL);
+87 −38
Original line number Diff line number Diff line
@@ -103,16 +103,42 @@ config_alloc(struct pool *pp, struct linpool *lp)
  return c;
}

int
config_parse(struct conf_order *order)
static void config_event_resume(void *arg)
{
  DBG("Parsing configuration named `%s'\n", order->state->name);
  DBG("config event resume\n");
  struct cf_context *ctx = arg;
  coro_resume(ctx->coro);
}

  if (!order->new_config)
    order->new_config = config_alloc(order->pool, order->lp);
static void config_event_cleanup(void *arg)
{
  DBG("config event cleanup\n");
  struct cf_context *ctx = arg;
  struct conf_order *order = ctx->order;

  rfree(ctx->coro);

  cf_free_context(ctx);
  order->ctx = NULL;

  if (order->flags & CO_CLI)
    {
      config_free(order->new_config);
      order->new_config = NULL;
    }

  struct cf_context *ctx = cf_new_context(0, order);
  int ret;
  return order->cf_done(order);
}

static void
config_parse_coro(void *arg)
{
  struct cf_context *ctx = arg;
  struct conf_order *order = ctx->order;
  DBG("%s parse coroutine started in %s mode\n",
      (order->flags & CO_CLI) ? "Cli" : "Conf",
      (order->flags & CO_SYNC) ? "sync" : "async"
      );

  if (setjmp(ctx->jmpbuf))
    {
@@ -120,58 +146,80 @@ config_parse(struct conf_order *order)
	while (! order->cf_outclude(order))
	  ;

      ret = 0;

      config_free(ctx->new_config);
      order->new_config = NULL;

      goto cleanup;
    }

  sysdep_preconfig(ctx);
  protos_preconfig(ctx->new_config);
  rt_preconfig(ctx);
  cfx_parse(ctx, ctx->yyscanner);

  if (EMPTY_LIST((ctx->new_config)->protos))
  if (!(order->flags & CO_CLI) && EMPTY_LIST(ctx->new_config->protos))
    cf_error(ctx, "No protocol is specified in the config file");

  ret = 1;

cleanup:
  cf_free_context(ctx);
  order->ctx = NULL;
  return ret;
  if (order->flags & CO_SYNC)
    return;

  DBG("config parse coroutine done, scheduling thread join\n");
  coro_done(ctx->ev_cleanup);
  bug("Resumed config when done.");
}

int
cli_parse(struct conf_order *order)
void
config_parse(struct conf_order *order)
{
  DBG("Parsing command line\n");
  DBG("Parsing configuration\n");

  if (!order->new_config)
    order->new_config = config_alloc(order->pool, order->lp);

  struct config cc = {};
  cc.pool = rp_new(order->pool ?: &root_pool, "CLI Dummy Config");
  cc.mem = order->lp ?: lp_new_default(cc.pool);
  pool *p = order->new_config->pool;

  struct cf_context *ctx = cf_new_context(order);

  /* CLI does no preconfig */
  if (!(order->flags & CO_CLI))
    {
      sysdep_preconfig(ctx);
      protos_preconfig(ctx->new_config);
      rt_preconfig(ctx);
    }

  order->new_config = &cc;
  if (!(order->flags & CO_SYNC))
    {
      ctx->ev_resume = ev_new(p);
      ctx->ev_resume->hook = config_event_resume;
      ctx->ev_resume->data = ctx;

  struct cf_context *ctx = cf_new_context(1, order);
      ctx->ev_cleanup = ev_new(p);
      ctx->ev_cleanup->hook = config_event_cleanup;
      ctx->ev_cleanup->data = ctx;
    }

  if (order->flags & CO_FILENAME)
    if (order->cf_include)
      order->cf_include(order, order->buf, order->len);
    else
      bug("Include handler must be set to config from file");
  else
    cf_scan_bytes(ctx, order->buf, order->len);
    /* Warning: Return from include will fail badly if you start with a buffer.
     * Currently it's not supported to supply cf_include hook without CO_FILENAME flag.
     */

  int ok = 0;
  if (setjmp(ctx->jmpbuf))
    goto done;
  if (order->flags & CO_SYNC)
    return config_parse_coro(ctx);

  cfx_parse(ctx, ctx->yyscanner);
  ok = 1;
  ctx->coro = coro_new(p, config_parse_coro, ctx);
  coro_resume(ctx->coro);
}

done:
  cf_free_context(ctx);
  config_free(&cc);
  order->new_config = NULL;
  order->ctx = NULL;
  return ok;
void config_yield(struct cf_context *ctx)
{
  DBG("Conf: Yield\n");
  ev_schedule(ctx->ev_resume);
  DBG("Conf: Yield resumed\n");
}

/**
@@ -319,6 +367,7 @@ config_done(void *unused UNUSED)
int
config_commit(struct config *c, int type, uint timeout)
{
  ASSERT(type != RECONFIG_CHECK);
  if (shutting_down)
    {
      config_free(c);
+20 −20
Original line number Diff line number Diff line
@@ -59,18 +59,30 @@ struct conf_state {
  uint lino;				/* Current line */
};

enum conf_order_flag {
  CO_CLI = 1,				/* Parse CLI, not regular config */
  CO_SYNC = 2,				/* Run parser synchronously */
  CO_FILENAME = 4,			/* Use the order buffer as filename */
} PACKED;

/* This struct is meant to be inherited and customized by caller */
struct conf_order {
  struct config *new_config;		/* Store the allocated config here */
  resource r;
  struct config *new_config;		/* Outputs the allocated config here */
  struct cf_context *ctx;		/* Internal config context, do not set */
  struct conf_state *state;
  struct conf_state *state;		/* Internal config state, do not set */

  struct pool *pool;			/* If set, use this resource pool */
  struct linpool *lp;			/* If set, use this linpool */
  const char *buf;
  uint len;
  const char *buf;			/* Buffer to parse or filename */
  uint len;				/* Buffer length */
  enum conf_order_flag flags;

  int (*cf_read_hook)(struct conf_order *order, byte *buf, uint max);
  void (*cf_include)(struct conf_order *order, char *name, uint len);
  void (*cf_include)(struct conf_order *order, const char *name, uint len);
  int (*cf_outclude)(struct conf_order *order);
  void (*cf_error)(struct conf_order *order, const char *msg, va_list args);
  void (*cf_done)(struct conf_order *order);
};

/* Please don't use these variables in protocols. Use proto_config->global instead. */
@@ -82,25 +94,12 @@ extern struct config *config; /* Currently active configuration */
 * Arguments:
 * @order provides callbacks to read config files
 *
 * This function queues 
 * Return value:
 * 1 on success; order->new_config is then set to the parsed config
 * 0 on fail; order->new_config is undefined
 **/
int config_parse(struct conf_order *order);

/**
 * Parse CLI command
 *
 * Arguments:
 * @order provides callbacks to read command line
 *
 * Return value:
 * 1 on success
 * 0 on fail
 *
 * Parsed config is never kept, order->new_config should be zero after return.
 **/
int cli_parse(struct conf_order *order);
void config_parse(struct conf_order *order);

/** Callback for returning error from parser hooks */
void cf_error(struct cf_context *, const char *msg, ...) NORET;
@@ -118,6 +117,7 @@ void order_shutdown(void);
#define RECONFIG_HARD	1
#define RECONFIG_SOFT	2
#define RECONFIG_UNDO	3
#define RECONFIG_CHECK	4

#define CONF_DONE	0
#define CONF_PROGRESS	1
+4 −0
Original line number Diff line number Diff line
@@ -22,6 +22,7 @@ CF_HDR
#include "nest/route.h"
#include "nest/cli.h"
#include "filter/filter.h"
#include "lib/coroutine.h"

/* FIXME: Turn on YYERROR_VERBOSE and work around lots of bison bugs? */

@@ -33,6 +34,9 @@ struct config *new_config;
jmp_buf jmpbuf;
linpool *cfg_mem;
struct conf_order *order;
coroutine *coro;
event *ev_resume;
event *ev_cleanup;

CF_DEFINES

+1 −1
Original line number Diff line number Diff line
@@ -27,7 +27,7 @@ union YYSTYPE;
int cfx_lex(union YYSTYPE *, yyscan_t);

/* Config context alloc and free */
struct cf_context *cf_new_context(int, struct conf_order *);
struct cf_context *cf_new_context(struct conf_order *);
void cf_free_context(struct cf_context *);

/* Lexer state alloc and free */
Loading