1
0
mirror of https://github.com/mariadb-corporation/mariadb-connector-c.git synced 2025-08-07 02:42:49 +03:00
Files
mariadb-connector-c/libmariadb/ma_boost_context.cc
Kristian Nielsen da0a01367c Implement boost::context as a fallback for non-blocking API support
The non-blocking API has native (assembler) implementations for x86_64,
i386, and (with recent patch) aarch64; these implementations are the most
efficient. For other architectures, a fallback to ucontext is supported.

But ucontext is not the most efficient, and it is not available on all
platforms (it has been deprecated in POSIX). The boost::context library
provides an alternative fallback that is available on more architectures and
should be more efficient than ucontext (if still not quite as fast as the
native support).

This patch adds a CMake option -DWITH_BOOST_CONTEXT=ON that adds
boost::context as a dependency of libmariadb to provide a fallback on
non-natively supported architectures. Boost::context is preferred over
ucontext when both are available.

The option is off by default and must be explicitly enabled by the
user. This avoids introducing a C++ dependency (including dependency
on a C++ compiler and on libstdc++) unless explicitly requested by the
user (libmariadb is otherwise C-only).

Tested-by: Brad Smith <brad@comstyle.com>
Signed-off-by: Kristian Nielsen <knielsen@knielsen-hq.org>
2024-09-27 15:33:43 +02:00

118 lines
2.7 KiB
C++

#include "ma_config.h"
#include "mysql.h"
#include "ma_context.h"
#ifdef MY_CONTEXT_USE_BOOST_CONTEXT
#include <boost/fiber/context.hpp>
namespace ctx=boost::context;
struct my_context_intern {
ctx::fiber parent, coro;
void *stack_top(const my_context *c) {
return (unsigned char *)(c->stack) + c->stack_size;
}
/* A StackAlloc for ctx::fiber that reuses our stack. */
struct my_stack_alloc {
typedef ctx::stack_traits traits_type;
my_context *c;
my_stack_alloc(my_context *c_arg) : c(c_arg) { };
ctx::stack_context allocate() {
ctx::stack_context sctx;
sctx.size= c->stack_size;
sctx.sp= ((my_context_intern *)c->internal_context)->stack_top(c);
#if defined(BOOST_USE_VALGRIND) && defined(HAVE_VALGRIND)
sctx.valgrind_stack_id= c->valgrind_stack_id;
#endif
return sctx;
}
void deallocate(ctx::stack_context & sctx) {
/* Empty, we will re-use the stack. */
}
};
};
extern "C"
int
my_context_spawn(struct my_context *c, void (*f)(void *), void *d)
{
my_context_intern *ci= (my_context_intern *)c->internal_context;
ci->coro= ctx::fiber(std::allocator_arg, my_context_intern::my_stack_alloc(c),
[c, f, d](ctx::fiber && parent) {
my_context_intern *ci= (my_context_intern *)c->internal_context;
ci->parent= std::move(parent);
(*f)(d);
c->active= 0;
return std::move(ci->parent);
});
c->active= 1;
ci->coro= std::move(ci->coro).resume();
return c->active;
}
extern "C"
int
my_context_continue(struct my_context *c)
{
if (!c->active)
return 0;
my_context_intern *ci= (my_context_intern *)c->internal_context;
ci->coro= std::move(ci->coro).resume();
return c->active;
}
extern "C"
int
my_context_yield(struct my_context *c)
{
if (!c->active)
return -1;
my_context_intern *ci= (my_context_intern *)c->internal_context;
ci->parent= std::move(ci->parent).resume();
return 0;
}
extern "C"
int
my_context_init(struct my_context *c, size_t stack_size)
{
memset(c, 0, sizeof(*c));
if (!(c->stack= malloc(stack_size)))
return -1; /* Out of memory */
if (!(c->internal_context= new my_context_intern))
{
free(c->stack);
return -1;
}
c->stack_size= stack_size;
#ifdef HAVE_VALGRIND
c->valgrind_stack_id=
VALGRIND_STACK_REGISTER(c->stack, ((unsigned char *)(c->stack))+stack_size);
#endif
return 0;
}
extern "C"
void
my_context_destroy(struct my_context *c)
{
delete (my_context_intern *)c->internal_context;
if (c->stack)
{
#ifdef HAVE_VALGRIND
VALGRIND_STACK_DEREGISTER(c->valgrind_stack_id);
#endif
free(c->stack);
}
}
#endif /* MY_CONTEXT_USE_BOOST_CONTEXT */