PreviousUpNext

15.4.1087  src/lib/std/src/nj/at.pkg

## at.pkg

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


# This provides a mechanism for registering at-functions
# which should be invoked at startup and/or shutdown time.

# We define five distinct contexts
# for an at-function:
#
#       FORK_TO_DISK    just prior to exporting a heap image (fork_to_disk).
#       SPAWN_TO_DISK   exit because of spawn_to_disk.
#       SHUTDOWN        normal program exit.
#       STARTUP initialization of a program that was generated by fork_to_disk.
#       APP_STARTUP     initialization of a program that was generated by spawn_to_disk.

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

###                "No pessimist ever discovered the secret of the stars,
###                 or sailed to an uncharted land, or opened a new doorway
###                 for the human spirit."
###
###                                             -- Helen Keller

                                # At    is from   src/lib/std/src/nj/at.api

package   at
: (weak)  At
{
    When
      = FORK_TO_DISK
      | SPAWN_TO_DISK
      | SHUTDOWN
      | STARTUP
      | APP_STARTUP
      ;

    all = [ FORK_TO_DISK, SPAWN_TO_DISK, SHUTDOWN, STARTUP, APP_STARTUP ];

    at_functions
        =
        REF ([]:   List( (String, List( When ), (When -> Void)) ) );


    # Return the list of at-functions
    # which satisfy 'when_predicate'. 
    #
    fun filter_by_when  when_predicate
        =
        f *at_functions
        where
            fun f [] =>  [];
                #
                f ((item as (_, when_list, _)) ! r)
                    =>
                    if (list::exists  when_predicate  when_list)    item ! (f r);
                    else                                                   (f r);
                    fi;
            end;
        end;


    # Run the at-functions for the given time.
    #
    # In some cases, this causes the list
    # of at_functions to be redefined.
    #
    # NB: We reverse the order of application at startup time.
    #
    fun run_functions_scheduled_to_run  when
        =
        {   at_fns
                =
                case when
                    #                  
                    (STARTUP | APP_STARTUP)
                        =>
                        list::reverse
                            (filter_by_when (fn w =  w == when));
                    _   =>  (filter_by_when (fn w =  w == when));
                esac;


            fun export_fn_predicate (APP_STARTUP | SHUTDOWN) =>   TRUE;
                export_fn_predicate _                        =>   FALSE;
            end;

            fun startup_fn_predicate  SHUTDOWN =>   TRUE;
                startup_fn_predicate _         =>   FALSE;
            end;

            # Remove uneccesary clean-up routines:
            #
            case when
                #              
                SPAWN_TO_DISK  =>   at_functions :=  filter_by_when  export_fn_predicate;
                APP_STARTUP    =>   at_functions :=  filter_by_when  startup_fn_predicate;
                _              =>   ();
            esac;

            # Now apply the selected at-functions:
            #
            list::apply
                (   fn (_, _, f)
                       =
                       (f when)
                       except
                           _ = ()
                )
                at_fns;
        };


    # Find and remove the named at-function
    # from the at-function list.
    #
    # Return the at-function and
    # the new at-function list.
    #
    # Return NULL if the named
    # at-function does not exist.
    #
    fun filter_by_name  fn_name
        =
        remove *at_functions
        where 
            fun remove []
                    =>
                    NULL;

                remove ((at_function as (fn_name', when_list, function_proper)) ! rest)
                    =>
                    if (fn_name == fn_name')
                        #
                        THE ((when_list, function_proper), rest);
                    else
                        case (remove rest)
                            #
                            THE (at_function', rest')
                                =>
                                THE (at_function', at_function ! rest');

                            NULL =>  NULL;
                        esac;
                    fi;
            end;
        end;


    # Add a named at-function.
    # This returns the previous definition, or NULL. 
    #
    fun schedule (at_function as (fn_name, _, _))
        =
        case (filter_by_name  fn_name)
            #     
            THE (old_at_function, new_at_function_list)
                =>
                {   at_functions :=  at_function ! new_at_function_list;
                    #
                    THE old_at_function;
                };

            NULL =>
                {   at_functions :=  at_function ! *at_functions;
                    #
                     NULL;
                };
         esac;


    # Remove and return the named at-function.
    # Return NULL if it is not found: 
    #
    fun deschedule  fn_name
        =
        case (filter_by_name  fn_name)
            #     
            THE (old_at_function, at_function_list)
                =>
                {   at_functions := at_function_list;
                    #
                    THE old_at_function;
                };

            NULL => NULL;
        esac;


};                              # at



Comments and suggestions to: bugs@mythryl.org

PreviousUpNext