| [1] | 1 | /* | 
|---|
 | 2 |  * thread.c -  implementation of thread operations (user & kernel) | 
|---|
| [171] | 3 |  * | 
|---|
| [1] | 4 |  * Author  Ghassan Almaless (2008,2009,2010,2011,2012) | 
|---|
| [23] | 5 |  *         Alain Greiner (2016,2017) | 
|---|
| [1] | 6 |  * | 
|---|
 | 7 |  * Copyright (c) UPMC Sorbonne Universites | 
|---|
 | 8 |  * | 
|---|
| [5] | 9 |  * This file is part of ALMOS-MKH. | 
|---|
| [1] | 10 |  * | 
|---|
| [5] | 11 |  * ALMOS-MKH is free software; you can redistribute it and/or modify it | 
|---|
| [1] | 12 |  * under the terms of the GNU General Public License as published by | 
|---|
 | 13 |  * the Free Software Foundation; version 2.0 of the License. | 
|---|
 | 14 |  * | 
|---|
| [5] | 15 |  * ALMOS-MKH is distributed in the hope that it will be useful, but | 
|---|
| [1] | 16 |  * WITHOUT ANY WARRANTY; without even the implied warranty of | 
|---|
 | 17 |  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU | 
|---|
 | 18 |  * General Public License for more details. | 
|---|
 | 19 |  * | 
|---|
 | 20 |  * You should have received a copy of the GNU General Public License | 
|---|
| [5] | 21 |  * along with ALMOS-MKH; if not, write to the Free Software Foundation, | 
|---|
| [1] | 22 |  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | 
|---|
 | 23 |  */ | 
|---|
 | 24 |  | 
|---|
| [14] | 25 | #include <kernel_config.h> | 
|---|
| [1] | 26 | #include <hal_types.h> | 
|---|
 | 27 | #include <hal_context.h> | 
|---|
 | 28 | #include <hal_irqmask.h> | 
|---|
 | 29 | #include <hal_special.h> | 
|---|
 | 30 | #include <hal_remote.h> | 
|---|
 | 31 | #include <memcpy.h> | 
|---|
 | 32 | #include <printk.h> | 
|---|
 | 33 | #include <cluster.h> | 
|---|
 | 34 | #include <process.h> | 
|---|
 | 35 | #include <scheduler.h> | 
|---|
| [188] | 36 | #include <dev_pic.h> | 
|---|
| [1] | 37 | #include <core.h> | 
|---|
 | 38 | #include <list.h> | 
|---|
 | 39 | #include <xlist.h> | 
|---|
 | 40 | #include <page.h> | 
|---|
 | 41 | #include <kmem.h> | 
|---|
 | 42 | #include <ppm.h> | 
|---|
 | 43 | #include <thread.h> | 
|---|
 | 44 |  | 
|---|
 | 45 | ////////////////////////////////////////////////////////////////////////////////////// | 
|---|
 | 46 | // Extern global variables | 
|---|
 | 47 | ////////////////////////////////////////////////////////////////////////////////////// | 
|---|
 | 48 |  | 
|---|
 | 49 | extern process_t      process_zero; | 
|---|
 | 50 |  | 
|---|
 | 51 | ////////////////////////////////////////////////////////////////////////////////////// | 
|---|
| [16] | 52 | // This function returns a printable string for the thread type. | 
|---|
| [1] | 53 | ////////////////////////////////////////////////////////////////////////////////////// | 
|---|
| [5] | 54 | char * thread_type_str( uint32_t type ) | 
|---|
 | 55 | { | 
|---|
| [296] | 56 |     if     ( type == THREAD_USER   ) return "USR"; | 
|---|
| [16] | 57 |     else if( type == THREAD_RPC    ) return "RPC"; | 
|---|
 | 58 |     else if( type == THREAD_DEV    ) return "DEV"; | 
|---|
| [296] | 59 |     else if( type == THREAD_KERNEL ) return "KER"; | 
|---|
 | 60 |     else if( type == THREAD_IDLE   ) return "IDL"; | 
|---|
| [5] | 61 |     else                             return "undefined"; | 
|---|
 | 62 | } | 
|---|
 | 63 |  | 
|---|
| [1] | 64 | ///////////////////////////////////////////////////////////////////////////////////// | 
|---|
| [14] | 65 | // This static function allocates physical memory for a thread descriptor. | 
|---|
 | 66 | // It can be called by the three functions: | 
|---|
| [1] | 67 | // - thread_user_create() | 
|---|
| [14] | 68 | // - thread_user_fork() | 
|---|
| [1] | 69 | // - thread_kernel_create() | 
|---|
 | 70 | ///////////////////////////////////////////////////////////////////////////////////// | 
|---|
| [14] | 71 | // @ return pointer on thread descriptor if success / return NULL if failure. | 
|---|
| [1] | 72 | ///////////////////////////////////////////////////////////////////////////////////// | 
|---|
| [14] | 73 | static thread_t * thread_alloc() | 
|---|
| [1] | 74 | { | 
|---|
| [23] | 75 |         page_t       * page;   // pointer on page descriptor containing thread descriptor | 
|---|
| [171] | 76 |         kmem_req_t     req;    // kmem request | 
|---|
| [1] | 77 |  | 
|---|
 | 78 |         // allocates memory for thread descriptor + kernel stack | 
|---|
 | 79 |         req.type  = KMEM_PAGE; | 
|---|
| [14] | 80 |         req.size  = CONFIG_THREAD_DESC_ORDER; | 
|---|
| [1] | 81 |         req.flags = AF_KERNEL | AF_ZERO; | 
|---|
 | 82 |         page      = kmem_alloc( &req ); | 
|---|
 | 83 |  | 
|---|
| [23] | 84 |         if( page == NULL ) return NULL; | 
|---|
| [1] | 85 |  | 
|---|
| [315] | 86 |     // return pointer on new thread descriptor | 
|---|
 | 87 |     xptr_t base_xp = ppm_page2base( XPTR(local_cxy , page ) ); | 
|---|
 | 88 |     return (thread_t *)GET_PTR( base_xp ); | 
|---|
 | 89 |  | 
|---|
 | 90 | }  // end thread_alloc() | 
|---|
 | 91 |    | 
|---|
 | 92 |  | 
|---|
| [14] | 93 | ///////////////////////////////////////////////////////////////////////////////////// | 
|---|
| [23] | 94 | // This static function releases the physical memory for a thread descriptor. | 
|---|
| [53] | 95 | // It is called by the three functions: | 
|---|
| [23] | 96 | // - thread_user_create() | 
|---|
 | 97 | // - thread_user_fork() | 
|---|
 | 98 | // - thread_kernel_create() | 
|---|
 | 99 | ///////////////////////////////////////////////////////////////////////////////////// | 
|---|
 | 100 | // @ thread  : pointer on thread descriptor. | 
|---|
 | 101 | ///////////////////////////////////////////////////////////////////////////////////// | 
|---|
 | 102 | static void thread_release( thread_t * thread ) | 
