PreviousUpNext

15.4.1228  src/lib/std/src/unsafe/mythryl-callable-c-library-interface.pkg

## mythryl-callable-c-library-interface.pkg
#
# See also:
#     src/c/h/mythryl-callable-c-libraries.h

# Compiled by:
#     src/lib/std/src/standard-core.sublib

stipulate
    package it  =  inline_t;                                                    # inline_t      is from   src/lib/core/init/built-in.pkg
    package rt  =  runtime;                                                     # runtime       is from   src/lib/core/init/runtime.pkg
    package sg  =  string_guts;                                                 # string_guts   is from   src/lib/std/src/string-guts.pkg
    package lst =  list;                                                        # list          is from   src/lib/std/src/list.pkg
    #
    in = list::in;
herein
    package   mythryl_callable_c_library_interface
    :         Mythryl_Callable_C_Library_Interface                              # Mythryl_Callable_C_Library_Interface  is from   src/lib/std/src/unsafe/mythryl-callable-c-library-interface.api
    {

                                                                                # for runtime see
                                                                                #     src/lib/core/init/core.pkg
                                                                                #     src/lib/core/init/runtime.pkg
                                                                                #     src/c/machine-dependent/prim.intel32.asm

        Cfunction =  rt::asm::Cfunction;

        find_cfun =  rt::asm::find_cfun;                                        # Maps ultimately to    find_cfun               in    src/c/lib/mythryl-callable-c-libraries.c

        exception  CFUN_NOT_FOUND  String;

        cfuns__local            = REF ([]: List(String));                       # See Note[1] at bottom of file.
        redirected_cfuns__local = REF ([]: List(String));                       # "                           ".
        restore_syscalls__local = REF ([]: List(Void -> Void));                 # A list of thunks which collectively restore all redirected syscalls to original direct form.

        fun restore_redirected_syscalls_to_direct_form ()                       # Restore all redirected syscalls to direct form by evaluating all thunks on  restore_syscalls__local  list.
            =
            {   apply'  *restore_syscalls__local  {. #f (); };
                #
                restore_syscalls__local :=  [];
            };

        stipulate
            fun add_name_to_namelist  namelist  name                            # 'namelist' is either cfuns__local or redirected_cfuns__local;
                =                                                               # 'name' is "posix_io::writebuf" or such.
                if (not (name in *namelist))                                    # We don't do mutex-type locking here because we should only be called early in bootstrapping, in a single-hostthread/single-app-thread context.
                    #
                    namelist :=  name ! *namelist;
                fi;
        herein
            fun note_cfun             name =  add_name_to_namelist             cfuns__local  name;                                      # Track all cfuns active in the codebase.
            fun note_redirected_cfun  name =  add_name_to_namelist  redirected_cfuns__local  name;
        end;

        fun find_c_function  { lib_name, fun_name }
            =
            {   cfun =  find_cfun (lib_name, fun_name);
                #
                                                                                if (it::cast cfun  ==  0)
                                                                                    print ("mythryl_callable_c_library_interface::find_c_function could not find " + lib_name + ":" + fun_name + "\n");
                                                                                    raise exception  CFUN_NOT_FOUND (sg::cat [lib_name, "::", fun_name]);
                                                                                fi;
                \\ x =  (rt::asm::call_cfun (cfun, x));
            };

        fun find_c_function'  { lib_name, fun_name }                            # See background comments in   src/lib/std/src/unsafe/mythryl-callable-c-library-interface.api
            =
            (refcell, redirect_refcell)
            where
                function =  find_c_function { lib_name, fun_name };
                                                                                name =  lib_name + "::" + fun_name;
                refcell  =  REF function;
                                                                                note_cfun  name;                        # Track all cfuns active in the codebase.
                fun redirect_refcell  f
                    =
                    {                                                           note_redirected_cfun  name;             # Track all redirected cfuns in the codebase.

                        refcell :=   f { lib_name,                              # Construct and install new implementation of this syscall.
                                         fun_name,
                                         io_call => function
                                       };
                    };
            end;

        fun find_c_function''  { lib_name, fun_name }                           # See background comments in   src/lib/std/src/unsafe/mythryl-callable-c-library-interface.api
            =
            (function, refcell, redirect_refcell)
            where
                function =  find_c_function { lib_name, fun_name };
                                                                                name =  lib_name + "::" + fun_name;
                refcell  =  REF function;
                                                                                note_cfun  name;                        # Track all cfuns active in the codebase.
                fun redirect_refcell  f
                    =
                    {                                                           note_redirected_cfun  name;             # Track all redirected cfuns in the codebase.

                        refcell :=   f { lib_name,                              # Construct and install new implementation of this syscall.
                                         fun_name,
                                         io_call => function
                                       };
                    };

                fun restore_syscall ()
                    =
                    refcell :=  function;

                restore_syscalls__local
                    :=
                    restore_syscall  !  *restore_syscalls__local;
            end;

        fun find_c_function'''  { lib_name, fun_name }                          # See background comments in   src/lib/std/src/unsafe/mythryl-callable-c-library-interface.api
            =
            (function, refcell, redirect_refcell, mailop_function, mailop_refcell, redirect_mailop_refcell)
            where
                function =  find_c_function { lib_name, fun_name };
                                                                                name =  lib_name + "::" + fun_name;
                refcell  =  REF function;
                                                                                note_cfun  name;                        # Track all cfuns active in the codebase.
                fun redirect_refcell  f
                    =
                    {                                                           note_redirected_cfun  name;             # Track all redirected cfuns in the codebase.

                        refcell :=   f { lib_name,                              # Construct and install new implementation of this syscall.
                                         fun_name,
                                         io_call => function
                                       };
                    };

                fun restore_syscall ()
                    =
                    refcell :=  function;

                restore_syscalls__local
                    :=
                    restore_syscall  !  *restore_syscalls__local;

                msg = "error: " + name + " not yet redirected.\n";
                mailop_function =   (\\ _ = raise exception DIE msg);
                mailop_refcell = REF mailop_function;
                fun redirect_mailop_refcell  f
                    =
                    {                                                           note_redirected_cfun  name;             # Track all redirected cfuns in the codebase.

                        mailop_refcell :=    f { lib_name,                              # Construct and install new implementation of this syscall.
                                                 fun_name,
                                                 io_call => function            # NOT mailop_function!
                                               };
                    };

                fun restore_mailop_syscall ()
                    =
                    mailop_refcell :=  mailop_function;

                restore_syscalls__local
                    :=
                    restore_mailop_syscall  !  *restore_syscalls__local;
            end;

        System_Constant =   { id: Int,  name: String };                         # This structure is exposed to clients.

        exception  SYSTEM_CONSTANT_NOT_FOUND String;

        # Linear scan down list,
        # checking for string equality
        # on list_element.name:
        #
        fun find_system_constant  (name,  system_constants: List(System_Constant))
            =
            search system_constants
            where
                fun search (system_constant ! rest)
                        =>
                        if (system_constant.name  ==  name)   THE  (system_constant:  System_Constant);
                        else                                  search rest;
                        fi;

                    search [] =>  NULL;
                end;
            end;

        fun bind_system_constant (name, l)
            =
            case (find_system_constant (name, l))
                #             
                THE sc =>   sc;
                NULL   =>   raise exception  SYSTEM_CONSTANT_NOT_FOUND name;
            esac;

    };                                                                          #  package mythryl_callable_c_library_interface 
end;


############################################################
# Note[1]                  2012-04-18
#
# There is a bootstrap problem in that the running Mythryl
# system starts with no application threads and one posix
# thread (i.e., a normal Unix process) but winds up as a
# dozen or so posix threads supporting possibly thousands
# of application threads.
#
# Stuff like disk I/O has to work in both contexts, but
# the multi-hostthread, multi-thread solution we use once
# fully booted clearly cannot be operational initially.
#
# Consequently to provide Mythryl-level access to C-level
# I/O (more generally, C-level syscalls to kernel services)
# we use two different implementations:
#
#   o During initial bootstrap we just do vanilla
#     single-hostthread single-thread syscalls -- trivial
#     except for the usual issues of communicating
#     between the Mythryl and C levels.
#
#   o Once we have posix-thread and application-thread
#     support fully booted, we switch over to indirecting
#     all syscalls through that machinery.  This means that
#     when a Mythryl app-thread invokes a function which
#     needs to perform a syscall to the kernel:
#
#      1) It calls a library fn which hides the following from it.
#
#      2) A message is sent to a separate posix-thread;
#         the app-thread blocks waiting for a threadmail reply.
#
#      3) The sacrificial posix I/O thread does the actual
#         syscall.  This will block it dead for maybe milliseconds,
#         but app-threads in the main hostthread will be able to
#         keep running, since the main hostthread is not blocked.
#
#      4) After the syscall returns, the sacrificial posix I/O
#         thread forwards the result to the main posix hostthread
#         via posix-thread mutex/condvar mechanisms.
#
#      5) In due course the main posix hostthread then wakes up
#         the original app-thread by forwarding the reply via
#         the threadmail system.
#
# To make this bi-mode system work we indirect each syscall
# through a refcell which can initially point to a trivial
# fn which just directly invokes the syscall in question,
# but which higher-level libraries can later change to
# point to a closure which performs the indirect I/O instead.

# One possible engineering problem with this is making sure
# that every such refcell does get properly updated during
# bootstrap;  there are quite a few of them and they are
# scattered through a number of files and then updated by
# various bits of logic scattered through yet other files.
#
# To track all Mythryl-visible syscalls in the codebase we use
#
#     cfuns__local

# and then to track redirected syscalls we maintain the matching
#
#     redirected_cfuns__local
#
# At the end of system bootstrap these lists should be identical
# up to ordering:  If they are not something needs fixing.
#
# (It would be convenient to make these lists be redblack
# sets-of-strings, but we are a very low-level facility
# here and I don't want introduce a dependency upon
# higher-level packages like the redblack trees.)


    
## COPYRIGHT (c) 1994 AT&T Bell Laboratories.
## Subsequent changes by Jeff Prothero Copyright (c) 2010-2015,
## released per terms of SMLNJ-COPYRIGHT.


Comments and suggestions to: bugs@mythryl.org

PreviousUpNext