/* * remote_rwlock.c - kernel remote rwlock implementation. * * Authors Alain Greiner (2016,2017) * * Copyright (c) UPMC Sorbonne Universites * * This file is part of ALMOS-MKH. * * ALMOS-MKH is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by * the Free Software Foundation; version 2.0 of the License. * * ALMOS-MKH is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with ALMOS-MKH; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include #include #include #include #include #include #include /////////////////////////////////////////// void remote_rwlock_init( xptr_t lock_xp ) { remote_rwlock_t * lock_ptr = (remote_rwlock_t *)GET_PTR( lock_xp ); cxy_t lock_cxy = GET_CXY( lock_xp ); hal_remote_sw ( XPTR( lock_cxy , &lock_ptr->ticket ) , 0 ); hal_remote_sw ( XPTR( lock_cxy , &lock_ptr->current ) , 0 ); hal_remote_sw ( XPTR( lock_cxy , &lock_ptr->count ) , 0 ); hal_remote_swd( XPTR( lock_cxy , &lock_ptr->owner ) , XPTR_NULL ); } ////////////////////////////////////////////// void remote_rwlock_rd_lock( xptr_t lock_xp ) { reg_t mode; uint32_t ticket; // get cluster and local pointer on remote_rwlock remote_rwlock_t * lock_ptr = (remote_rwlock_t *)GET_PTR( lock_xp ); cxy_t lock_cxy = GET_CXY( lock_xp ); // get cluster and local pointer on local thread cxy_t thread_cxy = local_cxy; thread_t * thread_ptr = CURRENT_THREAD; // extended pointers on ticket, current, count, and thread->remote_locks xptr_t ticket_xp = XPTR( lock_cxy , &lock_ptr->ticket ); xptr_t current_xp = XPTR( lock_cxy , &lock_ptr->current ); xptr_t count_xp = XPTR( lock_cxy , &lock_ptr->count ); xptr_t locks_xp = XPTR( thread_cxy , &thread_ptr->remote_locks ); // disable interrupts hal_disable_irq( &mode ); // get next free ticket ticket = hal_remote_atomic_add( ticket_xp , 1 ); // busy waiting loop to take the lock while( ticket != hal_remote_lw( current_xp ) ) { hal_fixed_delay( CONFIG_RWLOCK_DELAY ); } ////////// From here we have the lock //////////// // increment count and thead.remote_locks hal_remote_atomic_add( count_xp , 1 ); hal_remote_atomic_add( locks_xp , 1 ); // sync hal_fence(); // release lock to allow several simultaneous readers hal_remote_atomic_add( current_xp , 1 ); // enable interrupts hal_restore_irq( mode ); } // end remote_rwlock_rd_lock() //////////////////////////////////////////////// void remote_rwlock_rd_unlock( xptr_t lock_xp ) { reg_t mode; // get cluster and local pointer on remote_rwlock remote_rwlock_t * lock_ptr = (remote_rwlock_t *)GET_PTR( lock_xp ); cxy_t lock_cxy = GET_CXY( lock_xp ); // get cluster and local pointer on local thread cxy_t thread_cxy = local_cxy; thread_t * thread_ptr = CURRENT_THREAD; // extended pointers on lock->count and thread->remote_locks xptr_t count_xp = XPTR( lock_cxy , &lock_ptr->count ); xptr_t locks_xp = XPTR( thread_cxy , &thread_ptr->remote_locks ); // disable interrupts hal_disable_irq( &mode ); // decrement count and thread.remote_locks hal_remote_atomic_add( count_xp , -1 ); hal_remote_atomic_add( locks_xp , -1 ); // enable interrupts hal_restore_irq( mode ); } // end remote_rwlock_rd_unlock() ////////////////////////////////////////////// void remote_rwlock_wr_lock( xptr_t lock_xp ) { reg_t mode; uint32_t ticket; // get cluster and local pointer on remote_rwlock remote_rwlock_t * lock_ptr = (remote_rwlock_t *)GET_PTR( lock_xp ); cxy_t lock_cxy = GET_CXY( lock_xp ); // get cluster and local pointer on local thread cxy_t thread_cxy = local_cxy; thread_t * thread_ptr = CURRENT_THREAD; // compute extended pointers on lock->ticket, lock->owner, and thread->remote_locks xptr_t ticket_xp = XPTR( lock_cxy , &lock_ptr->ticket ); xptr_t count_xp = XPTR( lock_cxy , &lock_ptr->count ); xptr_t current_xp = XPTR( lock_cxy , &lock_ptr->current ); xptr_t owner_xp = XPTR( lock_cxy , &lock_ptr->owner ); xptr_t locks_xp = XPTR( thread_cxy , &thread_ptr->remote_locks ); xptr_t thread_xp = XPTR( thread_cxy , thread_ptr ); // disable interrupts hal_disable_irq( &mode ); // get next free ticket ticket = hal_remote_atomic_add( ticket_xp , 1 ); // loop to take the lock while( ticket != hal_remote_lw( current_xp ) ) { hal_fixed_delay( CONFIG_RWLOCK_DELAY ); } ////////// From here we have the lock //////////// // wait completion of read accesses while( hal_remote_lw( count_xp ) != 0 ) { hal_fixed_delay( CONFIG_RWLOCK_DELAY ); } // register owner thread and increment thread.remote_locks hal_remote_swd( owner_xp , thread_xp ); hal_remote_atomic_add( locks_xp , 1 ); // enable interrupts hal_restore_irq( mode ); } // end remote_rwlock_wr_lock() ////////////////////////////////////////////// void remote_rwlock_wr_unlock( xptr_t lock_xp ) { reg_t mode; // get cluster and local pointer on remote_rwlock remote_rwlock_t * lock_ptr = (remote_rwlock_t *)GET_PTR( lock_xp ); cxy_t lock_cxy = GET_CXY( lock_xp ); // get cluster and local pointer on local thread cxy_t thread_cxy = local_cxy; thread_t * thread_ptr = CURRENT_THREAD; // compute extended pointers on lock->ticket, lock->owner and thread->remote_locks xptr_t current_xp = XPTR( lock_cxy , &lock_ptr->current ); xptr_t owner_xp = XPTR( lock_cxy , &lock_ptr->owner ); xptr_t locks_xp = XPTR( thread_cxy , &thread_ptr->remote_locks ); // disable interrupts hal_disable_irq( &mode ); // unregister owner thread, and release lock hal_remote_swd( owner_xp , XPTR_NULL ); hal_remote_atomic_add( current_xp , 1 ); hal_remote_atomic_add( locks_xp , -1 ); // enable interrupts hal_restore_irq( mode ); } // end remote_rwlock_wr_unlock() /////////////////////////////////////////// void remote_rwlock_print( xptr_t lock_xp, char * comment ) { uint32_t ticket; // first free ticket index uint32_t current; // ticket index of current owner uint32_t count; // current number of reader threads xptr_t owner; // extended pointer on writer thread // get cluster and local pointer on remote_rwlock remote_rwlock_t * lock_ptr = (remote_rwlock_t *)GET_PTR( lock_xp ); cxy_t lock_cxy = GET_CXY( lock_xp ); ticket = hal_remote_lw ( XPTR( lock_cxy , &lock_ptr->ticket ) ); current = hal_remote_lw ( XPTR( lock_cxy , &lock_ptr->current ) ); count = hal_remote_lw ( XPTR( lock_cxy , &lock_ptr->count ) ); owner = hal_remote_lwd( XPTR( lock_cxy , &lock_ptr->owner ) ); printk("\n*** rwlock <%l> %s : ticket = %d / current = %d / count = %d / owner = %l\n", lock_xp , comment , ticket , current , count , owner ); } // end remote_rwlock_print()