PreviousUpNext

15.3.387  src/lib/src/lib/thread-kit/src/core-thread-kit/microthread-preemptive-scheduler.api

## microthread-preemptive-scheduler.api

# Compiled by:
#     src/lib/std/standard.lib

# This api is implemented in:
#
#     src/lib/src/lib/thread-kit/src/core-thread-kit/microthread-preemptive-scheduler.pkg

stipulate
    package fat =  fate;                                                                        # fate                          is from   src/lib/std/src/nj/fate.pkg
    package hth =  hostthread;                                                                  # hostthread                    is from   src/lib/std/src/hostthread.pkg
    package itt =  internal_threadkit_types;                                                    # internal_threadkit_types      is from   src/lib/src/lib/thread-kit/src/core-thread-kit/internal-threadkit-types.pkg
    package rwq =  rw_queue;                                                                    # rw_queue                      is from   src/lib/src/rw-queue.pkg
    package tim =  time;                                                                        # time                          is from   src/lib/std/time.pkg
    package wnx =  winix__premicrothread;                                                       # winix__premicrothread         is from   src/lib/std/winix--premicrothread.pkg
    #
    Fate(X)    =  fat::Fate(X);
    Microthread  =  itt::Microthread;
herein

    api Microthread_Preemptive_Scheduler {
        #
        foreground_run_queue:   rwq::Rw_Queue( (Microthread,  Fate( Void)) );                   # Referenced in         src/lib/src/lib/thread-kit/src/core-thread-kit/mailop.pkg
        background_run_queue:   rwq::Rw_Queue( (Microthread,  Fate( Void)) );                   # and                   src/lib/src/lib/thread-kit/src/glue/threadkit-base-for-os-g.pkg

        set_condvar__iu:   itt::Condition_Variable -> Void;

        get_current_microthread:  Void -> Microthread;
        set_current_microthread:  Microthread -> Void;

        push_into_run_queue:  (Microthread, Fate(Void)) -> Void;                                        # Run fate under thread when we get a chance.

        enqueue_old_thread_plus_old_fate_then_install_new_thread                                # Push (get_current_microthread(), old_fate) onto run queue, then do set_current_microthread(new_thread) and return.
            :                                                                                   # Fate of new_thread is whatever caller does upon our return.
            {   new_thread: Microthread,
                old_fate:   Fate(Void)
            }
            ->
            Void;
            #
            # Enqueue the given fate with the
            # current thread ID, and make the
            # given thread ID be the current one.


                                                                                                # Nomenclature: What I'm calling "uninterruptible mode" is usually called "critical section" or "atomic region"
                                                                                                # in the literature.  I dislike "critical" because it is vague. ("critical" in what sense? Who knows?)
                                                                                                # "atomic" is literally correct ("a-tomic" == "not cuttable" -- indivisible) but the modern reader is not
                                                                                                # likely to take it in that sense at first blush.  And neither "section" nor "region" are as apropos as "scope".
                                                                                                # (If we were going to use the term a lot I might favor "unit scope", but I do not expect we will.)
        assert_not_in_uninterruptible_scope:    String -> Void;
        enter_uninterruptible_scope:            Void -> Void;
        exit_uninterruptible_scope:             Void -> Void;
            #
            # Enter/leave a critical section.
            # These do NOT nest!

        dispatch_next_thread__xu__noreturn:  Void -> X;                                         # NEVER RETURNS TO CALLER.
            #
            # Leave the critical section
            # and dispatch the next thread.

        dispatch_next_thread__noreturn:  Void -> X;                                             # NEVER RETURNS TO CALLER.
            #
            # Dispatch the next thread.
            #
            # This should NOT be called
            # while in a critical section.
            # In a critical section use:
            #     dispatch_next_thread__xu__noreturn ();


        switch_to_thread__xu:  (Microthread, Fate(X), X) -> Void;
            #
            # Switch to the given thread
            # while leaving a critical section.

        yield_to_next_thread__xu:  Fate(Void) -> X;
            #
            # Yield control to the next thread
            # while leaving the critical section.


        run_next_runnable_thread__xu__hook:             Ref( Fate( Void ) );
            #
            # This hook points to a fate that
            # gets dispatched when a preemption
            # is received or when a thread exits
            # a critical section and there is a
            # signal pending.


        no_runnable_threads_left__hook:  Ref(  Fate(  Void ) );
            #
            # This hook points to a fate that gets invoked when
            # when the scheduler has nothing else to do.


        thread_scheduler_shutdown_hook:    Ref( Fate ((Bool, wnx::process::Status)) );
            #
            # This hook points to a fate that
            # gets invoked when the system is
            # otherwise deadlocked.  It is
            # also invoked by  run_threadkit::shutdown.
            #
            # It takes two arguments:
            #  o A boolean flag that says whether to do clean-up.
            #  o The exit status.
            #
            # This hook gets set in   wrap_for_export()                 in   src/lib/src/lib/thread-kit/src/glue/threadkit-base-for-os-g.pkg
            # and                     start_up_thread_scheduler''()     in   src/lib/src/lib/thread-kit/src/glue/thread-scheduler-control-g.pkg
 


        get_approximate_time:  Void -> tim::Time;
            #
            # Get an approximation of the current time of day.
            #
            # The value returned was obtained from the operating
            # system via
            #     tim::get_time ();
            # during the current timeslice, so it is off
            # by at most the length of that timeslice.


        reset_thread_scheduler:  Bool -> Void;

        # Control over the preemptive timer 
        #
        start_thread_scheduler_timer:    tim::Time -> Void;                     # Called from   src/lib/src/lib/thread-kit/src/glue/thread-scheduler-control-g.pkg
                                                                                # Called from   src/lib/src/lib/thread-kit/src/glue/threadkit-base-for-os-g.pkg

        stop_thread_scheduler_timer:     Void -> Void;                          # Called from   src/lib/std/src/posix/winix-process.pkg
                                                                                # Called from   src/lib/src/lib/thread-kit/src/glue/thread-scheduler-control-g.pkg
                                                                                # Called from   src/lib/src/lib/thread-kit/src/glue/threadkit-base-for-os-g.pkg
                                                                                # Called from   src/lib/std/src/posix/spawn.pkg

        restart_thread_scheduler_timer:  Void -> Void;                          # Called from   src/lib/std/src/posix/winix-process.pkg
                                                                                # Called from   src/lib/src/lib/thread-kit/src/glue/thread-scheduler-control-g.pkg
                                                                                # Called from   src/lib/src/lib/thread-kit/src/glue/threadkit-base-for-os-g.pkg
                                                                                # Called from   src/lib/std/src/posix/spawn.pkg

        block_until_inter_hostthread_request_queue_is_nonempty: Void -> Void;   # This gives  no_runnable_threads_left__fate    in   src/lib/src/lib/thread-kit/src/glue/threadkit-base-for-os-g.pkg.
                                                                                # a graceful way to block until we have something to do.

        Do_Echo = { what:  String,                                              # 'what' will be passed to 'reply'.
                    reply: String -> Void
                  };
        echo:           Do_Echo -> Void;                                        # To be called from other hostthreads.
        do:             (Void -> Void) -> Void;                                 # Execute arbitrary code in the context of the scheduler thread.

        run_thunk:      (Void -> Void) -> Void;                                 # Create a temporary thread (with dummy ID)
                                                                                # to run the given function and then exit.
                                                                                #
                                                                                # NB: The thread is placed at the BACK of the BACKGROUND run queue
                                                                                #     to ensure that every other thread gets a fair chance to run.

        run_thunks:      List( (Void -> Void) ) -> Void;                        # As above, submitting multiple thunks as independent threads.
                                                                                # Currently implemented as just   apply run_thunk thunks;

        run_thunk_soon:  (Void -> Void) -> Void;                                # Create a temporary thread (with dummy ID)
                                                                                # to run the given function and then exit.
                                                                                #
                                                                                # NB: The thread is placed at the BACK of the FOREGROUND run queue
                                                                                #     for execution when its turn comes up.


        run_thunk_immediately__iu:  (Void -> Void) -> Void;                     # Schedule thunk to run "immediately", using the dedicated run_thunk_immediately_thread from   src/lib/src/lib/thread-kit/src/core-thread-kit/internal-threadkit-types.pkg
                                                                                # CALL ONLY FROM WITHIN AN UNINTERRUPTIBLE SCOPE! (That's what the __iu means.)
                                                                                #
                                                                                # NB: The thread is placed at the FRONT of the FOREGROUND run queue
                                                                                #     for immediate execution, instead of being placed at
                                                                                #     the back to wait its turn.  This represents UNFAIR SCHEDULING;
                                                                                #     heavy use of it could lead to THREAD STARVATION; USE WITH CAUTION!        
                                                                                #
                                                                                # This is an obscure fn currently used only by src/lib/src/lib/thread-kit/src/process-deathwatch.pkg

        inter_hostthread_request_queue_is_empty: Void -> Bool;                  # Special kludge used by 

        trace_backpatchfn: Ref( (Void -> String) -> Void );                     # A tracelog kludge of no general interest, used (only) in src/lib/src/lib/thread-kit/src/lib/logger.pkg

        get_uninterruptible_scope_nesting_depth: Void -> Int;                   # A unit-test support hack of no general interest.

uninterruptible_scope_mutex: Ref(Int);

        alarm_handler_calls:                                         Ref(Int);
        alarm_handler_calls_with__uninterruptible_scope_mutex__set:  Ref(Int);
        alarm_handler_calls_with__microthread_switch_lock__set:      Ref(Int);


        wake_scheduler_hostthread_if_paused:    Void -> Void;                   # io_bound_task_hostthreads uses this to wake us from an interprocess_signals::pause() call when
                                                                                # it has made input available for us to process.  Without this call, the       pause() will continue
                                                                                # until the next 50HZ (20ms) SIGALRM signal is caught by microthread_preemptive_scheduler::alarm_handler.
                                                                                # interprocess_signals          is from   src/lib/std/src/nj/interprocess-signals.pkg
                                                                                # io_bound_task_hostthreads     is from   src/lib/std/src/hostthread/io-bound-task-hostthreads.pkg

# Very temporary debug hacks:
kill_count: Ref(Int);
thread_scheduler_statestring: Void -> String;
print_thread_scheduler_state: Void -> Void;
print_int: Int -> Int -> Void;
mutex: hth::Mutex;
condvar: hth::Mutex;
Request =  DO_ECHO  Do_Echo |  DO_THUNK (Void -> Void); 
request_queue:  Ref(List(Request));                                             # Queue of pending requests from client hostthreads.
    };
end;


Comments and suggestions to: bugs@mythryl.org

PreviousUpNext