mirror of
https://gitlab.nic.cz/labs/bird.git
synced 2025-01-03 07:31:54 +00:00
Co-routines moved to a separate module with sysdep implementation
This commit is contained in:
parent
fd3d15b6b5
commit
774121633f
22
lib/coroutine.h
Normal file
22
lib/coroutine.h
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
/*
|
||||||
|
* BIRD Coroutines
|
||||||
|
*
|
||||||
|
* (c) 2017 Martin Mares <mj@ucw.cz>
|
||||||
|
*
|
||||||
|
* Can be freely distributed and used under the terms of the GNU GPL.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _BIRD_COROUTINE_H_
|
||||||
|
#define _BIRD_COROUTINE_H_
|
||||||
|
|
||||||
|
// The structure is completely opaque, implemented by sysdep
|
||||||
|
typedef struct coroutine coroutine;
|
||||||
|
|
||||||
|
coroutine *coro_new(struct pool *pool, void (*entry_point)(void *arg), void *arg);
|
||||||
|
void coro_suspend(void);
|
||||||
|
void coro_resume(coroutine *c);
|
||||||
|
|
||||||
|
struct birdsock;
|
||||||
|
int coro_sk_read(struct birdsock *s);
|
||||||
|
|
||||||
|
#endif
|
@ -66,8 +66,8 @@
|
|||||||
#include "nest/bird.h"
|
#include "nest/bird.h"
|
||||||
#include "nest/cli.h"
|
#include "nest/cli.h"
|
||||||
#include "conf/conf.h"
|
#include "conf/conf.h"
|
||||||
|
#include "lib/coroutine.h"
|
||||||
#include "lib/string.h"
|
#include "lib/string.h"
|
||||||
#include "sysdep/unix/unix.h" // FIXME
|
|
||||||
|
|
||||||
pool *cli_pool;
|
pool *cli_pool;
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
src := io.c krt.c log.c main.c random.c
|
src := io.c krt.c log.c main.c random.c coroutine.c
|
||||||
obj := $(src-o-files)
|
obj := $(src-o-files)
|
||||||
$(all-daemon)
|
$(all-daemon)
|
||||||
$(cf-local)
|
$(cf-local)
|
||||||
|
135
sysdep/unix/coroutine.c
Normal file
135
sysdep/unix/coroutine.c
Normal file
@ -0,0 +1,135 @@
|
|||||||
|
/*
|
||||||
|
* BIRD Coroutines
|
||||||
|
*
|
||||||
|
* (c) 2017 Martin Mares <mj@ucw.cz>
|
||||||
|
*
|
||||||
|
* Can be freely distributed and used under the terms of the GNU GPL.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _GNU_SOURCE
|
||||||
|
#define _GNU_SOURCE
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <ucontext.h>
|
||||||
|
|
||||||
|
#include "nest/bird.h"
|
||||||
|
#include "lib/coroutine.h"
|
||||||
|
#include "lib/resource.h"
|
||||||
|
#include "lib/socket.h"
|
||||||
|
#include "sysdep/unix/unix.h"
|
||||||
|
|
||||||
|
struct coroutine {
|
||||||
|
resource r;
|
||||||
|
ucontext_t ctx;
|
||||||
|
void *stack;
|
||||||
|
void (*entry_point)(void *arg);
|
||||||
|
void *arg;
|
||||||
|
};
|
||||||
|
|
||||||
|
static ucontext_t *main_context;
|
||||||
|
static coroutine *coro_current; // NULL for main context
|
||||||
|
|
||||||
|
#define CORO_STACK_SIZE 65536
|
||||||
|
|
||||||
|
static void
|
||||||
|
coro_free(resource *r)
|
||||||
|
{
|
||||||
|
coroutine *c = (coroutine *) r;
|
||||||
|
xfree(c->stack);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
coro_dump(resource *r UNUSED)
|
||||||
|
{
|
||||||
|
debug("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
static size_t
|
||||||
|
coro_memsize(resource *r)
|
||||||
|
{
|
||||||
|
coroutine *c = (coroutine *) r;
|
||||||
|
return sizeof(*c) + CORO_STACK_SIZE + 2*ALLOC_OVERHEAD;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct resclass coro_class = {
|
||||||
|
.name = "Coroutine",
|
||||||
|
.size = sizeof(struct coroutine),
|
||||||
|
.free = coro_free,
|
||||||
|
.dump = coro_dump,
|
||||||
|
.memsize = coro_memsize,
|
||||||
|
};
|
||||||
|
|
||||||
|
static void
|
||||||
|
coro_do_start(void)
|
||||||
|
{
|
||||||
|
ASSERT(coro_current);
|
||||||
|
coro_current->entry_point(coro_current->arg);
|
||||||
|
bug("Coroutine returned unexpectedly");
|
||||||
|
}
|
||||||
|
|
||||||
|
struct coroutine *
|
||||||
|
coro_new(pool *p, void (*entry_point)(void *), void *arg)
|
||||||
|
{
|
||||||
|
if (!main_context)
|
||||||
|
{
|
||||||
|
main_context = xmalloc(sizeof(*main_context));
|
||||||
|
if (getcontext(main_context) < 0)
|
||||||
|
bug("getcontext() failed");
|
||||||
|
}
|
||||||
|
|
||||||
|
coroutine *c = ralloc(p, &coro_class);
|
||||||
|
c->entry_point = entry_point;
|
||||||
|
c->arg = arg;
|
||||||
|
if (getcontext(&c->ctx) < 0)
|
||||||
|
bug("getcontext() failed");
|
||||||
|
c->stack = xmalloc(CORO_STACK_SIZE);
|
||||||
|
c->ctx.uc_stack.ss_sp = c->stack;
|
||||||
|
c->ctx.uc_stack.ss_size = CORO_STACK_SIZE;
|
||||||
|
|
||||||
|
makecontext(&c->ctx, coro_do_start, 0);
|
||||||
|
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
coro_suspend(void)
|
||||||
|
{
|
||||||
|
ASSERT(coro_current);
|
||||||
|
ASSERT(main_context);
|
||||||
|
coroutine *c = coro_current;
|
||||||
|
coro_current = NULL;
|
||||||
|
swapcontext(&c->ctx, main_context);
|
||||||
|
ASSERT(coro_current == c);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
coro_resume(coroutine *c)
|
||||||
|
{
|
||||||
|
ASSERT(!coro_current);
|
||||||
|
coro_current = c;
|
||||||
|
swapcontext(main_context, &c->ctx);
|
||||||
|
ASSERT(!coro_current);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Coroutine-based I/O */
|
||||||
|
|
||||||
|
static int
|
||||||
|
coro_sk_rx_hook(sock *sk, uint size UNUSED)
|
||||||
|
{
|
||||||
|
ASSERT(sk->rx_coroutine);
|
||||||
|
ASSERT(!coro_current);
|
||||||
|
coro_resume(sk->rx_coroutine);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
coro_sk_read(sock *s)
|
||||||
|
{
|
||||||
|
ASSERT(coro_current);
|
||||||
|
s->rx_coroutine = coro_current;
|
||||||
|
s->rx_hook = coro_sk_rx_hook;
|
||||||
|
coro_suspend();
|
||||||
|
s->rx_hook = NULL;
|
||||||
|
return s->rpos - s->rbuf;
|
||||||
|
}
|
110
sysdep/unix/io.c
110
sysdep/unix/io.c
@ -2665,113 +2665,3 @@ test_old_bird(char *path)
|
|||||||
die("I found another BIRD running.");
|
die("I found another BIRD running.");
|
||||||
close(fd);
|
close(fd);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* EXPERIMENTAL: Support for coroutines */
|
|
||||||
|
|
||||||
#include <ucontext.h>
|
|
||||||
|
|
||||||
struct coroutine {
|
|
||||||
resource r;
|
|
||||||
ucontext_t ctx;
|
|
||||||
void *stack;
|
|
||||||
void (*entry_point)(void *arg);
|
|
||||||
void *arg;
|
|
||||||
};
|
|
||||||
|
|
||||||
static ucontext_t *main_context;
|
|
||||||
static coroutine *coro_current; // NULL for main context
|
|
||||||
|
|
||||||
static void
|
|
||||||
coro_free(resource *r)
|
|
||||||
{
|
|
||||||
coroutine *c = (coroutine *) r;
|
|
||||||
xfree(c->stack);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
coro_dump(resource *r UNUSED)
|
|
||||||
{
|
|
||||||
debug("\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
static struct resclass coro_class = {
|
|
||||||
.name = "Coroutine",
|
|
||||||
.size = sizeof(struct coroutine),
|
|
||||||
.free = coro_free,
|
|
||||||
.dump = coro_dump,
|
|
||||||
// FIXME: Implement memsize
|
|
||||||
};
|
|
||||||
|
|
||||||
static void
|
|
||||||
coro_do_start(void)
|
|
||||||
{
|
|
||||||
ASSERT(coro_current);
|
|
||||||
coro_current->entry_point(coro_current->arg);
|
|
||||||
bug("Coroutine returned unexpectedly");
|
|
||||||
}
|
|
||||||
|
|
||||||
struct coroutine *
|
|
||||||
coro_new(pool *p, void (*entry_point)(void *), void *arg)
|
|
||||||
{
|
|
||||||
if (!main_context)
|
|
||||||
{
|
|
||||||
main_context = xmalloc(sizeof(*main_context));
|
|
||||||
if (getcontext(main_context) < 0)
|
|
||||||
bug("getcontext() failed");
|
|
||||||
}
|
|
||||||
|
|
||||||
coroutine *c = ralloc(p, &coro_class);
|
|
||||||
c->entry_point = entry_point;
|
|
||||||
c->arg = arg;
|
|
||||||
if (getcontext(&c->ctx) < 0)
|
|
||||||
bug("getcontext() failed");
|
|
||||||
c->stack = xmalloc(65536);
|
|
||||||
c->ctx.uc_stack.ss_sp = c->stack;
|
|
||||||
c->ctx.uc_stack.ss_size = 65536;
|
|
||||||
|
|
||||||
makecontext(&c->ctx, coro_do_start, 0);
|
|
||||||
|
|
||||||
return c;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Return to main context
|
|
||||||
void
|
|
||||||
coro_suspend(void)
|
|
||||||
{
|
|
||||||
ASSERT(coro_current);
|
|
||||||
ASSERT(main_context);
|
|
||||||
coroutine *c = coro_current;
|
|
||||||
coro_current = NULL;
|
|
||||||
swapcontext(&c->ctx, main_context);
|
|
||||||
ASSERT(coro_current == c);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Resume context
|
|
||||||
void
|
|
||||||
coro_resume(coroutine *c)
|
|
||||||
{
|
|
||||||
ASSERT(!coro_current);
|
|
||||||
coro_current = c;
|
|
||||||
swapcontext(main_context, &c->ctx);
|
|
||||||
ASSERT(!coro_current);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
coro_sk_rx_hook(sock *sk, uint size UNUSED)
|
|
||||||
{
|
|
||||||
ASSERT(sk->rx_coroutine);
|
|
||||||
ASSERT(!coro_current);
|
|
||||||
coro_resume(sk->rx_coroutine);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
coro_sk_read(sock *s)
|
|
||||||
{
|
|
||||||
ASSERT(coro_current);
|
|
||||||
s->rx_coroutine = coro_current;
|
|
||||||
s->rx_hook = coro_sk_rx_hook;
|
|
||||||
coro_suspend();
|
|
||||||
s->rx_hook = NULL;
|
|
||||||
return s->rpos - s->rbuf;
|
|
||||||
}
|
|
||||||
|
@ -23,6 +23,7 @@
|
|||||||
#include <libgen.h>
|
#include <libgen.h>
|
||||||
|
|
||||||
#include "nest/bird.h"
|
#include "nest/bird.h"
|
||||||
|
#include "lib/coroutine.h"
|
||||||
#include "lib/lists.h"
|
#include "lib/lists.h"
|
||||||
#include "lib/resource.h"
|
#include "lib/resource.h"
|
||||||
#include "lib/socket.h"
|
#include "lib/socket.h"
|
||||||
|
@ -102,13 +102,6 @@ int sk_open_unix(struct birdsock *s, char *name);
|
|||||||
void *tracked_fopen(struct pool *, char *name, char *mode);
|
void *tracked_fopen(struct pool *, char *name, char *mode);
|
||||||
void test_old_bird(char *path);
|
void test_old_bird(char *path);
|
||||||
|
|
||||||
/* Co-routines */
|
|
||||||
typedef struct coroutine coroutine;
|
|
||||||
coroutine *coro_new(struct pool *pool, void (*entry_point)(void *arg), void *arg);
|
|
||||||
void coro_suspend(void);
|
|
||||||
void coro_resume(coroutine *c);
|
|
||||||
int coro_sk_read(struct birdsock *s);
|
|
||||||
|
|
||||||
/* krt.c bits */
|
/* krt.c bits */
|
||||||
|
|
||||||
void krt_io_init(void);
|
void krt_io_init(void);
|
||||||
|
Loading…
Reference in New Issue
Block a user