|---|
 | 103 | { | 
|---|
 | 104 |     kmem_req_t   req; | 
|---|
 | 105 |  | 
|---|
| [315] | 106 |     xptr_t base_xp = ppm_base2page( XPTR(local_cxy , thread ) ); | 
|---|
 | 107 |  | 
|---|
| [23] | 108 |     req.type  = KMEM_PAGE; | 
|---|
| [315] | 109 |     req.ptr   = GET_PTR( base_xp ); | 
|---|
| [23] | 110 |     kmem_free( &req ); | 
|---|
 | 111 | } | 
|---|
 | 112 |  | 
|---|
 | 113 | ///////////////////////////////////////////////////////////////////////////////////// | 
|---|
| [14] | 114 | // This static function initializes a thread descriptor (kernel or user). | 
|---|
 | 115 | // It can be called by the four functions: | 
|---|
 | 116 | // - thread_user_create() | 
|---|
 | 117 | // - thread_user_fork() | 
|---|
 | 118 | // - thread_kernel_create() | 
|---|
 | 119 | // - thread_user_init() | 
|---|
 | 120 | ///////////////////////////////////////////////////////////////////////////////////// | 
|---|
 | 121 | // @ thread       : pointer on thread descriptor | 
|---|
 | 122 | // @ process      : pointer on process descriptor. | 
|---|
 | 123 | // @ type         : thread type. | 
|---|
 | 124 | // @ func         : pointer on thread entry function. | 
|---|
 | 125 | // @ args         : pointer on thread entry function arguments. | 
|---|
 | 126 | // @ core_lid     : target core local index. | 
|---|
 | 127 | // @ u_stack_base : stack base (user thread only) | 
|---|
 | 128 | // @ u_stack_size : stack base (user thread only) | 
|---|
 | 129 | ///////////////////////////////////////////////////////////////////////////////////// | 
|---|
 | 130 | static error_t thread_init( thread_t      * thread, | 
|---|
 | 131 |                             process_t     * process, | 
|---|
 | 132 |                             thread_type_t   type, | 
|---|
 | 133 |                             void          * func, | 
|---|
 | 134 |                             void          * args, | 
|---|
 | 135 |                             lid_t           core_lid, | 
|---|
 | 136 |                             intptr_t        u_stack_base, | 
|---|
 | 137 |                             uint32_t        u_stack_size ) | 
|---|
 | 138 | { | 
|---|
 | 139 |     error_t        error; | 
|---|
 | 140 |     trdid_t        trdid;      // allocated thread identifier | 
|---|
 | 141 |  | 
|---|
 | 142 |         cluster_t    * local_cluster = LOCAL_CLUSTER; | 
|---|
 | 143 |  | 
|---|
 | 144 |     // register new thread in process descriptor, and get a TRDID | 
|---|
| [1] | 145 |     spinlock_lock( &process->th_lock ); | 
|---|
 | 146 |     error = process_register_thread( process, thread , &trdid ); | 
|---|
 | 147 |     spinlock_unlock( &process->th_lock ); | 
|---|
 | 148 |  | 
|---|
| [171] | 149 |     if( error ) | 
|---|
| [1] | 150 |     { | 
|---|
| [14] | 151 |         printk("\n[ERROR] in %s : cannot get TRDID\n", __FUNCTION__ ); | 
|---|
 | 152 |         return EINVAL; | 
|---|
| [1] | 153 |     } | 
|---|
| [14] | 154 |  | 
|---|
| [1] | 155 |         // Initialize new thread descriptor | 
|---|
 | 156 |     thread->trdid           = trdid; | 
|---|
| [171] | 157 |         thread->type            = type; | 
|---|
| [1] | 158 |     thread->quantum         = 0;            // TODO | 
|---|
 | 159 |     thread->ticks_nr        = 0;            // TODO | 
|---|
 | 160 |     thread->time_last_check = 0; | 
|---|
 | 161 |         thread->core            = &local_cluster->core_tbl[core_lid]; | 
|---|
 | 162 |         thread->process         = process; | 
|---|
 | 163 |  | 
|---|
 | 164 |     thread->local_locks     = 0; | 
|---|
 | 165 |     list_root_init( &thread->locks_root ); | 
|---|
 | 166 |  | 
|---|
 | 167 |     thread->remote_locks    = 0; | 
|---|
 | 168 |     xlist_root_init( XPTR( local_cxy , &thread->xlocks_root ) ); | 
|---|
 | 169 |  | 
|---|
| [171] | 170 |     thread->u_stack_base    = u_stack_base; | 
|---|
| [1] | 171 |     thread->u_stack_size    = u_stack_size; | 
|---|
| [171] | 172 |     thread->k_stack_base    = (intptr_t)thread; | 
|---|
| [14] | 173 |     thread->k_stack_size    = CONFIG_THREAD_DESC_SIZE; | 
|---|
| [1] | 174 |  | 
|---|
 | 175 |     thread->entry_func      = func;         // thread entry point | 
|---|
 | 176 |     thread->entry_args      = args;         // thread function arguments | 
|---|
| [171] | 177 |     thread->flags           = 0;            // all flags reset | 
|---|
| [1] | 178 |     thread->signals         = 0;            // no pending signal | 
|---|
 | 179 |     thread->errno           = 0;            // no error detected | 
|---|
| [171] | 180 |     thread->fork_user       = 0;            // no fork required | 
|---|
| [1] | 181 |     thread->fork_cxy        = 0; | 
|---|
 | 182 |  | 
|---|
 | 183 |     // thread blocked | 
|---|
 | 184 |     thread->blocked = THREAD_BLOCKED_GLOBAL; | 
|---|
 | 185 |  | 
|---|
 | 186 |     // reset children list | 
|---|
 | 187 |     xlist_root_init( XPTR( local_cxy , &thread->children_root ) ); | 
|---|
 | 188 |     thread->children_nr = 0; | 
|---|
 | 189 |  | 
|---|
 | 190 |     // reset sched list and brothers list | 
|---|
 | 191 |     list_entry_init( &thread->sched_list ); | 
|---|
 | 192 |     xlist_entry_init( XPTR( local_cxy , &thread->brothers_list ) ); | 
|---|
 | 193 |  | 
|---|
 | 194 |     // reset thread info | 
|---|
 | 195 |     memset( &thread->info , 0 , sizeof(thread_info_t) ); | 
|---|
 | 196 |  | 
|---|
 | 197 |     // initialise signature | 
|---|
 | 198 |         thread->signature = THREAD_SIGNATURE; | 
|---|
 | 199 |  | 
|---|
 | 200 |     // update local DQDT | 
|---|
 | 201 |     dqdt_local_update_threads( 1 ); | 
|---|
 | 202 |  | 
|---|
| [171] | 203 |     // register new thread in core scheduler | 
|---|
| [1] | 204 |     sched_register_thread( thread->core , thread ); | 
|---|
 | 205 |  | 
|---|
 | 206 |         return 0; | 
|---|
 | 207 |  | 
|---|
| [296] | 208 | } // end thread_init() | 
|---|
 | 209 |  | 
