1 Bootstrap builder.
$PWD/buildsystem/flx_rtl.py
import fbuild from fbuild.functools import call from fbuild.path import Path from fbuild.record import Record from fbuild.builders.file import copy import buildsystem from buildsystem.config import config_call # ------------------------------------------------------------------------------ def build_runtime(phase): path = Path(phase.ctx.buildroot/'share'/'src', 'rtl') print("[fbuild] [rtl] MAKING RTL ******* ") srcs = [f for f in Path.glob(path / '*.cpp')] includes = [ phase.ctx.buildroot / 'host/lib/rtl', phase.ctx.buildroot / 'share/lib/rtl' ] macros = ['BUILD_RTL'] libs = [ call('buildsystem.flx_uint256_t.build_runtime', phase), #call('buildsystem.flx_integer.build_runtime', phase), call('buildsystem.flx_strutil.build_runtime', phase), call('buildsystem.flx_dynlink.build_runtime', phase), call('buildsystem.flx_async.build_runtime', phase), call('buildsystem.flx_exceptions.build_runtime', phase), call('buildsystem.flx_gc.build_runtime', phase), ] dlfcn_h = config_call('fbuild.config.c.posix.dlfcn_h', phase.platform, phase.cxx.static, phase.cxx.shared) if dlfcn_h.dlopen: external_libs = dlfcn_h.external_libs else: external_libs = [] dst = 'host/lib/rtl/flx' return Record( static=buildsystem.build_cxx_static_lib(phase, dst, srcs, includes=includes, macros=macros, libs=[lib.static for lib in libs], external_libs=external_libs), shared=buildsystem.build_cxx_shared_lib(phase, dst, srcs, includes=includes, macros=macros, libs=[lib.shared for lib in libs], external_libs=external_libs))
2 Compiler Support
share/lib/rtl/flx_compiler_support_headers.hpp
#ifndef __FLX_COMPILER_SUPPORT_HEADERS_H__ #define __FLX_COMPILER_SUPPORT_HEADERS_H__ #include "flx_rtl_config.hpp" #if defined(FLX_PTF_STATIC_STRUCT) || defined(FLX_PTF_STATIC_PTR) #error "FLX_PTF_STATIC_STRUCT and FLX_PTF_STATIC_PTR no longer supported" #endif //#define PTF ptf-> #define FLX_POINTER_TO_THREAD_FRAME ptf #define FLX_DCL_THREAD_FRAME #if FLX_CGOTO #define FLX_LOCAL_LABEL_VARIABLE_TYPE void* #define FLX_PC_DECL void *pc; #define FLX_KILLPC pc = &&_flx_dead_frame; #define FLX_RESETPC pc = nullptr; #else #define FLX_PC_DECL int pc; #define FLX_LOCAL_LABEL_VARIABLE_TYPE int #define FLX_KILLPC pc = -1; #define FLX_RESETPC pc = 0; #endif // THESE ARE NOT CURRENTLY USED // The intent is that we can use a consistent name for some structural types // across compilation boundaries by using C++ template names. // The templates are never defined, just declared. // The types are defined with the old way, but as a specialisation // of the template. The existing structure names become typedefs // to that template. So the body of code is otherwise unchanged, // but the C++ mangled name will be the same in all compilations. // THE PROBLEM is it only works if the component types do not recursively // refer to the whole type, because C++ cannot handle recursive type // combinators. #define t typename #define t2 t,t #define t3 t,t,t #define t4 t,t,t,t #define p template < #define s > struct template <typename, int> struct _fix; // fixpoint template <t,t> struct _ft; // function template <t,t> struct _cft; // cfunction template <t,int> struct _at; // array template <t> struct _pt; // procedure p t2 s _tt2; // tuples p t3 s _tt3; p t4 s _tt4; p t,t4 s _tt5; p t2,t4 s _tt6; p t3,t4 s _tt7; #undef t #undef t2 #undef t3 #undef t4 #undef p #undef s #endif
share/lib/rtl/flx_compiler_support_bodies.hpp
#ifndef __FLX_COMPILER_SUPPORT_BODIES_H__ #define __FLX_COMPILER_SUPPORT_BODIES_H__ #include "flx_compiler_support_headers.hpp" #include <algorithm> // // convert an rvalue to an lvalue template<typename T> T const &lvalue(T const &x) { return x; } // this reinterpret cast works with rvalues too template<typename T, typename U> T &reinterpret(U const &x) { return reinterpret_cast<T&>(const_cast<U&>(x)); } // convert any pointer to any other: the T should be a pointer. template<typename T, typename U> T reinterpret(U const *x) { return reinterpret_cast<T>(const_cast<U*>(x)); } // convert any pointer to non-const to any other: the T should be a pointer. template<typename T, typename U> T reinterpret(U *x) { return reinterpret_cast<T>(x); } // dflt init template<typename T> void dflt_init(T *p){ new(p) T(); } // destroy object template<typename T> void destroy(T *p){ p->T::~T(); } // copy initialise template<typename T> void copy_init (T *dst, T *src) { new(dst) T(*src); } // move initialise template<typename T> void move_init (T *dst, T *src) { new(dst) T(::std::move(*src)); } // move initialise, destroy src template<typename T> void dmove_init (T *dst, T *src) { new(dst) T(::std::move(*src)); destroy (src); } // copy assign template<typename T> void copy_assign (T *dst, T *src) { *dst = *src; } // move assign template<typename T> void move_assign (T *dst, T *src) { *dst = ::std::move(*src); } // move assign, destroy src template<typename T> void dmove_assign (T *dst, T *src) { *dst = ::std::move(*src); destroy (src); } class ValueType { virtual size_t object_size_impl()=0; virtual size_t object_alignment_impl()=0; virtual void dflt_init_impl (void *)=0; virtual void destroy_impl (void *)=0; virtual void copy_init_impl(void *, void *)=0; virtual void move_init_impl(void *, void *)=0; virtual void copy_assign_impl(void *, void *)=0; virtual void move_assign_impl(void *, void *)=0; public: size_t object_size() { return object_size_impl(); } size_t object_alignment() { return object_size_impl(); } void dflt_init(void *dst) { dflt_init_impl(dst); } void destroy(void *dst) { destroy_impl (dst); } void copy_init (void *dst, void *src) { copy_init_impl(dst,src); } void move_init (void *dst, void *src) { move_init_impl(dst,src); } void copy_assign(void *dst, void *src) { copy_assign_impl(dst,src); } void move_assign(void *dst, void *src) { move_assign_impl(dst,src); } }; template<typename T> class CxxValueType : public virtual ValueType { size_t object_size_impl() { return sizeof(T); } size_t object_alignment_impl() { return alignof(T); } void dflt_init_impl(void *dst) { ::dflt_init<T>((T*)dst); } void destroy_impl(void *dst) { ::dflt_init<T>((T*)dst); } void copy_init_impl(void *dst, void *src) { ::copy_init<T>((T*)dst,(T*)src); } void move_init_impl(void *dst, void *src) { ::move_init<T>((T*)dst,(T*)src); } void copy_assign_impl(void *dst, void *src) { ::copy_assign<T>((T*)dst,(T*)src); } void move_assign_impl(void *dst, void *src) { ::move_assign<T>((T*)dst,(T*)src); } }; // object does NOT own the product description array // should use a shared pointer thing I guess class ProductType : public virtual ValueType { size_t n; ValueType **cp; public: ProductType (ValueType **p, size_t m) : cp(p), n(m) {} ~ProductType(); size_t object_size_impl() override; size_t object_alignment_impl() override; void dflt_init_impl (void *) override; void destroy_impl (void *) override; void copy_init_impl(void *, void *) override; void move_init_impl(void *, void *) override; void copy_assign_impl(void *, void *) override; void move_assign_impl(void *, void *) override; }; // special names for tuples with only a few components template<typename T0, typename T1> struct _tt2 { T0 mem_0; T1 mem_1; _tt2() {} _tt2 (T0 _a0, T1 _a1) : mem_0(_a0), mem_1(_a1) {} }; template<typename T0, typename T1, typename T2> struct _tt3 { T0 mem_0; T1 mem_1; T2 mem_2; _tt3() {} _tt3 (T0 _a0, T1 _a1, T2 _a2) : mem_0(_a0), mem_1(_a1),mem_2(_a2) {} }; template<typename T0, typename T1, typename T2, typename T3> struct _tt4 { T0 mem_0; T1 mem_1; T2 mem_2; T3 mem_3; _tt4() {} _tt4 (T0 _a0, T1 _a1, T2 _a2, T3 _a3) : mem_0(_a0), mem_1(_a1),mem_2(_a2), mem_3(_a3) {} }; template<typename T0, typename T1, typename T2, typename T3, typename T4> struct _tt5 { T0 mem_0; T1 mem_1; T2 mem_2; T3 mem_3; T4 mem_4; _tt5() {} _tt5 (T0 _a0, T1 _a1, T2 _a2, T3 _a3, T4 _a4) : mem_0(_a0), mem_1(_a1),mem_2(_a2), mem_3(_a3), mem_4(_a4) {} }; //----------------------------------------- // C function types // Felix cannot handle these in type specifications so we have to give aliases. // // Usage is like this: // type myfun1[R] = "type11>::cfun" //----------------------------------------- template<class R> struct _type1 { typedef R (*cfun)(void); typedef void (*cproc)(R); }; template<class R,class P1> struct _type2 { typedef R (*cfun)(P1); typedef void (*cproc)(R,P1); }; template<class R,class P1, class P2> struct _type3 { typedef R (*cfun)(P1,P2); typedef void (*cproc)(R,P1,P2); }; template<class R,class P1, class P2, class P3> struct _type4 { typedef R (*cfun)(P1,P2,P3); typedef void (*cproc)(R,P1,P2,P3); }; template<class R,class P1, class P2, class P3, class P4> struct _type5 { typedef R (*cfun)(P1,P2,P3,P4); typedef void (*cproc)(R,P1,P2,P3,P4); }; #define FLX_EXEC_FAILURE(f,op,what) \ throw ::flx::rtl::flx_exec_failure_t (f,op,what) #define FLX_HALT(f,sl,sc,el,ec,s) \ throw ::flx::rtl::flx_halt_t (::flx::rtl::flx_range_srcref_t(f,sl,sc,el,ec),__FILE__,__LINE__,s) // note call should be trace(&v,...) however that requires // compiler support to make a trace record for each tracepoint // so we use NULL for now #ifdef FLX_ENABLE_TRACE #define FLX_TRACE(v,f,sl,sc,el,ec,s) \ ::flx::rtl::flx_trace (NULL,::flx::rtl::flx_range_srcref_t(f,sl,sc,el,ec),__FILE__,__LINE__,s) #else #define FLX_TRACE(v,f,sl,sc,el,ec,s) #endif #define FLX_MATCH_FAILURE(f,sl,sc,el,ec) \ throw ::flx::rtl::flx_match_failure_t (::flx::rtl::flx_range_srcref_t(f,sl,sc,el,ec),__FILE__,__LINE__) #define FLX_DROPTHRU_FAILURE(f,sl,sc,el,ec) \ throw ::flx::rtl::flx_dropthru_failure_t (::flx::rtl::flx_range_srcref_t(f,sl,sc,el,ec),__FILE__,__LINE__) #define FLX_ASSERT_FAILURE(f,sl,sc,el,ec) \ throw ::flx::rtl::flx_assert_failure_t (::flx::rtl::flx_range_srcref_t(f,sl,sc,el,ec),__FILE__,__LINE__) #define FLX_ASSERT2_FAILURE(f,sl,sc,el,ec,f2,sl2,sc2,el2,ec2) \ throw ::flx::rtl::flx_assert2_failure_t (\ ::flx::rtl::flx_range_srcref_t(f,sl,sc,el,ec),\ ::flx::rtl::flx_range_srcref_t(f2,sl2,sc2,el2,sc2),\ __FILE__,__LINE__) #define FLX_AXIOM_CHECK_FAILURE(f,sl,sc,el,ec,f2,sl2,sc2,el2,ec2) \ throw ::flx::rtl::flx_axiom_check_failure_t (\ ::flx::rtl::flx_range_srcref_t(f,sl,sc,el,ec),\ ::flx::rtl::flx_range_srcref_t(f2,sl2,sc2,el2,sc2),\ __FILE__,__LINE__) #define FLX_RANGE_FAILURE(mi,v,ma,f,sl,sc,el,ec) \ throw ::flx::rtl::flx_range_failure_t (mi,v,ma,::flx::rtl::flx_range_srcref_t(f,sl,sc,el,ec),__FILE__,__LINE__) // for generated code in body file #define INIT_PC pc=0; ///< interior program counter #if FLX_CGOTO #ifdef __clang__ #define FLX_START_SWITCH (&&_start_switch); _start_switch: if(pc)goto *pc; #else #define FLX_START_SWITCH _start_switch: if(pc)goto *pc; #endif #define FLX_LOCAL_LABEL_ADDRESS(x) &&case_##x #define FLX_SET_PC(x) pc=&&case_##x; #define FLX_CASE_LABEL(x) case_##x:; #define FLX_DECLARE_LABEL(n,i,x) \ extern void f##i##_##n##_##x(void) __asm__("l"#i"_"#n"_"#x); #define FLX_LABEL(n,i,x) x:\ __asm__(".global l"#i"_"#n"_"#x);\ __asm__("l"#i"_"#n"_"#x":");\ __asm__(""::"g"(&&x)); #define FLX_FARTARGET(n,i,x) (void*)&f##i##_##n##_##x #define FLX_END_SWITCH \ _flx_dead_frame: throw ::flx::rtl::flx_dead_frame_failure_t(__FILE__,__LINE__); #else #define FLX_START_SWITCH _start_switch: switch(pc){case 0:; #define FLX_LOCAL_LABEL_ADDRESS(x) x #define FLX_SET_PC(x) pc=x; #define FLX_CASE_LABEL(x) case x:; #define FLX_DECLARE_LABEL(n,i,x) #define FLX_LABEL(n,i,x) case n: x:; #define FLX_FARTARGET(n,i,x) n #define FLX_END_SWITCH \ case -1: throw ::flx::rtl::flx_dead_frame_failure_t(__FILE__,__LINE__);\ default: throw ::flx::rtl::flx_switch_failure_t(__FILE__,__LINE__); } #endif // // We do a direct long jump to a target as follows: // // If the target frame is just ourself (this) // we set the pc and just goto the start of the procedure, // allowing the switch/computed goto there to do the local jump. // // If the target is foreign, we force the foreign frame pc // to the target pc, and then return that frame to the driver // so it will resume that procedure, executing the starting switch, // which now jumps to the required location. // #define FLX_DIRECT_LONG_JUMP(ja) \ { \ ::flx::rtl::jump_address_t j = ja; \ if(j.target_frame == this) { \ pc = j.local_pc; \ goto _start_switch; \ } else { \ j.target_frame->pc = j.local_pc; \ return j.target_frame; \ } \ } #define FLX_RETURN \ { \ con_t *tmp = _caller; \ _caller = 0; \ return tmp; \ } #define FLX_NEWP(x) new(*ptf->gcp,x##_ptr_map,true)x #define FLX_FINALISER(x) \ static void x##_finaliser(::flx::gc::generic::collector_t *, void *__p){\ ((x*)__p)->~x();\ } //#define FLX_FMEM_INIT_ONLY : ptf(_ptf) //#define FLX_FMEM_INIT : ptf(_ptf), //#define FLX_FPAR_PASS_ONLY ptf //#define FLX_FPAR_PASS ptf, //#define FLX_APAR_PASS_ONLY _ptf //#define FLX_APAR_PASS _ptf, //#define _PTF _ptf-> //#define _PTFV _ptf #define FLX_DEF_THREAD_FRAME #define FLX_FRAME_WRAPPERS(mname,name) \ extern "C" FLX_EXPORT mname::thread_frame_t *name##_create_thread_frame(\ ::flx::gc::generic::gc_profile_t *gcp,\ ::flx::run::flx_world *world\ ) {\ mname::thread_frame_t *p = new(*gcp,mname::thread_frame_t_ptr_map,false) mname::thread_frame_t();\ p->world = world;\ p->gcp = gcp;\ return p;\ } // init is a heap procedure #define FLX_START_WRAPPER(mname,name,x)\ extern "C" FLX_EXPORT ::flx::rtl::con_t *name##_flx_start(\ mname::thread_frame_t *__ptf,\ int argc,\ char **argv,\ FILE *stdin_,\ FILE *stdout_,\ FILE *stderr_\ ) {\ __ptf->argc = argc;\ __ptf->argv = argv;\ __ptf->flx_stdin = stdin_;\ __ptf->flx_stdout = stdout_;\ __ptf->flx_stderr = stderr_;\ return (new(*__ptf->gcp,mname::x##_ptr_map,false) \ mname::x(__ptf)) ->call(0);\ } // init is a stack procedure #define FLX_STACK_START_WRAPPER_PTF(mname,name,x)\ extern "C" FLX_EXPORT ::flx::rtl::con_t *name##_flx_start(\ mname::thread_frame_t *__ptf,\ int argc,\ char **argv,\ FILE *stdin_,\ FILE *stdout_,\ FILE *stderr_\ ) {\ __ptf->argc = argc;\ __ptf->argv = argv;\ __ptf->flx_stdin = stdin_;\ __ptf->flx_stdout = stdout_;\ __ptf->flx_stderr = stderr_;\ mname::x(__ptf).stack_call();\ return 0;\ } // init is a stack procedure, no PTF #define FLX_STACK_START_WRAPPER_NOPTF(mname,name,x)\ extern "C" FLX_EXPORT ::flx::rtl::con_t *name##_flx_start(\ mname::thread_frame_t *__ptf,\ int argc,\ char **argv,\ FILE *stdin_,\ FILE *stdout_,\ FILE *stderr_\ ) {\ __ptf->argc = argc;\ __ptf->argv = argv;\ __ptf->flx_stdin = stdin_;\ __ptf->flx_stdout = stdout_;\ __ptf->flx_stderr = stderr_;\ mname::x().stack_call();\ return 0;\ } // init is a C procedure, passed PTF #define FLX_C_START_WRAPPER_PTF(mname,name,x)\ extern "C" FLX_EXPORT ::flx::rtl::con_t *name##_flx_start(\ mname::thread_frame_t *__ptf,\ int argc,\ char **argv,\ FILE *stdin_,\ FILE *stdout_,\ FILE *stderr_\ ) {\ __ptf->argc = argc;\ __ptf->argv = argv;\ __ptf->flx_stdin = stdin_;\ __ptf->flx_stdout = stdout_;\ __ptf->flx_stderr = stderr_;\ mname::x(__ptf);\ return 0;\ } // init is a C procedure, NOT passed PTF #define FLX_C_START_WRAPPER_NOPTF(mname,name,x)\ extern "C" FLX_EXPORT ::flx::rtl::con_t *name##_flx_start(\ mname::thread_frame_t *__ptf,\ int argc,\ char **argv,\ FILE *stdin_,\ FILE *stdout_,\ FILE *stderr_\ ) {\ mname::x();\ return 0;\ } #endif
3 RTL
share/lib/rtl/flx_rtl.hpp
#ifndef __FLX_RTL_H__ #define __FLX_RTL_H__ #include "flx_rtl_config.hpp" #include "flx_exceptions.hpp" #include "flx_gc.hpp" #include "flx_serialisers.hpp" #include "flx_rtl_shapes.hpp" #include "flx_compiler_support_headers.hpp" #include "flx_compiler_support_bodies.hpp" #include "flx_continuation.hpp" #include "flx_svc.hpp" #include <string> #include <functional> #include <cstdint> #include <mutex> #include <list> #include <atomic> #include "flx_spinlock.hpp" // forward decl namespace flx {namespace run { struct RTL_EXTERN fthread_list; }} namespace flx { namespace rtl { typedef void *void_pointer; // ******************************************************** // Compact Linear Type and projection // ******************************************************** typedef ::std::uint64_t cl_t; // ******************************************************** // Felix system classes // ******************************************************** struct RTL_EXTERN muxguard; // MOVED TO flx_exceptions //struct RTL_EXTERN con_t; // continuation struct RTL_EXTERN jump_address_t; // label variable type struct RTL_EXTERN fthread_t; // f-thread struct RTL_EXTERN _uctor_; // union constructor //struct RTL_EXTERN _variant_; // variant constructor struct RTL_EXTERN schannel_t; // synchronous channel type struct RTL_EXTERN clptr_t; // pointer to compact linear product component struct RTL_EXTERN clprj_t; // compact linear projection struct RTL_EXTERN muxguard { private: muxguard() = delete; muxguard(muxguard const&) = delete; muxguard *operator=(muxguard const&)=delete; ::std::mutex *m; public: muxguard (::std::mutex *p); ~muxguard (); }; // MOVE THIS TO RTL AND PROVIDE SUITABLE RTTI SO GC KNOWS ABOUT THE FRAME POINTER struct RTL_EXTERN jump_address_t { con_t *target_frame; FLX_LOCAL_LABEL_VARIABLE_TYPE local_pc; jump_address_t (con_t *tf, FLX_LOCAL_LABEL_VARIABLE_TYPE lpc) : target_frame (tf), local_pc (lpc) {} jump_address_t () : target_frame (0), local_pc(0) {} jump_address_t (con_t *tf) : target_frame(tf), local_pc(0) {} // default copy constructor and assignment }; // ******************************************************** /// FTHREAD. Felix threads // ******************************************************** struct RTL_EXTERN fthread_t // fthread abstraction { con_t *cc; ///< current continuation fthread_t *next; ///< link to next fthread, to be used in scheduler queue and schannels ::flx::run::fthread_list *owner; ///< weak pointer to owning scheduler model object //fthread_t(); ///< dead thread, suitable for assignment //fthread_t(con_t*); ///< make thread from a continuation fthread_t(con_t*, ::flx::run::fthread_list *); ///< make thread from a continuation svc_req_t *run(); ///< run until dead or driver service request void kill(); ///< kill by detaching the continuation svc_req_t *get_svc()const; ///< get current service request of waiting thread private: // uncopyable fthread_t(fthread_t const&) = delete; void operator=(fthread_t const&) = delete; }; // ******************************************************** /// SCHANNEL. Synchronous channels // ******************************************************** struct RTL_EXTERN schannel_t { fthread_t *top; // has to be public for offsetof macro void push_reader(fthread_t *); ///< add a reader fthread_t *pop_reader(); ///< pop a reader, NULL if none void push_writer(fthread_t *); ///< add a writer fthread_t *pop_writer(); ///< pop a writer, NULL if none schannel_t(); private: // uncopyable schannel_t(schannel_t const&) = delete; void operator= (schannel_t const&) = delete; }; // ******************************************************** /// VARIANTS. Felix union type /// note: non-polymorphic, so ctor can be inline // ******************************************************** struct RTL_EXTERN _uctor_ { int variant; ///< Variant code void *data; ///< Heap variant constructor data _uctor_() : variant(-1), data(0) {} _uctor_(int i, void *d) : variant(i), data(d) {} _uctor_(int *a, _uctor_ x) : variant(a[x.variant]), data(x.data) {} }; // ******************************************************** /// VARIANTS. Felix variant type /// note: non-polymorphic, so ctor can be inline // ******************************************************** /* NOT USED ANY MORE struct RTL_EXTERN _variant_ { char const *vname; ///< Variant code void *vdata; ///< Heap variant constructor data _variant_() : vname(""), vdata(0) {} _variant_(char const *n, void *d) : vname(n), vdata(d) {} }; **/ // =============================================================== // COMPACT LINEAR STUFF // =============================================================== // ******************************************************** /// COMPACT LINEAR PROJECTIONS // ******************************************************** struct RTL_EXTERN clprj_t { cl_t divisor; cl_t modulus; clprj_t () : divisor(1), modulus(-1) {} clprj_t (cl_t d, cl_t m) : divisor (d), modulus (m) {} }; // reverse compose projections left \odot right inline clprj_t rcompose (clprj_t left, clprj_t right) { return clprj_t (left.divisor * right.divisor, right.modulus); } // apply projection to value inline cl_t apply (clprj_t prj, cl_t v) { return v / prj.divisor % prj.modulus; } // ******************************************************** /// COMPACT LINEAR POINTERS // ******************************************************** struct RTL_EXTERN clptr_t { cl_t *p; cl_t divisor; cl_t modulus; clptr_t () : p(0), divisor(1),modulus(-1) {} clptr_t (cl_t *_p, cl_t d, cl_t m) : p(_p), divisor(d),modulus(m) {} // upgrade from ordinary pointer clptr_t (cl_t *_p, cl_t siz) : p (_p), divisor(1), modulus(siz) {} // add projection to existing compact linear pointer clptr_t (clptr_t _p, cl_t div, cl_t siz) : p(_p.p), divisor (_p.divisor * div), modulus(siz) {} }; struct RTL_EXTERN const_clptr_t { cl_t const *p; cl_t divisor; cl_t modulus; const_clptr_t () : p(0), divisor(1),modulus(-1) {} const_clptr_t (cl_t const *_p, cl_t d, cl_t m) : p(_p), divisor(d),modulus(m) {} // copy constructors const_clptr_t (const_clptr_t const &x) : p(x.p), divisor(x.divisor), modulus(x.modulus) {} const_clptr_t (clptr_t const &x) : p(x.p), divisor(x.divisor), modulus(x.modulus) {} // upgrade from ordinary pointer const_clptr_t (cl_t const *_p, cl_t siz) : p (_p), divisor(1), modulus(siz) {} // add projection to existing compact linear pointer const_clptr_t (const_clptr_t _p, cl_t div, cl_t siz) : p(_p.p), divisor (_p.divisor * div), modulus(siz) {} }; // apply projection to pointer inline clptr_t applyprj (clptr_t cp, clprj_t d) { return clptr_t (cp.p, d.divisor * cp.divisor, d.modulus); } inline const_clptr_t applyprj (const_clptr_t cp, clprj_t d) { return const_clptr_t (cp.p, d.divisor * cp.divisor, d.modulus); } // dereference inline cl_t clt_deref(clptr_t q) { return *q.p / q.divisor % q.modulus; } inline cl_t clt_deref(const_clptr_t q) { return *q.p / q.divisor % q.modulus; } inline cl_t operator*(clptr_t q) { return *q.p / q.divisor % q.modulus; } inline cl_t operator*(const_clptr_t q) { return *q.p / q.divisor % q.modulus; } // storeat // NOTE: not available for const version inline void storeat (clptr_t q, cl_t v) { *q.p = *q.p - (*q.p / q.divisor % q.modulus) * q.divisor + v * q.divisor; //*q.p -= ((*q.p / q.divisor % q.modulus) - v) * q.divisor; //??? } // =============================================================== // TRACE // =============================================================== struct flx_trace_t { size_t count; int enable_trace; }; extern RTL_EXTERN int flx_enable_trace; RTL_EXTERN void flx_trace(flx_trace_t* tr,flx_range_srcref_t sr, char const *file, int line, char const *msg); }} // namespaces #endif
share/src/rtl/flx_rtl.cpp
#include "flx_rtl.hpp" #include "flx_rtl_shapes.hpp" #include <cstdio> #include <cassert> #include <cstddef> #include <stdint.h> #include "flx_exceptions.hpp" #include "flx_collector.hpp" #include "flx_serialisers.hpp" #include "flx_continuation.hpp" // main run time library code namespace flx { namespace rtl { muxguard::muxguard (::std::mutex *p): m(p) { if (m)m->lock(); } muxguard::~muxguard () { if (m)m->unlock(); } // ******************************************************** // fthread_t implementation // ******************************************************** //fthread_t::fthread_t() : cc(nullptr), next(nullptr) {} //fthread_t::fthread_t(con_t *a) : cc(a), next(nullptr) {} fthread_t::fthread_t(con_t *a, ::flx::run::fthread_list *b) : cc(a), owner(b), next(nullptr) {} void fthread_t::kill() { cc = nullptr; } svc_req_t *fthread_t::get_svc()const { return cc?cc->p_svc:nullptr; } svc_req_t *fthread_t::run() { if(!cc) return nullptr; // dead restep: cc->p_svc = nullptr; step: //fprintf(stderr,"[fthread_t::run::step] cc=%p->",cc); try { cc = cc->resume(); } catch (con_t *x) { cc = x; } //fprintf(stderr,"[fthread_t::run::step] ->%p\n",cc); if(!cc) return nullptr; // died if(cc->p_svc) { //fprintf(stderr,"[fthread_t::run::service call] ->%d\n",cc->p_svc); switch(cc->p_svc->svc_req) { /* case svc_get_fthread: // NEW VARIANT LAYOUT RULES // One less level of indirection here //**(fthread_t***)(cc->p_svc->data) = this; *(fthread_t**)(cc->p_svc->data) = this; goto restep; // handled **/ //case svc_yield: // goto restep; // we don't know what to do with the request, // so pass the buck to the driver default: return cc->p_svc; } } goto step; } // ******************************************************** // schannel_t implementation // ******************************************************** schannel_t::schannel_t () : top(nullptr) {} // PRECONDITION: channel is empty or has readers void schannel_t::push_reader(fthread_t *r) { r->next = top; top = r; } // PRECONDITION: channel is empty or has writers void schannel_t::push_writer(fthread_t *w) { w->next = top; top = (fthread_t*)((uintptr_t)w | 1u); } fthread_t *schannel_t::pop_reader() { if (top == nullptr || (uintptr_t)top & 1u) return nullptr; // NULL or low bit set fthread_t *tmp = top; top = tmp->next; tmp->next = nullptr; // for GC return tmp; } fthread_t *schannel_t::pop_writer() { if (!((uintptr_t)top & 1u)) return nullptr; // low bit clear (includes NULL case) fthread_t *tmp = (fthread_t*)((uintptr_t)top & ~(uintptr_t)1u); // mask out low bit top = tmp->next; tmp->next = nullptr; // for GC return tmp; } // ******************************************************** // trace feature // ******************************************************** int flx_enable_trace=1; size_t flx_global_trace_count=0uL; void flx_trace(flx_trace_t* tr,flx_range_srcref_t sr, char const *file, int line, char const *msg) { if(!flx_enable_trace)return; flx_global_trace_count++; if(tr) { tr->count++; if(tr->enable_trace) { fprintf(stderr,"%zu : %s\n",tr->count,msg); print_loc(stderr,sr,file,line); } } else { fprintf(stderr,"%zu : %s\n",flx_global_trace_count,msg); print_loc(stderr,sr,file,line); } } }} ProductType::~ProductType(){} size_t ProductType::object_size_impl() { size_t s = 0; for (int i=0; i<n; ++i) s+=cp[i]->object_size(); return s; } size_t ProductType::object_alignment_impl() { size_t s = 0; for (int i=0; i<n; ++i) s = ::std::max(s,cp[i]->object_alignment()); return s; } // if a is aligned then a%amt == 0 // otherwise a%amt is the amount over the previously aligned // address, so we subtract it to get the previously aligned address // and then add the amt back to get the next one. uintptr_t round_up (uintptr_t a, size_t amt) { size_t adj = a % amt; return adj? a + amt - a%amt:a; } #define INCR(p,a) *(unsigned char **)p += a; void *round_up (void *a, size_t amt) { return (void*)round_up((uintptr_t)a, amt); } void ProductType::dflt_init_impl (void *p) { for (int i = 0; i<n; ++i) { auto vt = cp[i]; p = round_up(p,vt->object_alignment()); vt->dflt_init(p); INCR(p,vt->object_size()); } }; void ProductType::destroy_impl (void *p) { for (int i = 0; i<n; ++i) { auto vt = cp[i]; p = round_up(p,vt->object_alignment()); vt->destroy(p); INCR(p,vt->object_size()); } } void ProductType::copy_init_impl(void *dst, void *src) { for (int i = 0; i<n; ++i) { auto vt = cp[i]; auto align = vt->object_alignment(); src = round_up(src,align); dst = round_up(dst,align); vt->copy_init(dst,src); auto z = vt->object_size(); INCR(src,z); INCR(dst,z); } } void ProductType::move_init_impl(void *dst, void *src) { for (int i = 0; i<n; ++i) { auto vt = cp[i]; auto align = vt->object_alignment(); src = round_up(src,align); dst = round_up(dst,align); vt->move_init(dst,src); auto z = vt->object_size(); INCR(src, z); INCR(dst, z); } } void ProductType::copy_assign_impl(void *dst, void *src) { for (int i = 0; i<n; ++i) { auto vt = cp[i]; auto align = vt->object_alignment(); src = round_up(src,align); dst = round_up(dst,align); vt->copy_assign(dst,src); auto z = vt->object_size(); INCR(src, z); INCR(dst, z); } } void ProductType::move_assign_impl(void *dst, void *src) { for (int i = 0; i<n; ++i) { auto vt = cp[i]; auto align = vt->object_alignment(); src = round_up(src,align); dst = round_up(dst,align); vt->move_assign(dst,src); auto z = vt->object_size(); INCR(src, z); INCR(dst, z); } }
4 Exec Util
share/lib/rtl/flx_executil.hpp
#ifndef FLX_EXECUTIL #define FLX_EXECUTIL #include "flx_rtl_config.hpp" #include "flx_rtl.hpp" #include "flx_sync.hpp" #include "flx_gc.hpp" namespace flx { namespace rtl { namespace executil { RTL_EXTERN void run(flx::rtl::con_t *c); RTL_EXTERN void frun (::flx::gc::generic::gc_profile_t* gcp, ::flx::rtl::con_t *p); }}} #endif
share/src/rtl/flx_executil.cpp
#include "flx_executil.hpp" namespace flx { namespace rtl { namespace executil { // badly named, this procedure just runs a Felix procedure, with minimal support // no handling of coroutine stuff or svc is supported void run(::flx::rtl::con_t *p) { //fprintf(stderr,"Starting executil::run\n"); while(p) { try { p=p->resume(); } catch (::flx::rtl::con_t *x) { p = x; } } } // This utility provides more support for synchronous scheduling // operations, supporting channel I/O etc but not async stuff like svc general void frun (::flx::gc::generic::gc_profile_t* gcp, ::flx::rtl::con_t *p) { //fprintf(stderr, "Starting executil::frun\n"); ::flx::run::fthread_list *q = new(*gcp,::flx::run::fthread_list_ptr_map,false) ::flx::run::fthread_list(gcp); ::flx::run::sync_sched *ss = new(*gcp,::flx::run::sync_sched_ptr_map,false) ::flx::run::sync_sched(false, gcp, q) ; ::flx::rtl::fthread_t *ft = new(*gcp,::flx::rtl::_fthread_ptr_map,false) ::flx::rtl::fthread_t(p,q) ; gcp->collector->add_root(ss); // this code should check the termination condition and BUG OUT // is the client code caused a delegation eg svc general ss->frun(); gcp->collector->remove_root(ss); } }}}
$PWD/src/config/flx_executil.fpc
Name: flx_executil Description: Felix mini scheduler Requires: flx includes: '"flx_executil.hpp"'
5 Main
share/src/rtl/flx_main.cpp
#include "flx_rtl_config.hpp" #include "flx_rtl.hpp" // THIS IS A DO NOTHING MAINLINE FOR USE WHEN STATICALLY LINKING #include "stdio.h" extern "C" RTL_EXTERN ::flx::rtl::con_t *flx_main( void *p){ //fprintf(stderr, "DUMMY flx_main()\n"); return 0; }
6 Shapes
share/lib/rtl/flx_rtl_shapes.hpp
#ifndef __FLX_RTL_SHAPES_HPP__ #define __FLX_RTL_SHAPES_HPP__ #include "flx_rtl_config.hpp" #include "flx_gc.hpp" namespace flx { namespace rtl { // ******************************************************** // Shape (RTTI) objects for system classes // con_t is only an abstract base, so has no fixed shape // shapes for instance types generated by Felix compiler // we provide a shape for C 'int' type as well // ******************************************************** // special: just the offset data for a pointer RTL_EXTERN extern ::flx::gc::generic::offset_data_t const _address_offset_data; RTL_EXTERN extern ::flx::gc::generic::gc_shape_t _fthread_ptr_map; RTL_EXTERN extern ::flx::gc::generic::gc_shape_t schannel_ptr_map; RTL_EXTERN extern ::flx::gc::generic::gc_shape_t _uctor_ptr_map; //RTL_EXTERN extern ::flx::gc::generic::gc_shape_t _variant_ptr_map; RTL_EXTERN extern ::flx::gc::generic::gc_shape_t _int_ptr_map; RTL_EXTERN extern ::flx::gc::generic::gc_shape_t _address_ptr_map; //RTL_EXTERN extern ::flx::gc::generic::gc_shape_t _caddress_ptr_map; RTL_EXTERN extern ::flx::gc::generic::gc_shape_t clptr_t_ptr_map; RTL_EXTERN extern ::flx::gc::generic::gc_shape_t clprj_t_ptr_map; RTL_EXTERN extern ::flx::gc::generic::gc_shape_t jump_address_ptr_map; RTL_EXTERN extern ::flx::gc::generic::gc_shape_t cl_t_ptr_map; }} #endif
share/src/rtl/flx_rtl_shapes.cpp
#include "flx_rtl_shapes.hpp" #include "flx_rtl.hpp" #include "flx_dynlink.hpp" #include <stddef.h> namespace flx { namespace rtl { // ******************************************************** //OFFSETS for fthread_t // ******************************************************** static const ::flx::gc::generic::offset_entry_t _fthread_offsets[2]={ {offsetof(fthread_t,cc),nullptr}, {offsetof(fthread_t,next),nullptr} }; static ::flx::gc::generic::offset_data_t const _fthread_offset_data = { 2, _fthread_offsets }; ::flx::gc::generic::gc_shape_t _fthread_ptr_map = { "rtl::fthread_t", 1,sizeof(fthread_t), 0, 0, // fcops &_fthread_offset_data, ::flx::gc::generic::scan_by_offsets, ::flx::gc::generic::tblit<fthread_t>,::flx::gc::generic::tunblit<fthread_t>, gc::generic::gc_flags_immobile, 0UL, 0UL }; // ******************************************************** //OFFSETS for schannel_t // ******************************************************** static const ::flx::gc::generic::offset_entry_t schannel_offsets[1]={ {offsetof(schannel_t,top),nullptr} }; static ::flx::gc::generic::offset_data_t const schannel_offset_data = { 1, schannel_offsets }; ::flx::gc::generic::gc_shape_t schannel_ptr_map = { "rtl::schannel_t", 1,sizeof(schannel_t), 0, // no finaliser 0, // fcops &schannel_offset_data, // scanner data ::flx::gc::generic::scan_by_offsets, // scanner ::flx::gc::generic::tblit<schannel_t>, // encoder ::flx::gc::generic::tunblit<schannel_t>, // decoder gc::generic::gc_flags_default, 0UL, 0UL }; // ******************************************************** // _uctor_ implementation // ******************************************************** //OFFSETS for _uctor_ static const ::flx::gc::generic::offset_entry_t _uctor_offsets[1]= { {offsetof(_uctor_,data),nullptr} }; static ::flx::gc::generic::offset_data_t const _uctor_offset_data = { 1, _uctor_offsets }; static CxxValueType<_uctor_> _uctor_fcops {}; ::flx::gc::generic::gc_shape_t _uctor_ptr_map = { "rtl::_uctor_", 1, sizeof(_uctor_), 0, // finaliser &_uctor_fcops, // fcops &_uctor_offset_data, // scanner data ::flx::gc::generic::scan_by_offsets, // scanner ::flx::gc::generic::tblit<_uctor_>, // encoder ::flx::gc::generic::tunblit<_uctor_>, // decoder gc::generic::gc_flags_default }; /* // ******************************************************** // _variant_ implementation // ******************************************************** //OFFSETS for _variant_ static const std::size_t _variant_offsets[1]= { offsetof(_variant_,vdata) }; static CxxValueType<_variant_> _variant_fcops {}; static ::flx::gc::generic::offset_data_t const _variant_offset_data = { 1, _variant_offsets }; ::flx::gc::generic::gc_shape_t _variant_ptr_map = { "rtl::_variant_", 1, sizeof(_variant_), 0, // finaliser &_variant_fcops, // fcops &_variant_offset_data, // scanner data ::flx::gc::generic::scan_by_offsets, // scanner ::flx::gc::generic::tblit<_variant_>, // encoder ::flx::gc::generic::tunblit<_variant_>, // decoder gc::generic::gc_flags_default }; **/ static CxxValueType<int> int_fcops {}; // ******************************************************** // jump_address implementation // ******************************************************** //OFFSETS for jump_address static const ::flx::gc::generic::offset_entry_t jump_address_offsets[1]= { {offsetof(jump_address_t,target_frame),nullptr} }; static ::flx::gc::generic::offset_data_t const jump_address_offset_data = { 1, jump_address_offsets } ; static CxxValueType<jump_address_t> jump_address_t_fcops {}; ::flx::gc::generic::gc_shape_t jump_address_ptr_map = { "rtl::jump_address_t", 1, sizeof(_uctor_), 0, // finaliser &jump_address_t_fcops, // fcops &jump_address_offset_data, // scanner data ::flx::gc::generic::scan_by_offsets, // scanner ::flx::gc::generic::tblit<jump_address_t>, // encoder ::flx::gc::generic::tunblit<jump_address_t>, // decoder gc::generic::gc_flags_default }; // ******************************************************** // int implementation // ******************************************************** ::flx::gc::generic::gc_shape_t _int_ptr_map = { "rtl::int", 1, sizeof(int), 0, // finaliser &int_fcops, //0, // fcops 0, // scanner data 0, // scanner ::flx::gc::generic::tblit<int>, // encoder ::flx::gc::generic::tunblit<int>, // decoder gc::generic::gc_flags_default, 0UL, 0UL }; // ******************************************************** // cl_t implementation // ******************************************************** static CxxValueType<cl_t> cl_t_fcops {}; ::flx::gc::generic::gc_shape_t cl_t_ptr_map = { "rtl::cl_t", 1, sizeof(cl_t), 0, // finaliser &cl_t_fcops, // fcops 0, // scanner data 0, // scanner ::flx::gc::generic::tblit<cl_t>, ::flx::gc::generic::tunblit<cl_t>, gc::generic::gc_flags_default, 0UL, 0UL }; // ******************************************************** // clptr_t implementation // ******************************************************** static CxxValueType<clptr_t> clptr_t_fcops {}; static const ::flx::gc::generic::offset_entry_t _clptr_t_offsets[1]={ {0,nullptr} }; ::flx::gc::generic::offset_data_t const _clptr_t_offset_data = { 1, _clptr_t_offsets }; ::flx::gc::generic::gc_shape_t clptr_t_ptr_map = { "rtl::clptr_t", 1, sizeof(clptr_t), 0, // finaliser &clptr_t_fcops, // fcops &_clptr_t_offset_data, // scanner data ::flx::gc::generic::scan_by_offsets, // scanner ::flx::gc::generic::tblit<clptr_t>, ::flx::gc::generic::tunblit<clptr_t>, gc::generic::gc_flags_default, 0UL, 0UL }; // ******************************************************** // clprj_t implementation // ******************************************************** static CxxValueType<clprj_t> clprj_t_fcops {}; ::flx::gc::generic::offset_data_t const _clprj_t_offset_data = { 0, NULL }; ::flx::gc::generic::gc_shape_t clprj_t_ptr_map = { "rtl::clprj_t", 1, sizeof(clprj_t), 0, // finaliser &clprj_t_fcops, // fcops 0, // scanner data ::flx::gc::generic::scan_by_offsets, // scanner ::flx::gc::generic::tblit<clprj_t>, ::flx::gc::generic::tunblit<clprj_t>, gc::generic::gc_flags_default, 0UL, 0UL }; // ******************************************************** // pointer implementation // ******************************************************** //OFFSETS for address static const ::flx::gc::generic::offset_entry_t _address_offsets[1]={ {0,nullptr} }; ::flx::gc::generic::offset_data_t const _address_offset_data = { 1, _address_offsets }; static ::std::string address_encoder (void *p) { return ::flx::gc::generic::blit (p,sizeof (void*)); } static size_t address_decoder (void *p, char *s, size_t i) { return ::flx::gc::generic::unblit (p,sizeof (void*),s,i); } // ******************************************************** // address implementation : MUST BE LAST because the compiler // uses "address_ptr_map" as the back link for generated shape tables // ******************************************************** ::flx::gc::generic::gc_shape_t _address_ptr_map = { "rtl::address", 1, sizeof(void*), 0, // finaliser 0, // fcops &_address_offset_data, /// scanner data ::flx::gc::generic::scan_by_offsets, // scanner ::flx::gc::generic::tblit<void*>, // encoder ::flx::gc::generic::tunblit<void*>, // decoder gc::generic::gc_flags_default, 0UL, 0UL }; }}
7 Plat Linux
share/lib/rtl/plat_linux.hpp
#ifndef __PLAT_LINUX_H__ #define __PLAT_LINUX_H__ int get_cpu_nr(); #endif
share/src/rtl/plat_linux.cpp
#define STAT "/proc/stat" #include <stdio.h> #include <errno.h> #include <stdlib.h> #include <string.h> #include "plat_linux.hpp" // return number of cpus int get_cpu_nr() { FILE *fp; char line[16]; int proc_nb, cpu_nr = -1; if ((fp = fopen(STAT, "r")) == NULL) { fprintf(stderr, ("Cannot open %s: %s\n"), STAT, strerror(errno)); exit(1); } while (fgets(line, 16, fp) != NULL) { if (strncmp(line, "cpu ", 4) && !strncmp(line, "cpu", 3)) { char* endptr = NULL; proc_nb = strtol(line + 3, &endptr, 0); if (!(endptr && *endptr == '\0')) { fprintf(stderr, "unable to parse '%s' as an integer in %s\n", line + 3, STAT); exit(1); } if (proc_nb > cpu_nr) cpu_nr = proc_nb; } } fclose(fp); return (cpu_nr + 1); }
8 Macro config stuff
Here flx_rtl_config.hpp depends on flx_rtl_config.h which depends on flx_rtl_config_params.hpp which is generated by the configuration system.
share/lib/rtl/flx_rtl_config.hpp
#ifndef __FLX_RTL_CONFIG_HPP__ #define __FLX_RTL_CONFIG_HPP__ #include "flx_rtl_config.h" #include <stdint.h> // get variant index code and pointer from packed variant rep #define FLX_VP(x) ((void*)((uintptr_t)(x) & ~(uintptr_t)0x03)) #define FLX_VI(x) ((int)((uintptr_t)(x) & (uintptr_t)0x03)) // make a packed variant rep from index code and pointer #define FLX_VR(i,p) ((void*)((uintptr_t)(p)|(uintptr_t)(i))) // get variant index code and pointer from nullptr variant rep #define FLX_VNP(x) (x) #define FLX_VNI(x) ((int)(x!=0)) // make a nullptr variant rep from index code and pointer #define FLX_VNR(i,p) (p) #endif
share/lib/rtl/flx_rtl_config.h
#ifndef __FLX_RTL_CONFIG_H__ #define __FLX_RTL_CONFIG_H__ #include "flx_rtl_config_params.hpp" #include <setjmp.h> #if FLX_HAVE_GNU_BUILTIN_EXPECT #define FLX_UNLIKELY(x) __builtin_expect(long(x),0) #define FLX_LIKELY(x) __builtin_expect(long(x),1) #else #define FLX_UNLIKELY(x) x #define FLX_LIKELY(x) x #endif #define FLX_SAVE_REGS \ jmp_buf reg_save_on_stack; \ setjmp (reg_save_on_stack) // #if FLX_HAVE_CGOTO && FLX_HAVE_ASM_LABELS #define FLX_CGOTO 1 #else #define FLX_CGOTO 0 #endif #if FLX_WIN32 && !defined(_WIN32_WINNT) #define _WIN32_WINNT 0x0600 // Require Windows NT5 (2K, XP, 2K3) #endif #if FLX_WIN32 && !defined(WINVER) #define WINVER 0x0600 // Require Windows NT5 (2K, XP, 2K3) #endif #if FLX_WIN32 // vs windows.h just LOVES to include winsock version 1 headers by default. // that's bad for everyone, so quit it. #define _WINSOCKAPI_ // windows.h defines min/max macros, which can cause all sorts of confusion. #ifndef NOMINMAX #define NOMINMAX #endif #endif #if FLX_WIN32 #if defined(FLX_STATIC_LINK) #define FLX_EXPORT #define FLX_IMPORT #else #define FLX_EXPORT __declspec(dllexport) #define FLX_IMPORT __declspec(dllimport) #endif #else // All modules on Unix are compiled with -fvisibility=hidden // All API symbols get visibility default // whether or not we're static linking or dynamic linking (with -fPIC) #define FLX_EXPORT __attribute__((visibility("default"))) #define FLX_IMPORT __attribute__((visibility("default"))) #endif #ifdef BUILD_RTL #define RTL_EXTERN FLX_EXPORT #else #define RTL_EXTERN FLX_IMPORT #endif #if FLX_MACOSX && !FLX_HAVE_DLOPEN #define FLX_MACOSX_NODLCOMPAT 1 #else #define FLX_MACOSX_NODLCOMPAT 0 #endif #if FLX_HAVE_GNU #define FLX_ALWAYS_INLINE __attribute__ ((always_inline)) #define FLX_NOINLINE __attribute__ ((noinline)) #define FLX_CONST __attribute__ ((const)) #define FLX_PURE __attribute__ ((pure)) #define FLX_GXX_PARSER_HACK (void)0, #define FLX_UNUSED __attribute__((unused)) #else #define FLX_ALWAYS_INLINE #define FLX_NOINLINE #define FLX_CONST #define FLX_PURE #define FLX_GXX_PARSER_HACK #define FLX_UNUSED #endif #endif
$PWD/src/config/flx_rtl_core.fpc
Description: Felix Core Run Time Libraries Requires: flx flx_gc flx_spinlock Requires: flx_exceptions flx_pthread flx_async Requires: re2 flx_dynlink demux faio Requires: flx_uint256_t Requires: sqlite3 Requires: blake3
$PWD/src/config/flx_thread_free_rtl_core.fpc
Description: Felix Core Run Time Libraries (no threads, no async I/O) Requires: flx flx_gc flx_thread_free_run Requires: flx_exceptions Requires: re2 flx_dynlink Requires: flx_uint256_t Requires: sqlite3
$PWD/src/config/unix/flx.fpc
Name: flx Description: Felix core runtime support provides_dlib: -lflx_dynamic provides_slib: -lflx_static Requires: flx_gc flx_exceptions flx_pthread flx_dynlink library: rtl includes: '"flx_rtl.hpp"' <iostream> <cstdio> <cstddef> <cassert> <climits> <string> macros: BUILD_RTL srcdir: src/rtl src: .*\.cpp
$PWD/src/config/win/flx.fpc
Name: flx Description: Felix core runtime support provides_dlib: /DEFAULTLIB:flx_dynamic provides_slib: /DEFAULTLIB:flx_static Requires: flx_gc flx_exceptions flx_pthread flx_dynlink library: rtl includes: '"flx_rtl.hpp"' <iostream> <cstdio> <cstddef> <cassert> <climits> <string> macros: BUILD_RTL srcdir: src/rtl src: .*\.cpp