PreviousUpNext

15.4.1154  src/lib/std/src/pthread.pkg

# pthread.pkg
#
# For background, see "Overview" comments in    src/lib/std/src/pthread.api
#
# Mythryl-level interface to support for parallel computation
# via kernel threads (on Linux, Posix threads).
#
# We are the Mythryl side of the
#
#     src/c/lib/pthread/libmythryl-pthread.c
#
# interface to functionality defined in the pthread section of
#
#     src/c/h/runtime-base.h   
#
# and implemented in
#
#     src/c/pthread/pthread-on-posix-threads.c                          # pthread build on top of modern posix threads interface.

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

stipulate
    package ci  =  mythryl_callable_c_library_interface;                                                # mythryl_callable_c_library_interface  is from   src/lib/std/src/unsafe/mythryl-callable-c-library-interface.pkg
    package fat =  fate;                                                                                # fate                                  is from   src/lib/std/src/nj/fate.pkg
    package psx =  posix_1003_1b;                                                                       # posix_1003_1b                         is from   src/lib/std/src/posix-1003.1b/posix-1003-1b.pkg
    package w1u =  one_word_unt_guts;                                                                   # one_word_unt_guts                     is from   src/lib/std/src/one-word-unt-guts.pkg
    #
    fun cfun fun_name
        =
        ci::find_c_function { lib_name => "pthread", fun_name };
herein

    package   pthread
    : (weak)  Pthread                                                                                   # Pthread                               is from   src/lib/std/src/pthread.api
    {
        # We allocate our pthread, mutex, condvar and barrier values
        # on the C heap because having the Mythryl garbage
        # collector moving them around seems like a really
        # really bad idea -- see        src/c/lib/pthread/libmythryl-pthread.c
        #
        # At the Mythryl level we represent them as C
        # addresses encoded as unsigned integer values:
        #
        Barrier =  tagged_int::Int;
        Condvar =  tagged_int::Int;
        Mutex   =  tagged_int::Int;

        Pthread =   tagged_int::Int;
            #
            # In practice Pthread is currently implemented as an index into
            # our  pthread_table__global[] table which is
            # declared          in   src/c/h/runtime-base.h
            # defined           in   src/c/main/runtime-state.c
            # and used mostly by
            # pth__pthread_create and
            # pth__pthread_exit in   src/c/pthread/pthread-on-posix-threads.c

        Try_Mutex_Result =  ACQUIRED_MUTEX | MUTEX_WAS_UNAVAILABLE;

        exception MAKE_PTRHEAD;

        # Return number of cores on host CPU,
        # for use in deciding how many posix
        # threads to run in parallel when
        # doing cpu-bound computations:
        #
        fun get_cpu_core_count ()                                                                       # We support this fn in this api partly to put it where it is expected
            =                                                                                           # and partly because we may need this call on platforms (Windows?) where
            w1u::to_int  (psx::sysconf  "NPROCESSORS_ONLN");                                            # sysconf "NPROCESSORS_ONLN" is not supported -- if so, at that point
                                                                                                        # we can switch to per-platform drivers without breaking client code.
        # Here we're looking up fns in
        # the table constructed in
        #
        #     src/c/lib/pthread/libmythryl-pthread.c
        #
        join_pthread    =       cfun   "join_pthread":          Pthread -> Void;

        spawn_pthread'  =       cfun   "spawn_pthread":         fat::Fate(Void) -> Pthread;             # Private to this file.
        #
        fun spawn_pthread  void_to_void
            =
            spawn_pthread'  (fat::make_isolated_fate  void_to_void);                                    # Hide the "fate::" stuff because for almost all users it will just be distracting clutter.

        stipulate                                                                                       # We need this little two-step because we'll get complaints
            foo =  cfun   "pthread_exit";                                                               # from the typechecker (due to the "value restriction")
        herein                                                                                          # if we just do    my pthread_exit:   Void -> X =   cfun "release_pthread" here.
            pthread_exit =      (unsafe::cast foo):     Void -> X ;
        end;

        get_pthread_id  =       cfun   "get_pthread_id":        Void -> Int;

        make_mutex      =       cfun "mutex_make":              Void -> Mutex;
        free_mutex      =       cfun "mutex_free":              Mutex -> Void;
        acquire_mutex   =       cfun "mutex_lock":              Mutex -> Void;
        release_mutex   =       cfun "mutex_unlock":            Mutex -> Void;
        try_mutex'      =       cfun "mutex_trylock":           Mutex -> Bool;                          # This is not exported to clients -- we export try_mutex (below) instead.

        make_barrier    =       cfun "barrier_make":            Void -> Barrier;
        free_barrier    =       cfun "barrier_free":            Barrier -> Void;
        set_barrier'    =       cfun "barrier_init":            (Barrier, Int) -> Void;                 # 'Int' is number of threads which must arrive at barrier before it will release them.
        wait_on_barrier =       cfun "barrier_wait":            Barrier -> Bool;                        # Exactly one pthread waiting on barrier gets a TRUE return value.

        make_condvar    =       cfun "condvar_make":            Void -> Condvar;
        free_condvar    =       cfun "condvar_free":            Condvar -> Void;
        wait_on_condvar =       cfun "condvar_wait":            (Condvar, Mutex) -> Void;
        signal_condvar  =       cfun "condvar_signal":          Condvar -> Void;
        broadcast_condvar =     cfun "condvar_broadcast":       Condvar -> Void;

        fun try_mutex mutex                                             # Returning a Bool is too confusing, so we use a custom datatype for clarity.
            =
            if (try_mutex' mutex)   MUTEX_WAS_UNAVAILABLE;              # I got these two backwards the first time around, confirming that the Bool value is confusing. :-)   -- 2011-12-05 CrT
            else                    ACQUIRED_MUTEX;
            fi;

        fun with_mutex_do  mutex  thunk
            =
            {   acquire_mutex  mutex;
                    #
                    result = thunk ();
                    #
                release_mutex  mutex;
                #
                result;
            }
            except x =  {   release_mutex  mutex;
                            #
                            raise exception x;
                        };

        fun set_barrier { barrier, threads }
            =
            set_barrier' (barrier, threads);                            # We do not actually need to repackage the record
                                                                        # as a tuple -- they have the same heap structure anyhow.
                                                                        # But for clarity we do so anyway, for the moment at least.
    };
end;

## Code by Jeff Prothero: Copyright (c) 2010-2012,
## released under Gnu Public Licence version 3.


Comments and suggestions to: bugs@mythryl.org

PreviousUpNext