|---|
| [1] | 210 | ///////////////////////////////////////////////////////// | 
|---|
| [23] | 211 | error_t thread_user_create( pid_t             pid, | 
|---|
 | 212 |                             void            * start_func, | 
|---|
 | 213 |                             void            * start_arg, | 
|---|
| [1] | 214 |                             pthread_attr_t  * attr, | 
|---|
| [23] | 215 |                             thread_t       ** new_thread ) | 
|---|
| [1] | 216 | { | 
|---|
 | 217 |     error_t        error; | 
|---|
 | 218 |         thread_t     * thread;       // pointer on created thread descriptor | 
|---|
 | 219 |     process_t    * process;      // pointer to local process descriptor | 
|---|
 | 220 |     lid_t          core_lid;     // selected core local index | 
|---|
| [23] | 221 |     vseg_t       * vseg;         // stack vseg | 
|---|
| [1] | 222 |  | 
|---|
| [23] | 223 |     thread_dmsg("\n[INFO] %s : enters for process %x\n", __FUNCTION__ , pid ); | 
|---|
| [5] | 224 |  | 
|---|
| [23] | 225 |     // get process descriptor local copy | 
|---|
 | 226 |     process = process_get_local_copy( pid ); | 
|---|
| [1] | 227 |  | 
|---|
| [23] | 228 |     if( process == NULL ) | 
|---|
 | 229 |     { | 
|---|
 | 230 |                 printk("\n[ERROR] in %s : cannot get process descriptor %x\n", | 
|---|
 | 231 |                __FUNCTION__ , pid ); | 
|---|
 | 232 |         return ENOMEM; | 
|---|
 | 233 |     } | 
|---|
 | 234 |  | 
|---|
| [171] | 235 |     // select a target core in local cluster | 
|---|
| [23] | 236 |     if( attr->attributes & PT_ATTR_CORE_DEFINED ) core_lid = attr->lid; | 
|---|
 | 237 |     else                                          core_lid = cluster_select_local_core(); | 
|---|
| [1] | 238 |  | 
|---|
 | 239 |     // check core local index | 
|---|
| [23] | 240 |     if( core_lid >= LOCAL_CLUSTER->cores_nr ) | 
|---|
 | 241 |     { | 
|---|
 | 242 |             printk("\n[ERROR] in %s : illegal core index attribute = %d\n", | 
|---|
 | 243 |                __FUNCTION__ , core_lid ); | 
|---|
| [171] | 244 |  | 
|---|
| [23] | 245 |         return EINVAL; | 
|---|
 | 246 |     } | 
|---|
| [1] | 247 |  | 
|---|
| [171] | 248 |     // allocate a stack from local VMM | 
|---|
| [23] | 249 |     vseg = vmm_create_vseg( process, 0 , 0 , VSEG_TYPE_STACK ); | 
|---|
| [1] | 250 |  | 
|---|
| [170] | 251 |     if( vseg == NULL ) | 
|---|
| [23] | 252 |     { | 
|---|
 | 253 |             printk("\n[ERROR] in %s : cannot create stack vseg\n", __FUNCTION__ ); | 
|---|
 | 254 |                 return ENOMEM; | 
|---|
| [171] | 255 |     } | 
|---|
| [23] | 256 |  | 
|---|
| [171] | 257 |     // allocate memory for thread descriptor | 
|---|
| [14] | 258 |     thread = thread_alloc(); | 
|---|
| [1] | 259 |  | 
|---|
| [23] | 260 |     if( thread == NULL ) | 
|---|
 | 261 |     { | 
|---|
 | 262 |             printk("\n[ERROR] in %s : cannot create new thread\n", __FUNCTION__ ); | 
|---|
 | 263 |         vmm_remove_vseg( vseg ); | 
|---|
 | 264 |         return ENOMEM; | 
|---|
 | 265 |     } | 
|---|
| [14] | 266 |  | 
|---|
| [171] | 267 |     // initialize thread descriptor | 
|---|
| [14] | 268 |     error = thread_init( thread, | 
|---|
 | 269 |                          process, | 
|---|
 | 270 |                          THREAD_USER, | 
|---|
| [23] | 271 |                          start_func, | 
|---|
 | 272 |                          start_arg, | 
|---|
| [14] | 273 |                          core_lid, | 
|---|
| [23] | 274 |                          vseg->min, | 
|---|
 | 275 |                          vseg->max - vseg->min ); | 
|---|
| [14] | 276 |  | 
|---|
| [171] | 277 |     if( error ) | 
|---|
| [14] | 278 |     { | 
|---|
| [23] | 279 |             printk("\n[ERROR] in %s : cannot initialize new thread\n", __FUNCTION__ ); | 
|---|
 | 280 |         vmm_remove_vseg( vseg ); | 
|---|
 | 281 |         thread_release( thread ); | 
|---|
| [14] | 282 |         return EINVAL; | 
|---|
 | 283 |     } | 
|---|
 | 284 |  | 
|---|
| [171] | 285 |     // set LOADABLE flag | 
|---|
| [1] | 286 |     thread->flags = THREAD_FLAG_LOADABLE; | 
|---|
| [14] | 287 |  | 
|---|
 | 288 |     // set DETACHED flag if required | 
|---|
| [23] | 289 |     if( attr->attributes & PT_ATTR_DETACH ) thread->flags |= THREAD_FLAG_DETACHED; | 
|---|
| [1] | 290 |  | 
|---|
| [171] | 291 |     // allocate & initialize CPU context | 
|---|
 | 292 |         error = hal_cpu_context_create( thread ); | 
|---|
| [1] | 293 |  | 
|---|
| [171] | 294 |     if( error ) | 
|---|
| [23] | 295 |     { | 
|---|
 | 296 |             printk("\n[ERROR] in %s : cannot create CPU context\n", __FUNCTION__ ); | 
|---|
 | 297 |         vmm_remove_vseg( vseg ); | 
|---|
 | 298 |         thread_release( thread ); | 
|---|
 | 299 |         return ENOMEM; | 
|---|
 | 300 |     } | 
|---|
 | 301 |  | 
|---|
| [171] | 302 |     // allocate & initialize FPU context | 
|---|
 | 303 |     error = hal_fpu_context_create( thread ); | 
|---|
| [23] | 304 |  | 
|---|
 | 305 |     if( error ) | 
|---|
 | 306 |     { | 
|---|
 | 307 |             printk("\n[ERROR] in %s : cannot create FPU context\n", __FUNCTION__ ); | 
|---|
 | 308 |         vmm_remove_vseg( vseg ); | 
|---|
 | 309 |         thread_release( thread ); | 
|---|
 | 310 |         return ENOMEM; | 
|---|
 | 311 |     } | 
|---|
 | 312 |  | 
|---|
| [171] | 313 |     thread_dmsg("\n[INFO] %s : exit / trdid = %x / process %x / core = %d\n", | 
|---|
| [5] | 314 |                 __FUNCTION__ , thread->trdid , process->pid , core_lid ); | 
|---|
| [1] | 315 |  | 
|---|
 | 316 |     *new_thread = thread; | 
|---|
 | 317 |         return 0; | 
|---|
| [14] | 318 |  | 
|---|
| [296] | 319 | }  // end thread_user_create() | 
|---|
 | 320 |  | 
