2022-01-29 08:26:45 -08:00
|
|
|
/*
|
|
|
|
Copyright 2018, 2020, 2021, 2022 Joel Svensson svenssonjoel@yahoo.se
|
|
|
|
|
|
|
|
This program is free software: you can redistribute it and/or modify
|
|
|
|
it under the terms of the GNU General Public License as published by
|
|
|
|
the Free Software Foundation, either version 3 of the License, or
|
|
|
|
(at your option) any later version.
|
|
|
|
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
GNU General Public License for more details.
|
|
|
|
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
|
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
*/
|
|
|
|
/** \file eval_cps.h */
|
|
|
|
#ifndef EVAL_CPS_H_
|
|
|
|
#define EVAL_CPS_H_
|
|
|
|
|
2022-02-01 11:40:07 -08:00
|
|
|
#include "lbm_types.h"
|
2022-01-29 08:26:45 -08:00
|
|
|
#include "stack.h"
|
2022-09-16 00:25:46 -07:00
|
|
|
#include "lbm_channel.h"
|
2022-01-29 08:26:45 -08:00
|
|
|
|
2022-09-04 07:08:58 -07:00
|
|
|
#ifdef __cplusplus
|
|
|
|
extern "C" {
|
|
|
|
#endif
|
|
|
|
|
2022-01-29 08:26:45 -08:00
|
|
|
#define EVAL_CPS_STATE_INIT 0
|
|
|
|
#define EVAL_CPS_STATE_PAUSED 1
|
|
|
|
#define EVAL_CPS_STATE_RUNNING 2
|
|
|
|
#define EVAL_CPS_STATE_STEP 3
|
|
|
|
#define EVAL_CPS_STATE_KILL 4
|
|
|
|
|
|
|
|
/** The eval_context_t struct represents a lispbm process.
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
typedef struct eval_context_s{
|
|
|
|
lbm_value program;
|
|
|
|
lbm_value curr_exp;
|
|
|
|
lbm_value curr_env;
|
|
|
|
lbm_value mailbox; /*massage passing mailbox */
|
|
|
|
lbm_value r;
|
2022-03-10 07:29:11 -08:00
|
|
|
char *error_reason;
|
2022-01-29 08:26:45 -08:00
|
|
|
bool done;
|
|
|
|
bool app_cont;
|
|
|
|
lbm_stack_t K;
|
|
|
|
/* Process control */
|
2022-03-25 07:47:05 -07:00
|
|
|
lbm_uint timestamp;
|
|
|
|
lbm_uint sleep_us;
|
2022-01-29 08:26:45 -08:00
|
|
|
lbm_cid id;
|
|
|
|
/* List structure */
|
|
|
|
struct eval_context_s *prev;
|
|
|
|
struct eval_context_s *next;
|
|
|
|
} eval_context_t;
|
|
|
|
|
|
|
|
/** A function pointer type to use together with the queue iterators.
|
|
|
|
*
|
|
|
|
* \param
|
|
|
|
* \param
|
|
|
|
* \param
|
|
|
|
*/
|
|
|
|
typedef void (*ctx_fun)(eval_context_t *, void*, void*);
|
|
|
|
|
|
|
|
/* Common interface */
|
|
|
|
/** Get the global environment
|
|
|
|
*
|
|
|
|
* \return global environment.
|
|
|
|
*/
|
2022-09-04 07:08:58 -07:00
|
|
|
lbm_value eval_cps_get_env(void);
|
2022-01-29 08:26:45 -08:00
|
|
|
|
|
|
|
/* Concurrent interface */
|
|
|
|
/** Initialize the evaluator.
|
|
|
|
*
|
|
|
|
* \return 1 on success and 0 on failure.
|
|
|
|
*/
|
2022-09-04 07:08:58 -07:00
|
|
|
int lbm_eval_init(void);
|
|
|
|
/** Set a new value to use as step quota.
|
|
|
|
* This changes the scheduling interval.
|
|
|
|
* \param quota The new quota.
|
|
|
|
*/
|
|
|
|
void lbm_set_eval_step_quota(uint32_t quota);
|
|
|
|
|
2022-01-29 08:26:45 -08:00
|
|
|
/** Remove a context that has finished executing and free up its associated memory.
|
|
|
|
*
|
|
|
|
* \param cid Context id of context to free.
|
|
|
|
* \param v Pointer to an lbm_value to store the result computed by the program into.
|
|
|
|
* Note that for comples values, GC will free these up the next time it runs.
|
|
|
|
* \return 1 if a context was successfully removed otherwise 0.
|
|
|
|
*/
|
2022-09-04 07:08:58 -07:00
|
|
|
int lbm_remove_done_ctx(lbm_cid cid, lbm_value *v);
|
2022-05-03 13:58:33 -07:00
|
|
|
/** Wait until a given cid is not present in any of the queues.
|
|
|
|
* If you have spawned this cid, you can conclude that it has
|
|
|
|
* run to completion or failure.
|
2022-01-29 08:26:45 -08:00
|
|
|
*
|
|
|
|
* \param cid Context id to wait for.
|
2022-02-28 15:53:55 -08:00
|
|
|
* \param timeout_ms timeout in ms or 0 for no timeout.
|
2022-01-29 08:26:45 -08:00
|
|
|
* \return Result computed by the program running in the context.
|
|
|
|
*/
|
2022-09-04 07:08:58 -07:00
|
|
|
bool lbm_wait_ctx(lbm_cid cid, lbm_uint timeout_ms);
|
2022-01-29 08:26:45 -08:00
|
|
|
/** Creates a context and initializes it with the provided program. The context
|
|
|
|
* is added to the ready queue and will start executing when the evaluator is free.
|
|
|
|
*
|
|
|
|
* \param lisp Program to launch
|
|
|
|
* \return a context id on success and 0 on failure to launch a context.
|
|
|
|
*/
|
2022-09-04 07:08:58 -07:00
|
|
|
lbm_cid lbm_eval_program(lbm_value lisp);
|
2022-01-29 08:26:45 -08:00
|
|
|
/** An extended version of lbm_eval_program that allows specification of stack size to use.
|
|
|
|
*
|
|
|
|
* \param lisp Program to launch.
|
|
|
|
* \param stack_size Size of the continuation stack for this context.
|
|
|
|
* \return a context id on success and 0 on failure to launch a context.
|
|
|
|
*/
|
2022-09-04 07:08:58 -07:00
|
|
|
lbm_cid lbm_eval_program_ext(lbm_value lisp, unsigned int stack_size);
|
2022-01-29 08:26:45 -08:00
|
|
|
|
|
|
|
/** This function executes the evaluation loop and does not return.
|
|
|
|
* lbm_run_eval should be started in a new thread provided by the underlying HAL or OS.
|
|
|
|
*/
|
2022-09-04 07:08:58 -07:00
|
|
|
void lbm_run_eval(void);
|
2022-01-29 08:26:45 -08:00
|
|
|
|
|
|
|
/** Indicate that the evaluator should pause at the next iteration.
|
|
|
|
* You cannot assume that the evaluator has paused unless you call lbm_get_eval_state and get the
|
|
|
|
* return value EVAL_CPS_STATE_PAUSED.
|
|
|
|
*/
|
2022-09-04 07:08:58 -07:00
|
|
|
void lbm_pause_eval(void);
|
2022-02-01 11:40:07 -08:00
|
|
|
/** Pause the evaluator and perform GC if needed.
|
|
|
|
*
|
|
|
|
* \param num_free Perform GC if there are less than this many elements free on the heap.
|
|
|
|
*/
|
2022-09-04 07:08:58 -07:00
|
|
|
void lbm_pause_eval_with_gc(uint32_t num_free);
|
2022-01-29 08:26:45 -08:00
|
|
|
/** Perform a single step of evaluation.
|
|
|
|
* The evaluator should be in EVAL_CPS_STATE_PAUSED before running this function.
|
|
|
|
* After taking one step of evaluation, the evaluator will return to being in the
|
|
|
|
* EVAL_CPS_STATE_PUASED state.
|
|
|
|
*/
|
2022-09-04 07:08:58 -07:00
|
|
|
void lbm_step_eval(void);
|
2022-02-03 03:49:33 -08:00
|
|
|
/** Perform multiple steps of evaluation.
|
|
|
|
* \param n Number of eval steps to perform.
|
|
|
|
*/
|
2022-09-04 07:08:58 -07:00
|
|
|
void lbm_step_n_eval(uint32_t n);
|
2022-01-29 08:26:45 -08:00
|
|
|
/** Resume from being in EVAL_CPS_STATE_PAUSED.
|
|
|
|
*
|
|
|
|
*/
|
2022-09-04 07:08:58 -07:00
|
|
|
void lbm_continue_eval(void);
|
2022-01-29 08:26:45 -08:00
|
|
|
/** This will kill the evaluator on the next iteration.
|
|
|
|
*
|
|
|
|
*/
|
2022-09-04 07:08:58 -07:00
|
|
|
void lbm_kill_eval(void);
|
2022-01-29 08:26:45 -08:00
|
|
|
/** Get the current state of the evaluator.
|
|
|
|
*
|
|
|
|
* \return Current state of the evaluator.
|
|
|
|
*/
|
2022-09-04 07:08:58 -07:00
|
|
|
uint32_t lbm_get_eval_state(void);
|
2022-03-10 07:29:11 -08:00
|
|
|
/** Provide a description of an error as a string.
|
|
|
|
* Use when implementing for example extensions to
|
|
|
|
* report an error message to the programmer in case
|
|
|
|
* the extension is used incorrectly.
|
|
|
|
*
|
2022-05-09 07:24:00 -07:00
|
|
|
* The error string can be allocated in lbm_memory
|
2022-03-10 07:29:11 -08:00
|
|
|
* and will in that case be freed when the context
|
|
|
|
* that errored is removed.
|
|
|
|
* \param error_str
|
|
|
|
* \return 1 on success and 0 on failure.
|
|
|
|
*/
|
2022-09-04 07:08:58 -07:00
|
|
|
int lbm_set_error_reason(char *error_str);
|
2022-02-01 11:40:07 -08:00
|
|
|
/** Create a context and enqueue it as runnable.
|
|
|
|
*
|
|
|
|
* \param program The program to evaluate in the context.
|
|
|
|
* \param env An initial environment.
|
|
|
|
* \param stack_size Stack size for the context.
|
|
|
|
* \return
|
|
|
|
*/
|
2022-09-04 07:08:58 -07:00
|
|
|
lbm_cid lbm_create_ctx(lbm_value program, lbm_value env, lbm_uint stack_size);
|
2022-05-03 13:58:33 -07:00
|
|
|
/** Block a context from an extension
|
|
|
|
*/
|
2022-09-04 07:08:58 -07:00
|
|
|
void lbm_block_ctx_from_extension(void);
|
2022-05-03 13:58:33 -07:00
|
|
|
/** Unblock a context that has been blocked by a C extension
|
|
|
|
* Trying to unblock a context that is waiting on a message
|
|
|
|
* in a mailbox is not encouraged
|
|
|
|
* \param cid Lisp process to wake up.
|
|
|
|
* \param result Value passed to the lisp process as the result from the blocking function.
|
|
|
|
*/
|
2022-09-04 07:08:58 -07:00
|
|
|
bool lbm_unblock_ctx(lbm_cid cid, lbm_value result);
|
2022-01-29 08:26:45 -08:00
|
|
|
/** Iterate over all ready contexts and apply function on each context.
|
|
|
|
*
|
|
|
|
* \param f Function to apply to each context.
|
|
|
|
* \param arg1 Pointer argument that can be used to convey information back to user
|
|
|
|
* \param arg2 Same as above.
|
|
|
|
*/
|
2022-09-04 07:08:58 -07:00
|
|
|
void lbm_running_iterator(ctx_fun f, void*, void*);
|
2022-01-29 08:26:45 -08:00
|
|
|
/** Iterate over all blocked contexts and apply function on each context.
|
|
|
|
*
|
|
|
|
* \param f Function to apply to each context.
|
|
|
|
* \param arg1 Pointer argument that can be used to convey information back to user
|
|
|
|
* \param arg2 Same as above
|
|
|
|
*/
|
2022-09-04 07:08:58 -07:00
|
|
|
void lbm_blocked_iterator(ctx_fun f, void*, void*);
|
2022-01-29 08:26:45 -08:00
|
|
|
/** Iterate over all done contexts and apply function on each context.
|
|
|
|
*
|
|
|
|
* \param f Function to apply to each context.
|
|
|
|
* \param arg1 Pointer argument that can be used to convey information back to user
|
|
|
|
* \param arg2 Same as above
|
|
|
|
*/
|
2022-09-04 07:08:58 -07:00
|
|
|
void lbm_done_iterator(ctx_fun f, void*, void*);
|
2022-04-03 03:26:23 -07:00
|
|
|
/** toggle verbosity level of error messages
|
|
|
|
*/
|
2022-09-04 07:08:58 -07:00
|
|
|
void lbm_toggle_verbose(void);
|
2022-04-03 03:26:23 -07:00
|
|
|
/** Set verbosity level of lispbm error messages.
|
|
|
|
*
|
|
|
|
* \param verbose Boolean to turn verbose errors on or off.
|
|
|
|
*/
|
2022-09-04 07:08:58 -07:00
|
|
|
void lbm_set_verbose(bool verbose);
|
2022-01-29 08:26:45 -08:00
|
|
|
/** Set a usleep callback for use by the evaluator thread.
|
|
|
|
*
|
|
|
|
* \param fptr Pointer to a sleep function.
|
|
|
|
*/
|
2022-09-04 07:08:58 -07:00
|
|
|
void lbm_set_usleep_callback(void (*fptr)(uint32_t));
|
2022-01-29 08:26:45 -08:00
|
|
|
/** Set a timestamp callback for use by the evaluator thread.
|
|
|
|
*
|
|
|
|
* \param fptr Pointer to a timestamp generating function.
|
|
|
|
*/
|
2022-09-04 07:08:58 -07:00
|
|
|
void lbm_set_timestamp_us_callback(uint32_t (*fptr)(void));
|
2022-01-29 08:26:45 -08:00
|
|
|
/** Set a "done" callback function. This function will be called by
|
|
|
|
* the evaluator when a context finishes execution.
|
|
|
|
*
|
|
|
|
* \param fptr Pointer to a "done" function.
|
|
|
|
*/
|
2022-09-04 07:08:58 -07:00
|
|
|
void lbm_set_ctx_done_callback(void (*fptr)(eval_context_t *));
|
2022-02-27 14:16:13 -08:00
|
|
|
/** Set a "printf" callback function. This function will be called by
|
|
|
|
* the evaluator to report error strings back to the user.
|
|
|
|
*
|
|
|
|
* \param fptr Pointer to a "printf" function.
|
|
|
|
*/
|
2022-09-04 07:08:58 -07:00
|
|
|
void lbm_set_printf_callback(int (*prnt)(const char*, ...));
|
2022-02-23 11:30:52 -08:00
|
|
|
/** Set a callback for dynamically loading code associated with
|
|
|
|
* an undefined symbol
|
|
|
|
*/
|
2022-09-04 07:08:58 -07:00
|
|
|
void lbm_set_dynamic_load_callback(bool (*fptr)(const char *, const char **));
|
2022-04-24 03:34:49 -07:00
|
|
|
/** Set a callback that is run when reading source is finishes
|
|
|
|
* within a context
|
|
|
|
*/
|
2022-09-04 07:08:58 -07:00
|
|
|
void lbm_set_reader_done_callback(void (*fptr)(lbm_cid));
|
2022-05-03 13:58:33 -07:00
|
|
|
/** Get the CID of the currently executing context.
|
|
|
|
* Should be called from an extension where there is
|
|
|
|
* a guarantee that a context is running
|
|
|
|
*/
|
2022-09-04 07:08:58 -07:00
|
|
|
lbm_cid lbm_get_current_cid(void);
|
2022-05-03 13:58:33 -07:00
|
|
|
|
2022-09-16 00:25:46 -07:00
|
|
|
bool create_string_channel(char *str, lbm_value *res);
|
|
|
|
bool lift_char_channel(lbm_char_channel_t *ch, lbm_value *res);
|
2022-01-29 08:26:45 -08:00
|
|
|
|
2022-02-01 11:40:07 -08:00
|
|
|
/** deliver a message
|
2022-01-29 08:26:45 -08:00
|
|
|
*
|
2022-02-01 11:40:07 -08:00
|
|
|
* \param cid Process to deliver to.
|
|
|
|
* \param msg Message to deliver
|
|
|
|
* \return lbm_enc_sym(SYM_NIL) on failure and lbm_enc_sym(SYM_TRUE) on success.
|
2022-01-29 08:26:45 -08:00
|
|
|
*/
|
2022-09-04 07:08:58 -07:00
|
|
|
lbm_value lbm_find_receiver_and_send(lbm_cid cid, lbm_value msg);
|
2022-03-05 17:01:41 -08:00
|
|
|
/** Perform garbage collection,
|
|
|
|
* If this is called from another thread than the eval thread, evaluation must be
|
|
|
|
* paused! Or there will be lots of trouble!
|
|
|
|
*
|
|
|
|
* \return 1 on success
|
|
|
|
*/
|
2022-09-04 07:08:58 -07:00
|
|
|
int lbm_perform_gc(void);
|
|
|
|
|
|
|
|
#ifdef __cplusplus
|
|
|
|
}
|
|
|
|
#endif
|
2022-01-29 08:26:45 -08:00
|
|
|
#endif
|