/* * cluster.c - Cluster-Manager related operations * * Author Ghassan Almaless (2008,2009,2010,2011,2012) * Mohamed Lamine Karaoui (2015) * 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 #include #include #include #include #include #include #include #include #include /////////////////////////////////////////////////////////////////////////////////////////// // Extern global variables /////////////////////////////////////////////////////////////////////////////////////////// extern process_t process_zero; // allocated in kernel_init.c file ////////////////////////////////// void cluster_sysfs_register(void) { // TODO } ///////////////////////////////////////////////// error_t cluster_init( struct boot_info_s * info ) { error_t error; lpid_t lpid; // local process_index lid_t lid; // local core index cluster_t * cluster = LOCAL_CLUSTER; // initialize cluster global parameters cluster->paddr_width = info->paddr_width; cluster->x_width = info->x_width; cluster->y_width = info->y_width; cluster->x_size = info->x_size; cluster->y_size = info->y_size; cluster->io_cxy = info->io_cxy; // initialize cluster local parameters cluster->cores_nr = info->cores_nr; cluster->cores_in_kernel = 0; // initialize the lock protecting the embedded kcm allocator spinlock_init( &cluster->kcm_lock ); cluster_dmsg("\n[INFO] %s for cluster %x enters\n", __FUNCTION__ , local_cxy ); // initialises DQDT cluster->dqdt_root_level = dqdt_init( info->x_size, info->y_size, info->y_width ); cluster->threads_var = 0; cluster->pages_var = 0; // initialises embedded PPM error = hal_ppm_init( info ); if( error ) { printk("\n[ERROR] in %s : cannot initialize PPM in cluster %x\n", __FUNCTION__ , local_cxy ); return ENOMEM; } cluster_dmsg("\n[INFO] %s : PPM initialized in cluster %x at cycle %d\n", __FUNCTION__ , local_cxy , hal_get_cycles() ); // initialises embedded KHM khm_init( &cluster->khm ); cluster_dmsg("\n[INFO] %s : KHM initialized in cluster %x at cycle %d\n", __FUNCTION__ , local_cxy , hal_get_cycles() ); // initialises embedded KCM kcm_init( &cluster->kcm , KMEM_KCM ); cluster_dmsg("\n[INFO] %s : KCM initialized in cluster %x at cycle %d\n", __FUNCTION__ , local_cxy , hal_get_cycles() ); // initialises all cores descriptors for( lid = 0 ; lid < cluster->cores_nr; lid++ ) { core_init( &cluster->core_tbl[lid], // target core descriptor lid, // local core index info->core[lid].gid ); // gid from boot_info_t } cluster_dmsg("\n[INFO] %s : cores initialized in cluster %x at cycle %d\n", __FUNCTION__ , local_cxy , hal_get_cycles() ); // initialises RPC fifo rpc_fifo_init( &cluster->rpc_fifo ); cluster->rpc_threads = 0; cluster_dmsg("\n[INFO] %s : RPC fifo inialized in cluster %x at cycle %d\n", __FUNCTION__ , local_cxy , hal_get_cycles() ); // initialise pref_tbl[] in process manager spinlock_init( &cluster->pmgr.pref_lock ); cluster->pmgr.pref_nr = 0; cluster->pmgr.pref_tbl[0] = XPTR( local_cxy , &process_zero ); for( lpid = 1 ; lpid < CONFIG_MAX_PROCESS_PER_CLUSTER ; lpid++ ) { cluster->pmgr.pref_tbl[lpid] = XPTR_NULL; } // initialise local_list in process manager remote_spinlock_init( XPTR( local_cxy , &cluster->pmgr.local_lock ) ); xlist_root_init( XPTR( local_cxy , &cluster->pmgr.local_root ) ); cluster->pmgr.local_nr = 0; // initialise copies_lists in process manager for( lpid = 0 ; lpid < CONFIG_MAX_PROCESS_PER_CLUSTER ; lpid++ ) { remote_spinlock_init( XPTR( local_cxy , &cluster->pmgr.copies_lock[lpid] ) ); cluster->pmgr.copies_nr[lpid] = 0; xlist_root_init( XPTR( local_cxy , &cluster->pmgr.copies_root[lpid] ) ); } cluster_dmsg("\n[INFO] %s Process Manager initialized in cluster %x at cycle %d\n", __FUNCTION__ , local_cxy , hal_get_cycles() ); hal_fence(); return 0; } // end cluster_init() //////////////////////////////////////// bool_t cluster_is_undefined( cxy_t cxy ) { cluster_t * cluster = LOCAL_CLUSTER; uint32_t y_width = cluster->y_width; uint32_t x = cxy >> y_width; uint32_t y = cxy & ((1<= cluster->x_size ) return true; if( y >= cluster->y_size ) return true; return false; } //////////////////////////////////////////////////////////////////////////////////// // Cores related functions //////////////////////////////////////////////////////////////////////////////////// //////////////////////////////// void cluster_core_kernel_enter() { cluster_t * cluster = LOCAL_CLUSTER; hal_atomic_add( &cluster->cores_in_kernel , 1 ); } /////////////////////////////// void cluster_core_kernel_exit() { cluster_t * cluster = LOCAL_CLUSTER; hal_atomic_add( &cluster->cores_in_kernel , -1 ); } ///////////////////////////////// lid_t cluster_select_local_core() { uint32_t min = 100; lid_t sel = 0; lid_t lid; cluster_t * cluster = LOCAL_CLUSTER; for( lid = 0 ; lid < cluster->cores_nr ; lid++ ) { if( cluster->core_tbl[lid].usage < min ) { min = cluster->core_tbl[lid].usage; sel = lid; } } return sel; } //////////////////////////////////////////////////////////////////////////////////// // Process management related functions //////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////// xptr_t cluster_get_reference_process_from_pid( pid_t pid ) { xptr_t ref_xp; // extended pointer on reference process descriptor cluster_t * cluster = LOCAL_CLUSTER; // get owner cluster and lpid cxy_t owner_cxy = CXY_FROM_PID( pid ); lpid_t lpid = LPID_FROM_PID( pid ); // Check valid PID if( lpid >= CONFIG_MAX_PROCESS_PER_CLUSTER ) return XPTR_NULL; if( local_cxy == owner_cxy ) // local cluster is owner cluster { ref_xp = cluster->pmgr.pref_tbl[lpid]; } else // use a remote_lwd to access owner cluster { ref_xp = (xptr_t)hal_remote_lwd( XPTR( owner_cxy , &cluster->pmgr.pref_tbl[lpid] ) ); } return ref_xp; } //////////////////////////////////////////////// error_t cluster_pid_alloc( xptr_t process_xp, pid_t * pid ) { error_t error; lpid_t lpid; bool_t found; pmgr_t * pm = &LOCAL_CLUSTER->pmgr; // get the process manager lock spinlock_lock( &pm->pref_lock ); // search an empty slot found = false; for( lpid = 0 ; lpid < CONFIG_MAX_PROCESS_PER_CLUSTER ; lpid++ ) { if( pm->pref_tbl[lpid] == XPTR_NULL ) { found = true; break; } } if( found ) { // register process in pref_tbl[] pm->pref_tbl[lpid] = process_xp; pm->pref_nr++; // returns pid *pid = PID( local_cxy , lpid ); error = 0; } else { error = EAGAIN; } // release the processs_manager lock spinlock_unlock( &pm->pref_lock ); return error; } // end cluster_pid_alloc() ///////////////////////////////////// void cluster_pid_release( pid_t pid ) { cxy_t owner_cxy = CXY_FROM_PID( pid ); lpid_t lpid = LPID_FROM_PID( pid ); // check pid argument if( (lpid >= CONFIG_MAX_PROCESS_PER_CLUSTER) || (owner_cxy != local_cxy) ) { printk("\n[PANIC] in %s : illegal PID\n", __FUNCTION__ ); hal_core_sleep(); } pmgr_t * pm = &LOCAL_CLUSTER->pmgr; // get the process manager lock spinlock_lock( &pm->pref_lock ); // remove process from pref_tbl[] pm->pref_tbl[lpid] = XPTR_NULL; pm->pref_nr--; // release the processs_manager lock spinlock_unlock( &pm->pref_lock ); } // end cluster_pid_release() /////////////////////////////////////////////////////////// process_t * cluster_get_local_process_from_pid( pid_t pid ) { xptr_t process_xp; process_t * process_ptr; xptr_t root_xp; xptr_t iter_xp; bool_t found; found = false; root_xp = XPTR( local_cxy , &LOCAL_CLUSTER->pmgr.local_root ); XLIST_FOREACH( root_xp , iter_xp ) { process_xp = XLIST_ELEMENT( iter_xp , process_t , local_list ); process_ptr = (process_t *)GET_PTR( process_xp ); if( process_ptr->pid == pid ) { found = true; break; } } if (found ) return process_ptr; else return NULL; } // end cluster_get_local_process_from_pid() ////////////////////////////////////////////////////// void cluster_process_local_link( process_t * process ) { pmgr_t * pm = &LOCAL_CLUSTER->pmgr; // get lock protecting the process manager local list remote_spinlock_lock( XPTR( local_cxy , &pm->local_lock ) ); xlist_add_first( XPTR( local_cxy , &pm->local_root ), XPTR( local_cxy , &process->local_list ) ); pm->local_nr++; // release lock protecting the process manager local list remote_spinlock_unlock( XPTR( local_cxy , &pm->local_lock ) ); } //////////////////////////////////////////////////////// void cluster_process_local_unlink( process_t * process ) { pmgr_t * pm = &LOCAL_CLUSTER->pmgr; // get lock protecting the process manager local list remote_spinlock_lock( XPTR( local_cxy , &pm->local_lock ) ); xlist_unlink( XPTR( local_cxy , &process->local_list ) ); pm->local_nr--; // release lock protecting the process manager local list remote_spinlock_unlock( XPTR( local_cxy , &pm->local_lock ) ); } /////////////////////////////////////////////////////// void cluster_process_copies_link( process_t * process ) { pmgr_t * pm = &LOCAL_CLUSTER->pmgr; // get owner cluster identifier CXY and process LPID pid_t pid = process->pid; cxy_t owner_cxy = CXY_FROM_PID( pid ); lpid_t lpid = LPID_FROM_PID( pid ); // get extended pointer on lock protecting copies_list[lpid] xptr_t copies_lock = XPTR( owner_cxy , &pm->copies_lock[lpid] ); // get extended pointer on the copies_list[lpid] root xptr_t copies_root = XPTR( owner_cxy , &pm->copies_root[lpid] ); // get extended pointer on the local copies_list entry xptr_t copies_entry = XPTR( local_cxy , &process->copies_list ); // get lock protecting copies_list[lpid] remote_spinlock_lock( copies_lock ); xlist_add_first( copies_root , copies_entry ); hal_remote_atomic_add( XPTR( owner_cxy , &pm->copies_nr[lpid] ) , 1 ); // release lock protecting copies_list[lpid] remote_spinlock_unlock( copies_lock ); } ///////////////////////////////////////////////////////// void cluster_process_copies_unlink( process_t * process ) { pmgr_t * pm = &LOCAL_CLUSTER->pmgr; // get owner cluster identifier CXY and process LPID pid_t pid = process->pid; cxy_t owner_cxy = CXY_FROM_PID( pid ); lpid_t lpid = LPID_FROM_PID( pid ); // get extended pointer on lock protecting copies_list[lpid] xptr_t copies_lock = hal_remote_lwd( XPTR( owner_cxy , &pm->copies_lock[lpid] ) ); // get extended pointer on the local copies_list entry xptr_t copies_entry = XPTR( local_cxy , &process->copies_list ); // get lock protecting copies_list[lpid] remote_spinlock_lock( copies_lock ); xlist_unlink( copies_entry ); hal_remote_atomic_add( XPTR( owner_cxy , &pm->copies_nr[lpid] ) , -1 ); // release lock protecting copies_list[lpid] remote_spinlock_unlock( copies_lock ); } //////////////////////////////////////////////////////////////////////////////////////// // TODO Il me semble que la seule chose que fait ce kernel thread à chaque réveil // est de mettre à jour la DQDT, et de se rendormir... A-t-on besoin d'un thread ? [AG] ////////////////////////////////////////////////////////////////////////////////////////// #if 0 void * cluster_manager_thread( void * arg ) { register struct dqdt_cluster_s * root; register struct cluster_s * root_home; register uint32_t tm_start; register uint32_t tm_end; register uint32_t cpu_id; struct cluster_s * cluster; struct thread_s * this; struct event_s event; struct alarm_info_s info; register uint32_t cntr; register bool_t isRootMgr; register uint32_t period; cpu_enable_all_irq( NULL ); cluster = arg; this = CURRENT_THREAD; cpu_id = cpu_get_id(); root = dqdt_root; root_home = dqdt_root->home; isRootMgr = (cluster == root_home) ? true : false; cntr = 0; period = (isRootMgr) ? CONFIG_DQDT_ROOTMGR_PERIOD * MSEC_PER_TICK : CONFIG_DQDT_MGR_PERIOD * MSEC_PER_TICK; event_set_senderId(&event, this); event_set_priority(&event, E_CHR); event_set_handler(&event, &manager_alarm_event_handler); info.event = &event; thread_preempt_disable(CURRENT_THREAD); // infinite loop while(1) { tm_start = cpu_time_stamp(); dqdt_update(); tm_end = cpu_time_stamp(); if(isRootMgr) { if((cntr % 10) == 0) { printk(INFO, "INFO: cpu %d, DQDT update ended [ %u - %u ]\n", cpu_id, tm_end, tm_end - tm_start); dqdt_print_summary(root); } } alarm_wait( &info , period ); sched_sleep(this); cntr ++; } return NULL; } // end cluster_manager_thread() ////////////////////////////////////////// EVENT_HANDLER(manager_alarm_event_handler) { struct thread_s *manager; manager = event_get_senderId(event); thread_preempt_disable(CURRENT_THREAD); //printk(INFO, "%s: cpu %d [%u]\n", __FUNCTION__, cpu_get_id(), cpu_time_stamp()); sched_wakeup(manager); thread_preempt_enable(CURRENT_THREAD); return 0; } /////////////////////////////////////////////// EVENT_HANDLER(cluster_key_create_event_handler) { struct cluster_s *cluster; struct thread_s *sender; ckey_t *ckey; uint32_t key; sender = event_get_senderId(event); ckey = event_get_argument(event); cluster = current_cluster; key = cluster->next_key; while((key < CLUSTER_TOTAL_KEYS_NR) && (cluster->keys_tbl[key] != NULL)) key ++; if(key < CLUSTER_TOTAL_KEYS_NR) { ckey->val = key; cluster->keys_tbl[key] = (void *) 0x1; // Reserved cluster->next_key = key; event_set_error(event, 0); } else event_set_error(event, ENOSPC); sched_wakeup(sender); return 0; } /////////////////////////////////////////////// EVENT_HANDLER(cluster_key_delete_event_handler) { struct cluster_s *cluster; struct thread_s *sender; ckey_t *ckey; uint32_t key; sender = event_get_senderId(event); ckey = event_get_argument(event); cluster = current_cluster; key = ckey->val; if(key < cluster->next_key) cluster->next_key = key; cluster->keys_tbl[key] = NULL; event_set_error(event, 0); sched_wakeup(sender); return 0; } #define _CKEY_CREATE 0x0 #define _CKEY_DELETE 0x1 error_t cluster_do_key_op(ckey_t *key, uint32_t op) { struct event_s event; struct thread_s *this; struct cluster_s *cluster; struct cpu_s *cpu; this = CURRENT_THREAD; event_set_priority(&event, E_FUNC); event_set_senderId(&event, this); event_set_argument(&event, key); if(op == _CKEY_CREATE) event_set_handler(&event, cluster_key_create_event_handler); else event_set_handler(&event, cluster_key_delete_event_handler); cluster = current_cluster; cpu = cluster->bscluster->bscpu; event_send(&event, &cpu->re_listner); sched_sleep(this); return event_get_error(&event); } error_t cluster_key_create(ckey_t *key) { return cluster_do_key_op(key, _CKEY_CREATE); } error_t cluster_key_delete(ckey_t *key) { return cluster_do_key_op(key, _CKEY_DELETE); } void* cluster_getspecific(ckey_t *key) { struct cluster_s *cluster; cluster = current_cluster; return cluster->keys_tbl[key->val]; } void cluster_setspecific(ckey_t *key, void *val) { struct cluster_s *cluster; cluster = current_cluster; cluster->keys_tbl[key->val] = val; } #endif