|---|
| [23] | 321 | ////////////////////////////////////////////// | 
|---|
 | 322 | error_t thread_user_fork( process_t * process, | 
|---|
 | 323 |                           thread_t ** new_thread ) | 
|---|
| [1] | 324 | { | 
|---|
 | 325 |     error_t        error; | 
|---|
| [14] | 326 |         thread_t     * thread;       // pointer on new thread descriptor | 
|---|
| [1] | 327 |     lid_t          core_lid;     // selected core local index | 
|---|
| [23] | 328 |         vseg_t       * vseg;         // stack vseg | 
|---|
| [1] | 329 |  | 
|---|
| [14] | 330 |     thread_dmsg("\n[INFO] %s : enters\n", __FUNCTION__ ); | 
|---|
| [5] | 331 |  | 
|---|
| [171] | 332 |     // allocate a stack from local VMM | 
|---|
| [23] | 333 |     vseg = vmm_create_vseg( process, 0 , 0 , VSEG_TYPE_STACK ); | 
|---|
 | 334 |  | 
|---|
| [286] | 335 |     if( vseg == NULL ) | 
|---|
| [23] | 336 |     { | 
|---|
 | 337 |             printk("\n[ERROR] in %s : cannot create stack vseg\n", __FUNCTION__ ); | 
|---|
 | 338 |                 return ENOMEM; | 
|---|
| [171] | 339 |     } | 
|---|
| [23] | 340 |  | 
|---|
| [1] | 341 |     // select a target core in local cluster | 
|---|
 | 342 |     core_lid = cluster_select_local_core(); | 
|---|
 | 343 |  | 
|---|
 | 344 |     // get pointer on calling thread descriptor | 
|---|
 | 345 |     thread_t * this = CURRENT_THREAD; | 
|---|
 | 346 |  | 
|---|
| [171] | 347 |     // allocate memory for new thread descriptor | 
|---|
| [14] | 348 |     thread = thread_alloc(); | 
|---|
| [1] | 349 |  | 
|---|
| [23] | 350 |     if( thread == NULL ) | 
|---|
 | 351 |     { | 
|---|
 | 352 |         printk("\n[ERROR] in %s : cannot allocate new thread\n", __FUNCTION__ ); | 
|---|
 | 353 |         vmm_remove_vseg( vseg ); | 
|---|
 | 354 |         return ENOMEM; | 
|---|
 | 355 |     } | 
|---|
| [14] | 356 |  | 
|---|
| [171] | 357 |     // initialize thread descriptor | 
|---|
| [14] | 358 |     error = thread_init( thread, | 
|---|
 | 359 |                          process, | 
|---|
 | 360 |                          THREAD_USER, | 
|---|
 | 361 |                          this->entry_func, | 
|---|
 | 362 |                          this->entry_args, | 
|---|
 | 363 |                          core_lid, | 
|---|
| [23] | 364 |                          vseg->min, | 
|---|
 | 365 |                          vseg->max - vseg->min ); | 
|---|
| [14] | 366 |  | 
|---|
| [23] | 367 |     if( error ) | 
|---|
| [14] | 368 |     { | 
|---|
| [23] | 369 |             printk("\n[ERROR] in %s : cannot initialize new thread\n", __FUNCTION__ ); | 
|---|
 | 370 |         vmm_remove_vseg( vseg ); | 
|---|
 | 371 |         thread_release( thread ); | 
|---|
| [14] | 372 |         return EINVAL; | 
|---|
 | 373 |     } | 
|---|
 | 374 |  | 
|---|
| [1] | 375 |     // set ATTACHED flag if set in this thread | 
|---|
| [14] | 376 |     if( this->flags & THREAD_FLAG_DETACHED ) thread->flags = THREAD_FLAG_DETACHED; | 
|---|
| [1] | 377 |  | 
|---|
| [171] | 378 |     // allocate & initialize CPU context from calling thread | 
|---|
 | 379 |         error = hal_cpu_context_copy( thread , this ); | 
|---|
| [1] | 380 |  | 
|---|
| [23] | 381 |     if( error ) | 
|---|
 | 382 |     { | 
|---|
 | 383 |             printk("\n[ERROR] in %s : cannot create CPU context\n", __FUNCTION__ ); | 
|---|
 | 384 |         vmm_remove_vseg( vseg ); | 
|---|
 | 385 |         thread_release( thread ); | 
|---|
 | 386 |         return ENOMEM; | 
|---|
 | 387 |     } | 
|---|
 | 388 |  | 
|---|
| [171] | 389 |     // allocate & initialize FPU context from calling thread | 
|---|
 | 390 |         error = hal_fpu_context_copy( thread , this ); | 
|---|
| [1] | 391 |  | 
|---|
| [23] | 392 |     if( error ) | 
|---|
 | 393 |     { | 
|---|
 | 394 |             printk("\n[ERROR] in %s : cannot create CPU context\n", __FUNCTION__ ); | 
|---|
 | 395 |         vmm_remove_vseg( vseg ); | 
|---|
 | 396 |         thread_release( thread ); | 
|---|
 | 397 |         return ENOMEM; | 
|---|
 | 398 |     } | 
|---|
 | 399 |  | 
|---|
| [171] | 400 |     thread_dmsg("\n[INFO] %s : exit / thread %x for process %x on core %d in cluster %x\n", | 
|---|
| [14] | 401 |                  __FUNCTION__, thread->trdid, process->pid, core_lid, local_cxy ); | 
|---|
| [1] | 402 |  | 
|---|
| [14] | 403 |     *new_thread = thread; | 
|---|
| [1] | 404 |         return 0; | 
|---|
| [5] | 405 |  | 
|---|
| [296] | 406 | }  // end thread_user_fork() | 
|---|
 | 407 |  | 
