Skip site navigation (1)Skip section navigation (2)

FreeBSD Manual Pages

  
 
  

home | help
EMILUA(7)		       Emilua reference			     EMILUA(7)

NAME
       Emilua -	Lua execution engine

DESCRIPTION
       If you want to embed Emilua in your own Boost.Asio-based	programs, this
       is the list of steps you	need to	do:

	1. Compile and link against Emilua (use	Meson or pkg-config to have
	   the appropriate compiler flags filled automatically).

	2. #include <emilua/state.hpp>

	3. Instantiate emilua::app_context. This object	needs to stay alive
	   for as long as at least one Lua VM is alive.	If you want to be
	   sure, just make sure	it outlives boost::asio::io_context and	you're
	   good	to go.

	4. Create an emilua::properties_service	object with the	same
	   concurrency hint passed to boost::asio::io_context and add it to
	   the boost::asio::io_context object using boost::asio::make_service.
	   This	step will be needed for	as long	as Boost.Asio refuses to add a
	   getter for the concurrency hint:
	   https://github.com/chriskohlhoff/asio/pull/1254.

	5. Call	emilua::make_vm() (see src/main.ypp for	an example).

	6. Call	emilua::vm_context::fiber_resume() inside the strand returned
	   by emilua::vm_context::strand() to start the	Lua VM created in the
	   previous step (see src/main.ypp for an example).

	7. Optionally synchronize against other	threads	before you exit	the
	   application.	If you're going	to spawn actors	in foreign
	   boost::asio::io_context objects in your Lua programs	then it's a
	   good	idea to	include	this step. See below.

	   Warning

	   Emilua is not designed to work properly with
	   boost::asio::io_context::stop(). Many cleanup steps will be missed
	   if you call this function. If you need to use it, then spawn	Emilua
	   programs in their own boost::asio::io_context instances.

emilua::app_context
       This type stores	process-wide info that is shared among all Lua VMs
       (e.g. process arguments,	environment, module paths, module caches,
       default logger, which VM	is the master VM, ...).

       If you want to embed the	Lua programs in	your binary as well you	can
       pre-populate the	module cache here with the contents of all Lua files
       you intend to ship in the binary. modules_cache_registry	is the member
       you're looking for. Do this before you start the	first Lua VM. However
       there's a better	way (see next section).

BUILTIN	MODULES
       Just define some	or all of the following	3 functions and	your module
       name resolution will be favoured	over filesystem	queries:

          emilua::get_builtin_module

          emilua::get_builtin_rdf_ec

          emilua::get_builtin_native_module

       Using this method instead of pre-filling	the module cache allows	actors
       spawned in subprocesses to import these modules as well.	This method
       may also	lead to	better start-up	times and a smaller memory footprint
       (you could even use gperf to have the best module search	performance).

MASTER VM
       If you want to allow your Lua programs to change	process	state that is
       shared among all	program	threads	(e.g. current working directory,
       signal handlers,	...) then you need to elect one	Lua VM to be the
       master VM.

       The 1-one snippet that follows is enough	to finish this setup. This
       step must be done before	you call fiber_resume().

	   appctx.master_vm = vm_ctx;

CLEANUP	AT EXIT
       First make sure emilua::app_context outlives boost::asio::io_context.

       After boost::asio::io_context::run() returns you	can use	the following
       snippet to synchronize against extra threads and
       boost::asio::io_context objects your Lua	scripts	created[1].

	   {
	       std::unique_lock<std::mutex> lk{appctx.extra_threads_count_mtx};
	       while (appctx.extra_threads_count > 0)
		   appctx.extra_threads_count_empty_cond.wait(lk);
	   }

ACTORS SPAWNED IN DIFFERENT PROCESSES
       Emilua has the ability to spawn Lua VMs in their	own processes for
       isolation or sandboxing purposes. To enable this	feature, a supervisor
       process must be created while the program is still single-threaded.

       For communication with the supervisor process, Emilua uses an UNIX
       socket. The file	descriptor for this process is stored in
       app_context::ipc_actor_service_sockfd. See src/main.ypp for an example
       on how to initialize this variable.

       On Linux, you also need to initialize emilua::clone_stack_address.

       If you don't intend to have Lua VMs tied	to their own processes
       triggered by Lua	programs then you can skip this	step.

INHERITED LOW-NUMBERED FILE DESCRIPTORS
       After file descriptors are allocated in the process table by some
       library,	it's already too late detect whether some arbitrary file
       descriptor was inherited	from the parent	process. If you're planning to
       allow Lua-programs to take control over these file descriptors (i.e.
       system.get_lowfd()), you	must add some logic at the program startup
       (before any new file descriptor is allocated) to	check which file
       descriptors were	inherited and are allowed to be	manipulated from Lua
       programs	and store them in the Emilua registry:

	   std::array<bool, 7> lowfds;
	   lowfds.fill(false);

	   for (int fd = 3 ; fd	<= 9 ; ++fd) {
	       if (fcntl(fd, F_GETFD) != -1 || errno !=	EBADF) {
		   lowfds[fd - 3] = true;
	       }
	   }

	   // ...

	   emilua::app_context appctx;
	   appctx.lowfds = lowfds;

RT SIGNALS
       Emilua reserves a RT signal for internal	uses (cancelling IO operations
       which have poor system APIs). This signal can be	configured at build
       time:

	   meson configure -Deintr_rtsigno=RTSIGNO

       If you choose the value 0, this support is disabled altogether and
       Emilua won't reserve any	RT signal by itself. If	this support is
       enabled,	you must add some code similar to the following	one in main():

	   struct sigaction sa;
	   std::memset(&sa, 0, sizeof(struct sigaction));

	   sigemptyset(&sa.sa_mask);
	   sigaddset(&sa.sa_mask, EMILUA_CONFIG_EINTR_RTSIGNO);
	   sigprocmask(SIG_BLOCK, &sa.sa_mask, /*oldset=*/NULL);

	   sa.sa_sigaction = emilua::longjmp_on_rtsigno;
	   sa.sa_flags = SA_RESTART | SA_SIGINFO;
	   sigaction(EMILUA_CONFIG_EINTR_RTSIGNO, /*act=*/&sa, /*oldact=*/NULL);

LIBEMILUA-MAIN
       If aren't trying	to embed Emilua	into an	existing application and just
       want to create a	single-binary application embedding the	Lua sources
       it'll be	easier to just use libemilua-main. It's	a ready	to roll
       implementation for the function main() with some	hooks you may use to
       customize simple	behavior.

NOTES
       [1]    Emilua only instantiates new threads and boost::asio::io_context
	      objects  if  your	 Lua  programs explicitly ask for that when it
	      calls spawn_vm().	You can	also disable this  feature  altogether
	      at build time.

Emilua 0.11.2			  2025-03-12			     EMILUA(7)

Want to link to this manual page? Use this URL:
<https://man.freebsd.org/cgi/man.cgi?query=emilua-embedding&sektion=7&manpath=FreeBSD+Ports+14.3.quarterly>

home | help