/* * xhtab.c - Remote access embedded hash table implementation. * * Author 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 #include #include /////////////////////////////////////////////////////////////////////////////////////////// // Item type specific (static) functions (two functions for each item type). // - for type , identifier is the name field. /////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////// // These static functions compute the hash index from the key. /////////////////////////////////////////////////////////////////////////////////////////// // @ key : local pointer on key. // @ return the index value, from 0 to (HASHTAB_SIZE - 1) /////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////// uint32_t xhtab_dentry_index( void * key ) { char * name = key; uint32_t index = 0; while( *name ) { index = index + (*(name++) ^ index); } return index % HASHTAB_SIZE; } //////////////////////////////////////////////////////////////////////////////////////////// // These static function are used by xhtab_lookup(), xhtab_insert(), xhtab_remove(). // They scan one sub-list identified by to find an item identified by . // The sub-list is not modified, but the readlock must have been taken by the caller. //////////////////////////////////////////////////////////////////////////////////////////// // @ xhtab_xp : extended pointer on hash table. // @ index : index of sub-list to be scanned. // @ key : local pointer on item identifier. // return an extended pointer on item if found / return XPTR_NULL if not found. //////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////// static xptr_t xhtab_dentry_scan( xptr_t xhtab_xp, uint32_t index, void * key ) { xptr_t xlist_xp; // xlist_entry_t (iterator) xhtab_t * xhtab_ptr; // hash table local pointer cxy_t xhtab_cxy; // hash table cluster char local_name[CONFIG_VFS_MAX_NAME_LENGTH]; // local copy of dentry name // get hash table cluster and local pointer xhtab_cxy = GET_CXY( xhtab_xp ); xhtab_ptr = (xhtab_t *)GET_PTR( xhtab_xp ); // scan sub-list[index] XLIST_FOREACH( XPTR( xhtab_cxy , &xhtab_ptr->roots[index] ) , xlist_xp ) { // get extended pointer on dentry containing the xlist_entry_t xptr_t dentry_xp = XLIST_ELEMENT( xlist_xp , vfs_dentry_t , xlist ); // get dentry cluster and local pointer cxy_t dentry_cxy = GET_CXY( dentry_xp ); vfs_dentry_t * dentry_ptr = (vfs_dentry_t *)GET_PTR( dentry_xp ); // make a local copy of dentry name hal_remote_memcpy( XPTR( local_cxy , local_name ) , XPTR( dentry_cxy , dentry_ptr->name ), CONFIG_VFS_MAX_NAME_LENGTH ); // check matching if( strcmp( local_name , (char *)key ) == 0 ) return dentry_xp; } // No matching item found return XPTR_NULL; } //////////////////////////////////////////////////////////////////////////////////////// // Generic access functions //////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////// void xhtab_init( xhtab_t * xhtab, xhtab_item_type_t type ) { uint32_t i; // initialize readlock remote_rwlock_init( XPTR( local_cxy , &xhtab->lock) ); xhtab->items = 0; if( type == XHTAB_DENTRY_TYPE ) { xhtab->scan = &xhtab_dentry_scan; xhtab->index = &xhtab_dentry_index; } else { printk("\n[PANIC] in %s : illegal item type\n", __FUNCTION__ ); hal_core_sleep(); } for( i=0 ; i < HASHTAB_SIZE ; i++ ) { xlist_root_init( XPTR( local_cxy , &xhtab->roots[i] ) ); } } /////////////////////////////////////// error_t xhtab_insert( xptr_t xhtab_xp, void * key, xptr_t xlist_xp ) { // get xhtab cluster and local pointer cxy_t xhtab_cxy = GET_CXY( xhtab_xp ); xhtab_t * xhtab_ptr = (xhtab_t *)GET_PTR( xhtab_xp ); // compute index from key uint32_t index = xhtab_ptr->index( key ); // take the lock protecting hash table remote_rwlock_wr_lock( XPTR( xhtab_cxy , &xhtab_ptr->lock ) ); // search a matching item xptr_t item_xp = xhtab_ptr->scan( xhtab_xp , index , key ); if( item_xp != XPTR_NULL ) // error if found { // release the lock protecting hash table remote_rwlock_wr_unlock( XPTR( xhtab_cxy , &xhtab_ptr->lock ) ); return EINVAL; } else // insert item if not found { // register item in hash table xlist_add_last( XPTR( xhtab_cxy , &xhtab_ptr->roots[index] ) , xlist_xp ); // update number of registered items hal_remote_atomic_add( XPTR( xhtab_cxy , &xhtab_ptr->items ) , 1 ); // release the lock protecting hash table remote_rwlock_wr_unlock( XPTR( xhtab_cxy , &xhtab_ptr->lock ) ); return 0; } } // end xhtab_insert() ///////////////////////////////////// error_t xhtab_remove( xptr_t xhtab_xp, void * key, xptr_t xlist_entry_xp ) { // get xhtab cluster and local pointer cxy_t xhtab_cxy = GET_CXY( xhtab_xp ); xhtab_t * xhtab_ptr = (xhtab_t *)GET_PTR( xhtab_xp ); // compute index from key uint32_t index = xhtab_ptr->index( key ); // take the lock protecting hash table remote_rwlock_wr_lock( XPTR( xhtab_cxy , &xhtab_ptr->lock ) ); // get extended pointer on item to remove xptr_t item_xp = xhtab_ptr->scan( xhtab_xp , index , key ); if( item_xp == XPTR_NULL ) // error if not found { // release the lock protecting hash table remote_rwlock_wr_unlock( XPTR( xhtab_cxy , &xhtab_ptr->lock ) ); return EINVAL; } else // remove item if found { // remove item from hash table <=> unlink xlist_entry_t xlist_unlink( xlist_entry_xp ); // update number of registered items hal_remote_atomic_add( XPTR( xhtab_cxy , &xhtab_ptr->items ) , -1 ); // release the lock protecting hash table remote_rwlock_wr_unlock( XPTR( xhtab_cxy , &xhtab_ptr->lock ) ); return 0; } } // end xhtab_remove() ///////////////////////////////////////// xptr_t xhtab_lookup( xptr_t xhtab_xp, void * key ) { xptr_t item_xp; // get xhtab cluster and local pointer cxy_t xhtab_cxy = GET_CXY( xhtab_xp ); xhtab_t * xhtab_ptr = (xhtab_t *)GET_PTR( xhtab_xp ); // compute index from key uint32_t index = xhtab_ptr->index( key ); // take the lock protecting hash table remote_rwlock_rd_lock( XPTR( xhtab_cxy , &xhtab_ptr->lock ) ); // scan sub-list item_xp = xhtab_ptr->scan( xhtab_xp , index , key ); // release the lock protecting hash table remote_rwlock_rd_unlock( XPTR( xhtab_cxy , &xhtab_ptr->lock ) ); return item_xp; } // end xhtab_lookup()