|---|
| [1] | 408 | ///////////////////////////////////////////////////////// | 
|---|
 | 409 | error_t thread_kernel_create( thread_t     ** new_thread, | 
|---|
 | 410 |                               thread_type_t   type, | 
|---|
| [171] | 411 |                               void          * func, | 
|---|
 | 412 |                               void          * args, | 
|---|
| [1] | 413 |                                               lid_t           core_lid ) | 
|---|
 | 414 | { | 
|---|
 | 415 |     error_t        error; | 
|---|
| [14] | 416 |         thread_t     * thread;       // pointer on new thread descriptor | 
|---|
| [1] | 417 |  | 
|---|
| [296] | 418 |     thread_dmsg("\n[INFO] %s : enter / for type %s on core[%x,%d] / cycle %d\n", | 
|---|
 | 419 |     __FUNCTION__ , thread_type_str( type ) , local_cxy , core_lid , hal_time_stamp() ); | 
|---|
| [1] | 420 |  | 
|---|
| [171] | 421 |     assert( ( (type == THREAD_KERNEL) || (type == THREAD_RPC) || | 
|---|
| [5] | 422 |               (type == THREAD_IDLE)   || (type == THREAD_DEV) ) , | 
|---|
 | 423 |               __FUNCTION__ , "illegal thread type" ); | 
|---|
| [1] | 424 |  | 
|---|
| [171] | 425 |     assert( (core_lid < LOCAL_CLUSTER->cores_nr) , | 
|---|
| [5] | 426 |             __FUNCTION__ , "illegal core_lid" ); | 
|---|
| [1] | 427 |  | 
|---|
| [171] | 428 |     // allocate memory for new thread descriptor | 
|---|
| [14] | 429 |     thread = thread_alloc(); | 
|---|
 | 430 |  | 
|---|
 | 431 |     if( thread == NULL ) return ENOMEM; | 
|---|
 | 432 |  | 
|---|
| [171] | 433 |     // initialize thread descriptor | 
|---|
| [14] | 434 |     error = thread_init( thread, | 
|---|
 | 435 |                          &process_zero, | 
|---|
 | 436 |                          type, | 
|---|
 | 437 |                          func, | 
|---|
 | 438 |                          args, | 
|---|
 | 439 |                          core_lid, | 
|---|
 | 440 |                          0 , 0 );  // no user stack for a kernel thread | 
|---|
 | 441 |  | 
|---|
| [171] | 442 |     if( error ) // release allocated memory for thread descriptor | 
|---|
| [1] | 443 |     { | 
|---|
| [185] | 444 |         thread_release( thread ); | 
|---|
| [14] | 445 |         return EINVAL; | 
|---|
| [1] | 446 |     } | 
|---|
 | 447 |  | 
|---|
| [171] | 448 |     // allocate & initialize CPU context | 
|---|
 | 449 |         hal_cpu_context_create( thread ); | 
|---|
| [14] | 450 |  | 
|---|
| [296] | 451 |     thread_dmsg("\n[INFO] %s : exit / trdid = %x / type = %s / core = [%x,%d] / cycle %d\n", | 
|---|
 | 452 |     __FUNCTION__ , thread->trdid , thread_type_str(type) ,  | 
|---|
 | 453 |     local_cxy , core_lid , hal_time_stamp() ); | 
|---|
| [1] | 454 |  | 
|---|
| [171] | 455 |     *new_thread = thread; | 
|---|
| [1] | 456 |         return 0; | 
|---|
| [5] | 457 |  | 
|---|
| [296] | 458 | } // end thread_kernel_create() | 
|---|
 | 459 |  | 
|---|
| [14] | 460 | /////////////////////////////////////////////////// | 
|---|
 | 461 | error_t thread_kernel_init( thread_t      * thread, | 
|---|
 | 462 |                             thread_type_t   type, | 
|---|
| [171] | 463 |                             void          * func, | 
|---|
 | 464 |                             void          * args, | 
|---|
| [14] | 465 |                                             lid_t           core_lid ) | 
|---|
 | 466 | { | 
|---|
| [171] | 467 |     assert( ( (type == THREAD_KERNEL) || (type == THREAD_RPC) || | 
|---|
| [14] | 468 |               (type == THREAD_IDLE)   || (type == THREAD_DEV) ) , | 
|---|
 | 469 |               __FUNCTION__ , "illegal thread type" ); | 
|---|
| [1] | 470 |  | 
|---|
| [171] | 471 |     if( core_lid >= LOCAL_CLUSTER->cores_nr ) | 
|---|
| [14] | 472 |     { | 
|---|
| [374] | 473 |         panic("illegal core_lid / cores = %d / lid = %d / cxy = %x", | 
|---|
| [373] | 474 |               LOCAL_CLUSTER->cores_nr , core_lid , local_cxy ); | 
|---|
| [14] | 475 |     } | 
|---|
 | 476 |  | 
|---|
 | 477 |     error_t  error = thread_init( thread, | 
|---|
 | 478 |                                   &process_zero, | 
|---|
 | 479 |                                   type, | 
|---|
 | 480 |                                   func, | 
|---|
 | 481 |                                   args, | 
|---|
 | 482 |                                   core_lid, | 
|---|
 | 483 |                                   0 , 0 );   // no user stack for a kernel thread | 
|---|
 | 484 |  | 
|---|
 | 485 |     // allocate & initialize CPU context if success | 
|---|
 | 486 |     if( error == 0 ) hal_cpu_context_create( thread ); | 
|---|
| [171] | 487 |  | 
|---|
| [14] | 488 |     return error; | 
|---|
| [171] | 489 | } | 
|---|
| [14] | 490 |  | 
|---|
| [1] | 491 | /////////////////////////////////////////////////////////////////////////////////////// | 
|---|
 | 492 | // TODO: check that all memory dynamically allocated during thread execution | 
|---|
 | 493 | // has been released, using a cache of mmap and malloc requests. [AG] | 
|---|
 | 494 | /////////////////////////////////////////////////////////////////////////////////////// | 
|---|
 | 495 | void thread_destroy( thread_t * thread ) | 
