Changeset 581 for trunk/kernel/libk


Ignore:
Timestamp:
Oct 10, 2018, 3:11:53 PM (6 years ago)
Author:
alain
Message:

1) Improve the busylock debug infrastructure.
2) introduce a non-distributed, but portable implementation for the pthread_barrier.

Location:
trunk/kernel/libk
Files:
7 edited

Legend:

Unmodified
Added
Removed
  • trunk/kernel/libk/remote_barrier.c

    r563 r581  
    8383
    8484    // get pointer on local process descriptor
    85     process_t * process = CURRENT_THREAD->process;
     85    thread_t  * this    = CURRENT_THREAD;
     86    process_t * process = this->process;
     87
     88#if DEBUG_BARRIER
     89uint32_t cycle = (uint32_t)hal_get_cycles();
     90if( cycle > DEBUG_BARRIER )
     91printk("\n[DBG] %s : thread %x in process %x enter / count %d / cycle %d\n",
     92__FUNCTION__, this->trdid, process->pid, count, cycle );
     93#endif
    8694
    8795    // get extended pointer on reference process
     
    110118
    111119    // initialise barrier
    112     hal_remote_s32 ( XPTR( ref_cxy , &barrier_ptr->nb_threads ) , count );
    113     hal_remote_s32 ( XPTR( ref_cxy , &barrier_ptr->current    ) , 0 );
    114     hal_remote_s32 ( XPTR( ref_cxy , &barrier_ptr->sense      ) , 0 );
     120    hal_remote_s32( XPTR( ref_cxy , &barrier_ptr->nb_threads ) , count );
     121    hal_remote_s32( XPTR( ref_cxy , &barrier_ptr->current    ) , 0 );
     122    hal_remote_s32( XPTR( ref_cxy , &barrier_ptr->sense      ) , 0 );
    115123    hal_remote_spt( XPTR( ref_cxy , &barrier_ptr->ident      ) , (void*)ident );
    116124
    117     xlist_entry_init( XPTR( ref_cxy , &barrier_ptr->list ) );
     125    xlist_root_init( XPTR( ref_cxy , &barrier_ptr->root ) );
    118126
    119127    // register  barrier in reference process xlist
     
    125133    remote_busylock_release( XPTR( ref_cxy , &ref_ptr->sync_lock ) );
    126134
     135#if DEBUG_BARRIER
     136cycle = (uint32_t)hal_get_cycles();
     137if( cycle > DEBUG_BARRIER )
     138printk("\n[DBG] %s : thread %x in process %x exit / barrier %x in cluster %x / cycle %d\n",
     139__FUNCTION__, this->trdid, process->pid, barrier_ptr, ref_cxy, cycle );
     140#endif
     141
    127142    return 0;
    128 }
     143
     144}  // end remote_barrier_create()
    129145
    130146////////////////////////////////////////////////
     
    162178        rpc_kcm_free_client( barrier_cxy , barrier_ptr , KMEM_BARRIER );
    163179    }
    164 }
     180}  // end remote_barrier_destroy()
    165181
    166182/////////////////////////////////////////////
     
    168184{
    169185    uint32_t  expected;
     186    uint32_t  sense;
    170187    uint32_t  current;
    171     uint32_t  count;
    172     uint32_t  sense;
    173     reg_t     irq_state;
     188    uint32_t  nb_threads;
    174189    xptr_t    root_xp;
    175 
    176     // get cluster and local pointer on calling thread
    177     cxy_t              thread_cxy = local_cxy;
    178     thread_t         * thread_ptr = CURRENT_THREAD;
    179 
    180 // check calling thread can yield
    181 assert( (thread_ptr->busylocks == 0),
    182 "cannot yield : busylocks = %d\n", thread_ptr->busylocks );
     190    xptr_t    lock_xp;
     191    xptr_t    current_xp;
     192    xptr_t    sense_xp;
     193    xptr_t    nb_threads_xp;
     194
     195    // get pointer on calling thread
     196    thread_t * this = CURRENT_THREAD;
     197
     198    // check calling thread can yield
     199    thread_assert_can_yield( this , __FUNCTION__ );
    183200
    184201    // get cluster and local pointer on remote barrier
    185     remote_barrier_t * barrier_ptr = (remote_barrier_t *)GET_PTR( barrier_xp );
     202    remote_barrier_t * barrier_ptr = GET_PTR( barrier_xp );
    186203    cxy_t              barrier_cxy = GET_CXY( barrier_xp );
    187204
    188     // get count and root fields from barrier descriptor
    189     count   = hal_remote_l32 ( XPTR( barrier_cxy , &barrier_ptr->nb_threads ) );
    190     root_xp = hal_remote_l64( XPTR( barrier_cxy , &barrier_ptr->root ) );
    191 
    192     // get barrier sense value
    193     sense = hal_remote_l32( XPTR( barrier_cxy , &barrier_ptr->sense ) );
     205#if DEBUG_BARRIER
     206uint32_t cycle = (uint32_t)hal_get_cycles();
     207if( cycle > DEBUG_BARRIER )
     208printk("\n[DBG] %s : thread %x in process %x enter / barrier %x in cluster %x / cycle %d\n",
     209__FUNCTION__, this->trdid, this->process->pid, barrier_ptr, barrier_cxy, cycle );
     210#endif
     211
     212    // compute extended pointers on various barrier fields
     213    lock_xp       = XPTR( barrier_cxy , &barrier_ptr->lock );
     214    root_xp       = XPTR( barrier_cxy , &barrier_ptr->root );
     215    current_xp    = XPTR( barrier_cxy , &barrier_ptr->current );
     216    sense_xp      = XPTR( barrier_cxy , &barrier_ptr->sense );
     217    nb_threads_xp = XPTR( barrier_cxy , &barrier_ptr->nb_threads );
     218
     219    // take busylock protecting the remote_barrier
     220    remote_busylock_acquire( lock_xp );
     221
     222#if (DEBUG_BARRIER & 1)
     223cycle = (uint32_t)hal_get_cycles();
     224if( cycle > DEBUG_BARRIER )
     225printk("\n[DBG] %s : thread %x in process %x get lock / cycle %d\n",
     226__FUNCTION__, this->trdid, this->process->pid, cycle );
     227#endif
     228
     229    // get sense and nb_threads values from barrier descriptor
     230    sense      = hal_remote_l32( sense_xp );
     231    nb_threads = hal_remote_l32( nb_threads_xp );
    194232
    195233    // compute expected value
     
    197235    else              expected = 0;
    198236
    199     // atomically increment current
    200     current = hal_remote_atomic_add( XPTR( barrier_cxy , &barrier_ptr->current ) , 1 );
     237#if (DEBUG_BARRIER & 1)
     238cycle = (uint32_t)hal_get_cycles();
     239if( cycle > DEBUG_BARRIER )
     240printk("\n[DBG] %s : thread %x in process %x / count %d / sense %d / cycle %d\n",
     241__FUNCTION__, this->trdid, this->process->pid, nb_threads, sense, cycle );
     242#endif
     243
     244    // atomically increment current, and get value before increment
     245    current = hal_remote_atomic_add( current_xp , 1 );
    201246
    202247    // last thread reset current, toggle sense, and activate all waiting threads
    203248    // other threads block, register in queue, and deschedule
    204249
    205     if( current == (count-1) )                       // last thread
    206     {
    207         hal_remote_s32( XPTR( barrier_cxy , &barrier_ptr->current) , 0 );
    208         hal_remote_s32( XPTR( barrier_cxy , &barrier_ptr->sense  ) , expected );
    209 
    210         // activate waiting threads if required
    211         if( xlist_is_empty( root_xp ) == false )
     250    if( current == (nb_threads-1) )                       // last thread
     251    {
     252        hal_remote_s32( current_xp , 0 );
     253        hal_remote_s32( sense_xp , expected );
     254
     255        // unblock all waiting threads
     256        while( xlist_is_empty( root_xp ) == false )
    212257        {
    213             // disable interrupts
    214             hal_disable_irq( &irq_state );
    215 
    216             xptr_t  iter_xp;
    217             xptr_t  thread_xp;
    218             XLIST_FOREACH( root_xp , iter_xp )
    219             {
    220                 // get extended pointer on waiting thread
    221                 thread_xp = XLIST_ELEMENT( iter_xp , thread_t , wait_list );
    222 
    223                 // remove waiting thread from queue
    224                 remote_busylock_acquire( XPTR( barrier_cxy , &barrier_ptr->lock ) );
    225                 xlist_unlink( XPTR( barrier_cxy , &barrier_ptr->list ) );
    226                 remote_busylock_release( XPTR( barrier_cxy , &barrier_ptr->lock ) );
    227 
    228                 // unblock waiting thread
    229                 thread_unblock( thread_xp , THREAD_BLOCKED_USERSYNC );
    230             }
    231 
    232             // restore interrupts
    233             hal_restore_irq( irq_state );
     258            // get pointers on first waiting thread
     259            xptr_t     thread_xp  = XLIST_FIRST( root_xp , thread_t , wait_list );
     260            cxy_t      thread_cxy = GET_CXY( thread_xp );
     261            thread_t * thread_ptr = GET_PTR( thread_xp );
     262
     263#if (DEBUG_BARRIER & 1)
     264cycle = (uint32_t)hal_get_cycles();
     265if( cycle > DEBUG_BARRIER )
     266printk("\n[DBG] %s : thread %x in process %x / unblock thread %x / cycle %d\n",
     267__FUNCTION__, this->trdid, this->process->pid, thread_ptr, cycle );
     268#endif
     269
     270            // remove waiting thread from queue
     271            xlist_unlink( XPTR( thread_cxy , &thread_ptr->wait_list ) );
     272
     273            // unblock waiting thread
     274            thread_unblock( thread_xp , THREAD_BLOCKED_USERSYNC );
    234275        }
     276
     277        // release busylock protecting the remote_barrier
     278        remote_busylock_release( lock_xp );
    235279    }
    236280    else                                             // not the last thread
    237281    {
    238         // disable interrupts
    239         hal_disable_irq( &irq_state );
     282
     283#if (DEBUG_BARRIER & 1)
     284cycle = (uint32_t)hal_get_cycles();
     285if( cycle > DEBUG_BARRIER )
     286printk("\n[DBG] %s : thread %x in process %x / blocked / cycle %d\n",
     287__FUNCTION__, this->trdid, this->process->pid, cycle );
     288#endif
    240289
    241290        // register calling thread in barrier waiting queue
    242         xptr_t entry_xp = XPTR( thread_cxy , &thread_ptr->wait_list );
    243 
    244         remote_busylock_acquire( XPTR( barrier_cxy , &barrier_ptr->lock ) );
    245         xlist_add_last( root_xp , entry_xp );
    246         remote_busylock_release( XPTR( barrier_cxy , &barrier_ptr->lock ) );
    247 
    248         // block & deschedule the calling thread
    249         thread_block( XPTR( local_cxy , thread_ptr ) , THREAD_BLOCKED_USERSYNC );
     291        xlist_add_last( root_xp , XPTR( local_cxy , &this->wait_list ) );
     292
     293        // block calling thread
     294        thread_block( XPTR( local_cxy , this ) , THREAD_BLOCKED_USERSYNC );
     295
     296        // release busylock protecting the remote_barrier
     297        remote_busylock_release( lock_xp );
     298
     299        // deschedule
    250300        sched_yield("blocked on barrier");
    251 
    252         // restore interrupts
    253         hal_restore_irq( irq_state );
    254     }
    255 }
     301    }
     302
     303#if DEBUG_BARRIER
     304cycle = (uint32_t)hal_get_cycles();
     305if( cycle > DEBUG_BARRIER )
     306printk("\n[DBG] %s : thread %x in process %x exit / barrier %x in cluster %x / cycle %d\n",
     307__FUNCTION__, this->trdid, this->process->pid, barrier_ptr, barrier_cxy, cycle );
     308#endif
     309
     310}  // end remote_barrier_wait()
  • trunk/kernel/libk/remote_barrier.h

    r563 r581  
    3333 *          This file defines a POSIX compliant barrier.
    3434 *
    35  * It is used by multi-threaded iuser applications to synchronise threads running in
     35 * It is used by multi-threaded user applications to synchronise threads running in
    3636 * different clusters, as all access functions uses hal_remote_l32() / hal_remote_s32()
    3737 * remote access primitives.
     
    6161typedef struct remote_barrier_s
    6262{
    63     remote_busylock_t  lock;          /*! lock protecting xlist of arrived threads      */
     63    remote_busylock_t  lock;          /*! lock protecting list of waiting threads       */
    6464    intptr_t           ident;         /*! virtual address in user space == identifier   */
    6565    uint32_t           current;       /*! number of arrived threads                     */
     
    6767    uint32_t           nb_threads;    /*! number of expected threads                    */
    6868    xlist_entry_t      list;          /*! member of list of barriers in same process    */
    69     xlist_entry_t      root;          /*! root of list of arrived threads               */
     69    xlist_entry_t      root;          /*! root of list of waiting threads               */
    7070}
    7171remote_barrier_t;
  • trunk/kernel/libk/remote_condvar.c

    r563 r581  
    186186    thread_t * this = CURRENT_THREAD;
    187187
    188 // check calling thread can yield
    189 assert( (this->busylocks == 0),
    190 "cannot yield : busylocks = %d\n", this->busylocks );
     188    // check calling thread can yield
     189    thread_assert_can_yield( this , __FUNCTION__ );
    191190
    192191    // get condvar cluster and local pointer
  • trunk/kernel/libk/remote_condvar.h

    r563 r581  
    3131
    3232/*******************************************************************************************
    33  *     This file define an user level POSIX compliant condition variable.
     33 * This file defines the ALMOS-MKH implentation of an user level, POSIX compliant condvar.
    3434 *
    3535 * It can be used by muti-threaded user applications to synchronise user threads
     
    4444 * is not running in the reference cluster.
    4545 *
    46  * The blocking "remote_condvar_wait() function allowx the calling thread to efficiently
     46 * The blocking "remote_condvar_wait() function allows the calling thread to efficiently
    4747 * wait for a change in a shared user object. The calling thread blocks and register in
    4848 * a waiting queue attached to the condvar. The blocked thread is unblocked by another
  • trunk/kernel/libk/remote_mutex.c

    r563 r581  
    191191void remote_mutex_lock( xptr_t mutex_xp )
    192192{
     193    // get cluster and pointers on calling thread
     194    cxy_t            caller_cxy = local_cxy;
     195    thread_t       * caller_ptr = CURRENT_THREAD;
     196    xptr_t           caller_xp  = XPTR( caller_cxy , caller_ptr );
     197
     198    // check calling thread can yield
     199    thread_assert_can_yield( caller_ptr , __FUNCTION__ );
     200
    193201    // get cluster and local pointer on mutex
    194202    remote_mutex_t * mutex_ptr = GET_PTR( mutex_xp );
     
    200208    xptr_t           root_xp  = XPTR( mutex_cxy , &mutex_ptr->root );
    201209    xptr_t           lock_xp  = XPTR( mutex_cxy , &mutex_ptr->lock );
    202 
    203     // get cluster and pointers on calling thread
    204     cxy_t            caller_cxy = local_cxy;
    205     thread_t       * caller_ptr = CURRENT_THREAD;
    206     xptr_t           caller_xp  = XPTR( caller_cxy , caller_ptr );
    207 
    208 // check calling thread can yield
    209 assert( (caller_ptr->busylocks == 0),
    210 "cannot yield : busylocks = %d\n", caller_ptr->busylocks );
    211210
    212211    while( 1 )
  • trunk/kernel/libk/remote_mutex.h

    r563 r581  
    2929#include <xlist.h>
    3030
    31 /***************************************************************************************
    32  *    This file defines an user level POSIX compliant mutex.
     31/*****************************************************************************************
     32 * This file defines the ALMOS-MKH implementation of an user level POSIX compliant mutex.
    3333 *
    3434 * It can be used by muti-threaded user applications to synchronise user threads
     
    4949 * The "remote_mutex_unlock()" function unblocks the first waiting thread in the queue
    5050 * without releasing the mutex if queue is not empty.
    51  **************************************************************************************/
     51 ****************************************************************************************/
    5252
    5353/*****************************************************************************************
     
    5757typedef struct remote_mutex_s
    5858{
    59     remote_busylock_t  lock;            /*! lock protecting the mutex state           */
    60     intptr_t           ident;           /*! mutex identifier (vaddr in user space)    */
    61     uint32_t           taken;           /*! mutex non allocated if 0                  */
    62     xlist_entry_t      list;            /*! member of list of mutex in same process   */
    63     xlist_entry_t      root;            /*! root of list of waiting threads           */
    64     xptr_t             owner;           /*! extended pointer on owner thread          */
     59    remote_busylock_t  lock;            /*! lock protecting the mutex state             */
     60    intptr_t           ident;           /*! mutex identifier (vaddr in user space)      */
     61    uint32_t           taken;           /*! mutex non allocated if 0                    */
     62    xlist_entry_t      list;            /*! member of list of mutex in same process     */
     63    xlist_entry_t      root;            /*! root of list of waiting threads             */
     64    xptr_t             owner;           /*! extended pointer on owner thread            */
    6565}
    6666remote_mutex_t;
    6767
    68 /***************************************************************************************
     68/*****************************************************************************************
    6969 * This function returns an extended pointer on the remote mutex, identified
    7070 * by its virtual address in a given user process. It makes an associative search,
    7171 * scanning the list of mutex rooted in the reference process descriptor.
    72  ***************************************************************************************
     72 *****************************************************************************************
    7373 * @ ident    : mutex virtual address, used as identifier.
    7474 * @ returns extended pointer on mutex if success / returns XPTR_NULL if not found.
    75  **************************************************************************************/
     75 ****************************************************************************************/
    7676xptr_t remote_mutex_from_ident( intptr_t  ident );
    7777
    78 /***************************************************************************************
     78/*****************************************************************************************
    7979 * This function implements the pthread_mutex_init() syscall.
    8080 * It allocates memory for the mutex descriptor in the reference cluster for
    8181 * the calling process, it initializes the mutex state, and register it in the
    8282 * list of mutex owned by the reference process.
    83  ***************************************************************************************
     83 *****************************************************************************************
    8484 * @ ident       : mutex identifier (virtual address in user space).
    8585 * @ return 0 if success / ENOMEM if no memory / EINVAL if invalid argument.
    86  **************************************************************************************/
     86 ****************************************************************************************/
    8787error_t remote_mutex_create( intptr_t ident );
    8888
    89 /***************************************************************************************
     89/*****************************************************************************************
    9090 * This function implements the pthread_mutex_destroy() syscall.
    9191 * It releases thr memory allocated for the mutex descriptor, and remove the mutex
    9292 * from the list of mutex owned by the reference process.
    93  ***************************************************************************************
     93 *****************************************************************************************
    9494 * @ mutex_xp  : extended pointer on mutex descriptor.
    95  **************************************************************************************/
     95 ****************************************************************************************/
    9696void remote_mutex_destroy( xptr_t  mutex_xp );
    9797
    98 /***************************************************************************************
     98/*****************************************************************************************
    9999 * This blocking function implements the pthread_mutex_lock() syscall.
    100100 * It returns only when the ownership of the mutex identified by the <mutex_xp>
    101101 * argument has been obtained by the calling thread. It register in the mutex waiting
    102102 * queue when the mutex is already taken by another thread.
    103  ***************************************************************************************
     103 *****************************************************************************************
    104104 * @ mutex_xp  : extended pointer on mutex descriptor.
    105  **************************************************************************************/
     105 ****************************************************************************************/
    106106void remote_mutex_lock( xptr_t  mutex_xp );
    107107
    108 /***************************************************************************************
     108/*****************************************************************************************
    109109 * This function implements the pthread_mutex_unlock() syscall.
    110110 * It cheks that the calling thread is actually the mutex owner.
     
    112112 * It unblocks the first thread registered in the mutex waiting queue, when the
    113113 * queue is not empty.
    114  ***************************************************************************************
     114 *****************************************************************************************
    115115 * @ mutex_xp  : extended pointer on mutex descriptor.
    116116 * @ return 0 if success / return non zero if calling thread is not mutex owner.
    117  **************************************************************************************/
     117 ****************************************************************************************/
    118118error_t remote_mutex_unlock( xptr_t  mutex_xp );
    119119
    120 /***************************************************************************************
     120/*****************************************************************************************
    121121 * This non blocking function function attempts to lock a mutex without blocking.
    122  ***************************************************************************************
     122 *****************************************************************************************
    123123 * @ mutex_xp  : extended pointer on mutex descriptor.
    124124 * @ return 0 if success / return non zero if already taken.
    125  **************************************************************************************/
     125 ****************************************************************************************/
    126126error_t remote_mutex_trylock( xptr_t  mutex_xp );
    127127
  • trunk/kernel/libk/remote_sem.h

    r563 r581  
    109109
    110110/****************************yy***************************************************************
    111  * This function mplements the SEM_POST operation.
     111 * This function implements the SEM_POST operation.
    112112 * - It atomically increments the remote semaphore.
    113113 * - If the waiting queue is not empty, it wakes up all waiting thread.
Note: See TracChangeset for help on using the changeset viewer.