|---|
 | 496 | { | 
|---|
 | 497 |         uint32_t     tm_start; | 
|---|
 | 498 |         uint32_t     tm_end; | 
|---|
| [60] | 499 |     reg_t        state; | 
|---|
| [1] | 500 |  | 
|---|
 | 501 |     process_t  * process    = thread->process; | 
|---|
 | 502 |     core_t     * core       = thread->core; | 
|---|
 | 503 |  | 
|---|
| [5] | 504 |     thread_dmsg("\n[INFO] %s : enters for thread %x in process %x / type = %s\n", | 
|---|
 | 505 |                 __FUNCTION__ , thread->trdid , process->pid , thread_type_str( thread->type ) ); | 
|---|
| [1] | 506 |  | 
|---|
| [5] | 507 |     assert( (thread->children_nr == 0) , __FUNCTION__ , "still attached children" ); | 
|---|
 | 508 |  | 
|---|
 | 509 |     assert( (thread->local_locks == 0) , __FUNCTION__ , "all local locks not released" ); | 
|---|
| [171] | 510 |  | 
|---|
| [5] | 511 |     assert( (thread->remote_locks == 0) , __FUNCTION__ , "all remote locks not released" ); | 
|---|
 | 512 |  | 
|---|
| [101] | 513 |         tm_start = hal_get_cycles(); | 
|---|
| [1] | 514 |  | 
|---|
 | 515 |     // update intrumentation values | 
|---|
 | 516 |     uint32_t pgfaults = thread->info.pgfault_nr; | 
|---|
 | 517 |     uint32_t u_errors = thread->info.u_err_nr; | 
|---|
 | 518 |     uint32_t m_errors = thread->info.m_err_nr; | 
|---|
 | 519 |  | 
|---|
 | 520 |         process->vmm.pgfault_nr += pgfaults; | 
|---|
 | 521 |         process->vmm.u_err_nr   += u_errors; | 
|---|
 | 522 |         process->vmm.m_err_nr   += m_errors; | 
|---|
 | 523 |  | 
|---|
 | 524 |     // release memory allocated for CPU context and FPU context | 
|---|
 | 525 |         hal_cpu_context_destroy( thread ); | 
|---|
 | 526 |         hal_fpu_context_destroy( thread ); | 
|---|
 | 527 |          | 
|---|
 | 528 |     // release FPU if required | 
|---|
 | 529 |     // TODO This should be done before calling thread_destroy() | 
|---|
 | 530 |         hal_disable_irq( &state ); | 
|---|
 | 531 |         if( core->fpu_owner == thread ) | 
|---|
 | 532 |         { | 
|---|
 | 533 |                 core->fpu_owner = NULL; | 
|---|
 | 534 |                 hal_fpu_disable(); | 
|---|
 | 535 |         } | 
|---|
 | 536 |         hal_restore_irq( state ); | 
|---|
 | 537 |  | 
|---|
| [171] | 538 |     // remove thread from process th_tbl[] | 
|---|
| [1] | 539 |     // TODO This should be done before calling thread_destroy() | 
|---|
 | 540 |     ltid_t ltid = LTID_FROM_TRDID( thread->trdid ); | 
|---|
 | 541 |  | 
|---|
 | 542 |         spinlock_lock( &process->th_lock ); | 
|---|
 | 543 |         process->th_tbl[ltid] = XPTR_NULL; | 
|---|
 | 544 |         process->th_nr--; | 
|---|
 | 545 |         spinlock_unlock( &process->th_lock ); | 
|---|
 | 546 |          | 
|---|
| [23] | 547 |     // update local DQDT | 
|---|
 | 548 |     dqdt_local_update_threads( -1 ); | 
|---|
 | 549 |  | 
|---|
| [1] | 550 |     // invalidate thread descriptor | 
|---|
 | 551 |         thread->signature = 0; | 
|---|
 | 552 |  | 
|---|
 | 553 |     // release memory for thread descriptor | 
|---|
| [23] | 554 |     thread_release( thread ); | 
|---|
| [1] | 555 |  | 
|---|
| [101] | 556 |         tm_end = hal_get_cycles(); | 
|---|
| [1] | 557 |  | 
|---|
| [5] | 558 |         thread_dmsg("\n[INFO] %s : exit for thread %x in process %x / duration = %d\n", | 
|---|
 | 559 |                        __FUNCTION__, thread->trdid , process->pid , tm_end - tm_start ); | 
|---|
| [171] | 560 | } | 
|---|
| [1] | 561 |  | 
|---|
 | 562 | ///////////////////////////////////////////////// | 
|---|
 | 563 | void thread_child_parent_link( xptr_t  xp_parent, | 
|---|
 | 564 |                                xptr_t  xp_child ) | 
|---|
 | 565 | { | 
|---|
| [171] | 566 |     // get extended pointers on children list root | 
|---|
 | 567 |     cxy_t      parent_cxy = GET_CXY( xp_parent ); | 
|---|
| [1] | 568 |     thread_t * parent_ptr = (thread_t *)GET_PTR( xp_parent ); | 
|---|
 | 569 |     xptr_t     root       = XPTR( parent_cxy , &parent_ptr->children_root ); | 
|---|
 | 570 |  | 
|---|
| [171] | 571 |     // get extended pointer on children list entry | 
|---|
 | 572 |     cxy_t      child_cxy  = GET_CXY( xp_child ); | 
|---|
| [1] | 573 |     thread_t * child_ptr  = (thread_t *)GET_PTR( xp_child ); | 
|---|
 | 574 |     xptr_t     entry      = XPTR( child_cxy , &child_ptr->brothers_list ); | 
|---|
 | 575 |  | 
|---|
 | 576 |     // set the link | 
|---|
 | 577 |     xlist_add_first( root , entry ); | 
|---|
 | 578 |     hal_remote_atomic_add( XPTR( parent_cxy , &parent_ptr->children_nr ) , 1 ); | 
|---|
| [171] | 579 | } | 
|---|
| [1] | 580 |  | 
|---|
 | 581 | /////////////////////////////////////////////////// | 
|---|
 | 582 | void thread_child_parent_unlink( xptr_t  xp_parent, | 
|---|
 | 583 |                                  xptr_t  xp_child ) | 
|---|
 | 584 | { | 
|---|
 | 585 |     // get extended pointer on children list lock | 
|---|
| [171] | 586 |     cxy_t      parent_cxy = GET_CXY( xp_parent ); | 
|---|
| [1] | 587 |     thread_t * parent_ptr = (thread_t *)GET_PTR( xp_parent ); | 
|---|
 | 588 |     xptr_t     lock       = XPTR( parent_cxy , &parent_ptr->children_lock ); | 
|---|
 | 589 |  | 
|---|
| [171] | 590 |     // get extended pointer on children list entry | 
|---|
 | 591 |     cxy_t      child_cxy  = GET_CXY( xp_child ); | 
|---|
| [1] | 592 |     thread_t * child_ptr  = (thread_t *)GET_PTR( xp_child ); | 
|---|
 | 593 |     xptr_t     entry      = XPTR( child_cxy , &child_ptr->brothers_list ); | 
|---|
 | 594 |  | 
|---|
 | 595 |     // get the lock | 
|---|
 | 596 |     remote_spinlock_lock( lock ); | 
|---|
 | 597 |  | 
|---|
 | 598 |     // remove the link | 
|---|
 | 599 |     xlist_unlink( entry ); | 
|---|
 | 600 |     hal_remote_atomic_add( XPTR( parent_cxy , &parent_ptr->children_nr ) , -1 ); | 
|---|
| [171] | 601 |  | 
|---|
| [1] | 602 |     // release the lock | 
|---|
 | 603 |     remote_spinlock_unlock( lock ); | 
|---|
 | 604 | } | 
|---|
 | 605 |  | 
|---|
 | 606 | ///////////////////////////////////////////////// | 
|---|
 | 607 | inline void thread_set_signal( thread_t * thread, | 
|---|
 | 608 |                                uint32_t   mask ) | 
|---|
 | 609 | { | 
|---|
 | 610 |     hal_atomic_or( &thread->signals , mask ); | 
|---|
 | 611 | } | 
|---|
| [171] | 612 |  | 
|---|
| [1] | 613 | /////////////////////////////////////////////////// | 
|---|
 | 614 | inline void thread_reset_signal( thread_t * thread, | 
|---|
 | 615 |                                  uint32_t   mask ) | 
|---|
 | 616 | { | 
|---|
 | 617 |     hal_atomic_and( &thread->signals , ~mask ); | 
|---|
 | 618 | } | 
|---|
| [171] | 619 |  | 
|---|
| [1] | 620 | ////////////////////////////////// | 
|---|
 | 621 | inline bool_t thread_is_joinable() | 
|---|
 | 622 | { | 
|---|
 | 623 |     thread_t * this = CURRENT_THREAD; | 
|---|
 | 624 |     return( (this->brothers_list.next != XPTR_NULL) && | 
|---|
 | 625 |             (this->brothers_list.pred != XPTR_NULL) ); | 
|---|
 | 626 | } | 
|---|
 | 627 |  | 
|---|
 | 628 | ////////////////////////////////// | 
|---|
 | 629 | inline bool_t thread_is_runnable() | 
|---|
 | 630 | { | 
|---|
 | 631 |     thread_t * this = CURRENT_THREAD; | 
|---|
 | 632 |     return( this->blocked == 0 ); | 
|---|
 | 633 | } | 
|---|
 | 634 |  | 
|---|
 | 635 | //////////////////////////////// | 
|---|
 | 636 | inline bool_t thread_can_yield() | 
|---|
 | 637 | { | 
|---|
 | 638 |     thread_t * this = CURRENT_THREAD; | 
|---|
| [367] | 639 |     return (this->local_locks == 0) && (this->remote_locks == 0); | 
|---|
| [1] | 640 | } | 
|---|
 | 641 |  | 
|---|
| [367] | 642 | ///////////////////////// | 
|---|
 | 643 | void thread_check_sched() | 
|---|
| [1] | 644 | { | 
|---|
| [338] | 645 |     thread_t * this = CURRENT_THREAD; | 
|---|
| [1] | 646 |  | 
|---|
| [367] | 647 |         if( (this->local_locks == 0) &&  | 
|---|
 | 648 |         (this->remote_locks == 0) && | 
|---|
 | 649 |         (this->flags & THREAD_FLAG_SCHED) )  | 
|---|
 | 650 |     { | 
|---|
 | 651 |         this->flags &= ~THREAD_FLAG_SCHED; | 
|---|
| [338] | 652 |         sched_yield( NULL ); | 
|---|
| [367] | 653 |     } | 
|---|
| [1] | 654 | } | 
|---|
 | 655 |  | 
|---|
 | 656 | ///////////////////// | 
|---|
 | 657 | error_t thread_exit() | 
|---|
 | 658 | { | 
|---|
| [60] | 659 |     reg_t      sr_save; | 
|---|
| [1] | 660 |  | 
|---|
 | 661 |         thread_t * this = CURRENT_THREAD; | 
|---|
 | 662 |  | 
|---|
 | 663 |     // test if this thread can be descheduled | 
|---|
 | 664 |         if( !thread_can_yield() ) | 
|---|
 | 665 |         { | 
|---|
 | 666 |         printk("ERROR in %s : thread %x in process %x on core %d in cluster %x\n" | 
|---|
 | 667 |                " did not released all locks\n", | 
|---|
 | 668 |                __FUNCTION__ , this->trdid , this->process->pid , | 
|---|
 | 669 |                CURRENT_CORE->lid , local_cxy ); | 
|---|
 | 670 |         return EINVAL; | 
|---|
 | 671 |     } | 
|---|
 | 672 |  | 
|---|
 | 673 |     if( this->flags & THREAD_FLAG_DETACHED ) | 
|---|
 | 674 |     { | 
|---|
 | 675 |         // if detached set signal and set blocking cause atomically | 
|---|
 | 676 |         hal_disable_irq( &sr_save ); | 
|---|
 | 677 |         thread_set_signal( this , THREAD_SIG_KILL ); | 
|---|
 | 678 |         thread_block( this , THREAD_BLOCKED_EXIT ); | 
|---|
 | 679 |         hal_restore_irq( sr_save ); | 
|---|
 | 680 |     } | 
|---|
| [171] | 681 |     else | 
|---|
| [1] | 682 |     { | 
|---|
| [171] | 683 |         // if attached, set blocking cause | 
|---|
| [1] | 684 |         thread_block( this , THREAD_BLOCKED_EXIT ); | 
|---|
 | 685 |     } | 
|---|
 | 686 |  | 
|---|
 | 687 |     // deschedule | 
|---|
| [296] | 688 |     sched_yield( NULL ); | 
|---|
| [1] | 689 |     return 0; | 
|---|
| [171] | 690 | } | 
|---|
| [1] | 691 |  | 
|---|
 | 692 | ///////////////////////////////////// | 
|---|
 | 693 | void thread_block( thread_t * thread, | 
|---|
 | 694 |                    uint32_t   cause ) | 
|---|
 | 695 | { | 
|---|
| [171] | 696 |     // set blocking cause | 
|---|
| [1] | 697 |     hal_atomic_or( &thread->blocked , cause ); | 
|---|
| [171] | 698 | } | 
|---|
| [1] | 699 |  | 
|---|
 | 700 | //////////////////////////////////// | 
|---|
 | 701 | void thread_unblock( xptr_t   thread, | 
|---|
 | 702 |                     uint32_t cause ) | 
|---|
 | 703 | { | 
|---|
 | 704 |     // get thread cluster and local pointer | 
|---|
| [171] | 705 |     cxy_t      cxy = GET_CXY( thread ); | 
|---|
| [1] | 706 |     thread_t * ptr = (thread_t *)GET_PTR( thread ); | 
|---|
 | 707 |  | 
|---|
 | 708 |     // reset blocking cause | 
|---|
 | 709 |     hal_remote_atomic_and( XPTR( cxy , &ptr->blocked ) , ~cause ); | 
|---|
| [171] | 710 | } | 
|---|
| [1] | 711 |  | 
|---|
 | 712 | ///////////////////////////////////// | 
|---|
 | 713 | void thread_kill( thread_t * target ) | 
|---|
 | 714 | { | 
|---|
 | 715 |     // set SIG_KILL signal in target thread descriptor | 
|---|
 | 716 |     thread_set_signal( target , THREAD_SIG_KILL ); | 
|---|
 | 717 |  | 
|---|
 | 718 |     // set the global blocked bit in target thread descriptor. | 
|---|
 | 719 |     thread_block( target , THREAD_BLOCKED_GLOBAL ); | 
|---|
 | 720 |  | 
|---|
| [188] | 721 |     // send an IPI to schedule the target thread core. | 
|---|
 | 722 |     dev_pic_send_ipi( local_cxy , target->core->lid ); | 
|---|
| [171] | 723 | } | 
|---|
| [1] | 724 |  | 
|---|
| [14] | 725 | /////////////////////// | 
|---|
 | 726 | void thread_idle_func() | 
|---|
| [1] | 727 | { | 
|---|
| [68] | 728 | #if CONFIG_IDLE_DEBUG | 
|---|
| [14] | 729 |     lid_t  lid = CURRENT_CORE->lid; | 
|---|
| [68] | 730 | #endif | 
|---|
| [14] | 731 |  | 
|---|
| [1] | 732 |     while( 1 ) | 
|---|
 | 733 |     { | 
|---|
| [50] | 734 |         idle_dmsg("\n[INFO] %s : core[%x][%d] goes to sleep at cycle %d\n", | 
|---|
| [101] | 735 |                     __FUNCTION__ , local_cxy , lid , hal_get_cycles() ); | 
|---|
| [1] | 736 |  | 
|---|
 | 737 |         // force core to sleeping state | 
|---|
| [373] | 738 |         //hal_core_sleep(); | 
|---|
| [1] | 739 |  | 
|---|
| [50] | 740 |         idle_dmsg("\n[INFO] %s : core[%x][%d] wake up at cycle %d\n", | 
|---|
| [101] | 741 |                     __FUNCTION__ , local_cxy , lid , hal_get_cycles() ); | 
|---|
| [1] | 742 |  | 
|---|
| [14] | 743 |         // force scheduling | 
|---|
| [296] | 744 |         sched_yield( NULL ); | 
|---|
| [1] | 745 |    } | 
|---|
| [171] | 746 | } | 
|---|
| [1] | 747 |  | 
|---|
| [16] | 748 | ///////////////////////////////////////////////// | 
|---|
 | 749 | void thread_user_time_update( thread_t * thread ) | 
|---|
 | 750 | { | 
|---|
 | 751 |     // TODO | 
|---|
| [337] | 752 |     // printk("\n[WARNING] function %s not implemented\n", __FUNCTION__ ); | 
|---|
| [16] | 753 | } | 
|---|
| [1] | 754 |  | 
|---|
| [16] | 755 | /////////////////////////////////////////////////// | 
|---|
 | 756 | void thread_kernel_time_update( thread_t * thread ) | 
|---|
 | 757 | { | 
|---|
 | 758 |     // TODO | 
|---|
| [337] | 759 |     // printk("\n[WARNING] function %s not implemented\n", __FUNCTION__ ); | 
|---|
| [16] | 760 | } | 
|---|
 | 761 |  | 
|---|
 | 762 | //////////////////////////////////////////////// | 
|---|
| [23] | 763 | void thread_signals_handle( thread_t * thread ) | 
|---|
| [16] | 764 | { | 
|---|
 | 765 |     // TODO | 
|---|
| [337] | 766 |     // printk("\n[WARNING] function %s not implemented\n", __FUNCTION__ ); | 
|---|
| [16] | 767 | } | 
|---|
 | 768 |  | 
|---|
| [23] | 769 | ///////////////////////////////////// | 
|---|
 | 770 | xptr_t thread_get_xptr( pid_t    pid, | 
|---|
 | 771 |                         trdid_t  trdid ) | 
|---|
 | 772 | { | 
|---|
 | 773 |     cxy_t         target_cxy;          // target thread cluster identifier | 
|---|
 | 774 |     ltid_t        target_thread_ltid;  // target thread local index | 
|---|
| [171] | 775 |     thread_t    * target_thread_ptr;   // target thread local pointer | 
|---|
| [23] | 776 |     xptr_t        target_process_xp;   // extended pointer on target process descriptor | 
|---|
| [171] | 777 |     process_t   * target_process_ptr;  // local pointer on target process descriptor | 
|---|
| [23] | 778 |     pid_t         target_process_pid;  // target process identifier | 
|---|
 | 779 |     xlist_entry_t root;                // root of list of process in target cluster | 
|---|
 | 780 |     xptr_t        lock_xp;             // extended pointer on lock protecting  this list | 
|---|
| [16] | 781 |  | 
|---|
| [23] | 782 |     // get target cluster identifier and local thread identifier | 
|---|
 | 783 |     target_cxy         = CXY_FROM_TRDID( trdid ); | 
|---|
 | 784 |     target_thread_ltid = LTID_FROM_TRDID( trdid ); | 
|---|
 | 785 |  | 
|---|
 | 786 |     // get root of list of process descriptors in target cluster | 
|---|
 | 787 |     hal_remote_memcpy( XPTR( local_cxy  , &root ), | 
|---|
 | 788 |                        XPTR( target_cxy , &LOCAL_CLUSTER->pmgr.local_root ), | 
|---|
 | 789 |                        sizeof(xlist_entry_t) ); | 
|---|
 | 790 |  | 
|---|
| [171] | 791 |     // get extended pointer on lock protecting the list of processes | 
|---|
| [23] | 792 |     lock_xp = XPTR( target_cxy , &LOCAL_CLUSTER->pmgr.local_lock ); | 
|---|
 | 793 |  | 
|---|
 | 794 |     // take the lock protecting the list of processes in target cluster | 
|---|
 | 795 |     remote_spinlock_lock( lock_xp ); | 
|---|
 | 796 |  | 
|---|
 | 797 |     // loop on list of process in target cluster to find the PID process | 
|---|
 | 798 |     xptr_t  iter; | 
|---|
 | 799 |     bool_t  found = false; | 
|---|
 | 800 |     XLIST_FOREACH( XPTR( target_cxy , &LOCAL_CLUSTER->pmgr.local_root ) , iter ) | 
|---|
 | 801 |     { | 
|---|
 | 802 |         target_process_xp  = XLIST_ELEMENT( iter , process_t , local_list ); | 
|---|
 | 803 |         target_process_ptr = (process_t *)GET_PTR( target_process_xp ); | 
|---|
 | 804 |         target_process_pid = hal_remote_lw( XPTR( target_cxy , &target_process_ptr->pid ) ); | 
|---|
 | 805 |         if( target_process_pid == pid ) | 
|---|
 | 806 |         { | 
|---|
 | 807 |             found = true; | 
|---|
 | 808 |             break; | 
|---|
 | 809 |         } | 
|---|
 | 810 |     } | 
|---|
 | 811 |  | 
|---|
 | 812 |     // release the lock protecting the list of processes in target cluster | 
|---|
 | 813 |     remote_spinlock_unlock( lock_xp ); | 
|---|
 | 814 |  | 
|---|
 | 815 |     // check target thread found | 
|---|
 | 816 |     if( found == false ) | 
|---|
 | 817 |     { | 
|---|
 | 818 |         return XPTR_NULL; | 
|---|
 | 819 |     } | 
|---|
 | 820 |  | 
|---|
 | 821 |     // get target thread local pointer | 
|---|
 | 822 |     xptr_t xp = XPTR( target_cxy , &target_process_ptr->th_tbl[target_thread_ltid] ); | 
|---|
| [171] | 823 |     target_thread_ptr = (thread_t *)hal_remote_lpt( xp ); | 
|---|
| [23] | 824 |  | 
|---|
 | 825 |     if( target_thread_ptr == NULL ) | 
|---|
 | 826 |     { | 
|---|
 | 827 |         return XPTR_NULL; | 
|---|
 | 828 |     } | 
|---|
 | 829 |  | 
|---|
 | 830 |     return XPTR( target_cxy , target_thread_ptr ); | 
|---|
| [171] | 831 | } | 
|---|
| [23] | 832 |  | 
|---|