| 1 | /* | 
|---|
| 2 |  * process.c - process related management | 
|---|
| 3 |  * | 
|---|
| 4 |  * Authors  Ghassan Almaless (2008,2009,2010,2011,2012) | 
|---|
| 5 |  *          Mohamed Lamine Karaoui (2015) | 
|---|
| 6 |  *          Alain Greiner (2016,2017) | 
|---|
| 7 |  * | 
|---|
| 8 |  * Copyright (c) UPMC Sorbonne Universites | 
|---|
| 9 |  * | 
|---|
| 10 |  * This file is part of ALMOS-MKH.. | 
|---|
| 11 |  * | 
|---|
| 12 |  * ALMOS-MKH is free software; you can redistribute it and/or modify it | 
|---|
| 13 |  * under the terms of the GNU General Public License as published by | 
|---|
| 14 |  * the Free Software Foundation; version 2.0 of the License. | 
|---|
| 15 |  * | 
|---|
| 16 |  * ALMOS-MKH is distributed in the hope that it will be useful, but | 
|---|
| 17 |  * WITHOUT ANY WARRANTY; without even the implied warranty of | 
|---|
| 18 |  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU | 
|---|
| 19 |  * General Public License for more details. | 
|---|
| 20 |  * | 
|---|
| 21 |  * You should have received a copy of the GNU General Public License | 
|---|
| 22 |  * along with ALMOS-MKH; if not, write to the Free Software Foundation, | 
|---|
| 23 |  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | 
|---|
| 24 |  */ | 
|---|
| 25 |  | 
|---|
| 26 | #include <kernel_config.h> | 
|---|
| 27 | #include <hal_types.h> | 
|---|
| 28 | #include <hal_remote.h> | 
|---|
| 29 | #include <hal_uspace.h> | 
|---|
| 30 | #include <errno.h> | 
|---|
| 31 | #include <printk.h> | 
|---|
| 32 | #include <memcpy.h> | 
|---|
| 33 | #include <bits.h> | 
|---|
| 34 | #include <kmem.h> | 
|---|
| 35 | #include <page.h> | 
|---|
| 36 | #include <vmm.h> | 
|---|
| 37 | #include <vfs.h> | 
|---|
| 38 | #include <core.h> | 
|---|
| 39 | #include <thread.h> | 
|---|
| 40 | #include <list.h> | 
|---|
| 41 | #include <scheduler.h> | 
|---|
| 42 | #include <remote_spinlock.h> | 
|---|
| 43 | #include <dqdt.h> | 
|---|
| 44 | #include <cluster.h> | 
|---|
| 45 | #include <ppm.h> | 
|---|
| 46 | #include <boot_info.h> | 
|---|
| 47 | #include <process.h> | 
|---|
| 48 | #include <elf.h> | 
|---|
| 49 | #include <syscalls.h> | 
|---|
| 50 |  | 
|---|
| 51 | ////////////////////////////////////////////////////////////////////////////////////////// | 
|---|
| 52 | // Extern global variables | 
|---|
| 53 | ////////////////////////////////////////////////////////////////////////////////////////// | 
|---|
| 54 |  | 
|---|
| 55 | extern process_t process_zero; | 
|---|
| 56 |  | 
|---|
| 57 | ////////////////////////////////////////////////////////////////////////////////////////// | 
|---|
| 58 | // Process initialisation related functions | 
|---|
| 59 | ////////////////////////////////////////////////////////////////////////////////////////// | 
|---|
| 60 |  | 
|---|
| 61 | /////////////////////////// | 
|---|
| 62 | process_t * process_alloc() | 
|---|
| 63 | { | 
|---|
| 64 |         kmem_req_t   req; | 
|---|
| 65 |  | 
|---|
| 66 |     req.type  = KMEM_PROCESS; | 
|---|
| 67 |         req.size  = sizeof(process_t); | 
|---|
| 68 |         req.flags = AF_KERNEL; | 
|---|
| 69 |  | 
|---|
| 70 |     return (process_t *)kmem_alloc( &req ); | 
|---|
| 71 | } | 
|---|
| 72 |  | 
|---|
| 73 | //////////////////////////////////////// | 
|---|
| 74 | void process_free( process_t * process ) | 
|---|
| 75 | { | 
|---|
| 76 |     kmem_req_t  req; | 
|---|
| 77 |  | 
|---|
| 78 |         req.type = KMEM_PROCESS; | 
|---|
| 79 |         req.ptr  = process; | 
|---|
| 80 |         kmem_free( &req ); | 
|---|
| 81 | } | 
|---|
| 82 |  | 
|---|
| 83 | ///////////////////////////////////////////////// | 
|---|
| 84 | void process_reference_init( process_t * process, | 
|---|
| 85 |                              pid_t       pid, | 
|---|
| 86 |                              xptr_t      parent_xp ) | 
|---|
| 87 | { | 
|---|
| 88 |     cxy_t       parent_cxy; | 
|---|
| 89 |     process_t * parent_ptr; | 
|---|
| 90 |     pid_t       parent_pid; | 
|---|
| 91 |  | 
|---|
| 92 |     process_dmsg("\n[INFO] %s : enters for process %x in cluster %x\n", | 
|---|
| 93 |                  __FUNCTION__ , pid , local_cxy ); | 
|---|
| 94 |  | 
|---|
| 95 |     // get parent process cluster, local pointer, and pid | 
|---|
| 96 |     // for all processes other than process_zero | 
|---|
| 97 |     if( process == &process_zero ) | 
|---|
| 98 |     { | 
|---|
| 99 |         assert( (pid == 0) , __FUNCTION__ , "process_zero must have PID = 0\n"); | 
|---|
| 100 |  | 
|---|
| 101 |         parent_cxy = 0; | 
|---|
| 102 |         parent_ptr = NULL; | 
|---|
| 103 |         parent_pid = 0;      // process_zero is its own parent... | 
|---|
| 104 |     } | 
|---|
| 105 |     else | 
|---|
| 106 |     { | 
|---|
| 107 |         assert( (parent_xp != XPTR_NULL) , __FUNCTION__ , "parent_xp cannot be NULL\n"); | 
|---|
| 108 |  | 
|---|
| 109 |         parent_cxy = GET_CXY( parent_xp ); | 
|---|
| 110 |         parent_ptr = (process_t *)GET_PTR( parent_xp ); | 
|---|
| 111 |         parent_pid = hal_remote_lw( XPTR( parent_cxy , &parent_ptr->pid ) ); | 
|---|
| 112 |     } | 
|---|
| 113 |  | 
|---|
| 114 |     // initialize PID and PPID | 
|---|
| 115 |         process->pid   = pid; | 
|---|
| 116 |     process->ppid  = parent_pid; | 
|---|
| 117 |  | 
|---|
| 118 |     // reset reference process vmm (not for kernel process) | 
|---|
| 119 |     if( pid ) vmm_init( process ); | 
|---|
| 120 |  | 
|---|
| 121 |     // reset reference process file descriptors array | 
|---|
| 122 |         process_fd_init( process ); | 
|---|
| 123 |  | 
|---|
| 124 |     // reset reference process files structures and cwd_lock | 
|---|
| 125 |         process->vfs_root_xp     = XPTR_NULL; | 
|---|
| 126 |         process->vfs_bin_xp      = XPTR_NULL; | 
|---|
| 127 |         process->vfs_cwd_xp      = XPTR_NULL; | 
|---|
| 128 |     remote_rwlock_init( XPTR( local_cxy , &process->cwd_lock ) ); | 
|---|
| 129 |  | 
|---|
| 130 |     // reset children list root | 
|---|
| 131 |     xlist_root_init( XPTR( local_cxy , &process->children_root ) ); | 
|---|
| 132 |         process->children_nr     = 0; | 
|---|
| 133 |  | 
|---|
| 134 |     // reset semaphore / mutex / barrier / condvar list roots | 
|---|
| 135 |     xlist_root_init( XPTR( local_cxy , &process->sem_root ) ); | 
|---|
| 136 |     xlist_root_init( XPTR( local_cxy , &process->mutex_root ) ); | 
|---|
| 137 |     xlist_root_init( XPTR( local_cxy , &process->barrier_root ) ); | 
|---|
| 138 |     xlist_root_init( XPTR( local_cxy , &process->condvar_root ) ); | 
|---|
| 139 |     remote_spinlock_init( XPTR( local_cxy , &process->sync_lock ) ); | 
|---|
| 140 |  | 
|---|
| 141 |     // register new process in the parent children list (not for kernel process) | 
|---|
| 142 |     if( pid ) | 
|---|
| 143 |     { | 
|---|
| 144 |         xptr_t entry = XPTR( local_cxy  , &process->brothers_list ); | 
|---|
| 145 |         xptr_t root  = XPTR( parent_cxy , &parent_ptr->children_root ); | 
|---|
| 146 |         xlist_add_first( root , entry ); | 
|---|
| 147 |     } | 
|---|
| 148 |  | 
|---|
| 149 |     // reset th_tbl[] array as empty | 
|---|
| 150 |     uint32_t i; | 
|---|
| 151 |     for( i = 0 ; i < CONFIG_THREAD_MAX_PER_CLUSTER ; i++ ) | 
|---|
| 152 |         { | 
|---|
| 153 |         process->th_tbl[i] = NULL; | 
|---|
| 154 |     } | 
|---|
| 155 |     process->th_nr  = 0; | 
|---|
| 156 |     spinlock_init( &process->th_lock ); | 
|---|
| 157 |  | 
|---|
| 158 |     // set ref_xp field | 
|---|
| 159 |     process->ref_xp = XPTR( local_cxy , process ); | 
|---|
| 160 |  | 
|---|
| 161 |     // register new process descriptor in local cluster manager local_list | 
|---|
| 162 |     cluster_process_local_link( process ); | 
|---|
| 163 |  | 
|---|
| 164 |     // register new process descriptor in owner cluster manager copies_list | 
|---|
| 165 |     cluster_process_copies_link( process ); | 
|---|
| 166 |  | 
|---|
| 167 |     // initialize signal manager TODO [AG] | 
|---|
| 168 |  | 
|---|
| 169 |         hal_fence(); | 
|---|
| 170 |  | 
|---|
| 171 |     process_dmsg("\n[INFO] %s : exit for process %x in cluster %x\n", | 
|---|
| 172 |                  __FUNCTION__ , pid ); | 
|---|
| 173 |  | 
|---|
| 174 | }  // process_reference init() | 
|---|
| 175 |  | 
|---|
| 176 | ///////////////////////////////////////////////////// | 
|---|
| 177 | error_t process_copy_init( process_t * local_process, | 
|---|
| 178 |                            xptr_t      reference_process_xp ) | 
|---|
| 179 | { | 
|---|
| 180 |     // get reference process cluster and local pointer | 
|---|
| 181 |     cxy_t       ref_cxy = GET_CXY( reference_process_xp ); | 
|---|
| 182 |     process_t * ref_ptr = (process_t *)GET_PTR( reference_process_xp ); | 
|---|
| 183 |  | 
|---|
| 184 |     // reset local process vmm | 
|---|
| 185 |     vmm_init( local_process ); | 
|---|
| 186 |  | 
|---|
| 187 |     // reset process file descriptors array | 
|---|
| 188 |         process_fd_init( local_process ); | 
|---|
| 189 |  | 
|---|
| 190 |     // reset vfs_root_xp / vfs_bin_xp / vfs_cwd_xp fields | 
|---|
| 191 |     local_process->vfs_root_xp = hal_remote_lwd( XPTR( ref_cxy , &ref_ptr->vfs_root_xp ) ); | 
|---|
| 192 |     local_process->vfs_bin_xp  = hal_remote_lwd( XPTR( ref_cxy , &ref_ptr->vfs_bin_xp ) ); | 
|---|
| 193 |     local_process->vfs_cwd_xp  = XPTR_NULL; | 
|---|
| 194 |  | 
|---|
| 195 |     // set the pid, ppid, ref_xp fields | 
|---|
| 196 |     local_process->pid    = hal_remote_lw( XPTR( ref_cxy , &ref_ptr->pid ) ); | 
|---|
| 197 |     local_process->ppid   = hal_remote_lw( XPTR( ref_cxy , &ref_ptr->ppid ) ); | 
|---|
| 198 |     local_process->ref_xp = reference_process_xp; | 
|---|
| 199 |  | 
|---|
| 200 |     process_dmsg("\n[INFO] %s : enter for process %x in cluster %x\n", | 
|---|
| 201 |                  __FUNCTION__ , local_process->pid ); | 
|---|
| 202 |  | 
|---|
| 203 |     // reset children list root (not used in a process descriptor copy) | 
|---|
| 204 |     xlist_root_init( XPTR( local_cxy , &local_process->children_root ) ); | 
|---|
| 205 |     local_process->children_nr   = 0; | 
|---|
| 206 |  | 
|---|
| 207 |     // reset brothers list (not used in a process descriptor copy) | 
|---|
| 208 |     xlist_entry_init( XPTR( local_cxy , &local_process->brothers_list ) ); | 
|---|
| 209 |  | 
|---|
| 210 |     // reset semaphores list root (not used in a process descriptor copy) | 
|---|
| 211 |     xlist_root_init( XPTR( local_cxy , &local_process->sem_root ) ); | 
|---|
| 212 |     xlist_root_init( XPTR( local_cxy , &local_process->mutex_root ) ); | 
|---|
| 213 |     xlist_root_init( XPTR( local_cxy , &local_process->barrier_root ) ); | 
|---|
| 214 |     xlist_root_init( XPTR( local_cxy , &local_process->condvar_root ) ); | 
|---|
| 215 |  | 
|---|
| 216 |     // reset th_tbl[] array as empty | 
|---|
| 217 |     uint32_t i; | 
|---|
| 218 |     for( i = 0 ; i < CONFIG_THREAD_MAX_PER_CLUSTER ; i++ ) | 
|---|
| 219 |         { | 
|---|
| 220 |         local_process->th_tbl[i] = NULL; | 
|---|
| 221 |     } | 
|---|
| 222 |     local_process->th_nr  = 0; | 
|---|
| 223 |     spinlock_init( &local_process->th_lock ); | 
|---|
| 224 |  | 
|---|
| 225 |     // register new process descriptor in local cluster manager local_list | 
|---|
| 226 |     cluster_process_local_link( local_process ); | 
|---|
| 227 |  | 
|---|
| 228 |     // register new process descriptor in owner cluster manager copies_list | 
|---|
| 229 |     cluster_process_copies_link( local_process ); | 
|---|
| 230 |  | 
|---|
| 231 |     // initialize signal manager TODO [AG] | 
|---|
| 232 |  | 
|---|
| 233 |         hal_fence(); | 
|---|
| 234 |  | 
|---|
| 235 |     process_dmsg("\n[INFO] %s : exit for process %x in cluster %x\n", | 
|---|
| 236 |                  __FUNCTION__ , local_process->pid ); | 
|---|
| 237 |  | 
|---|
| 238 |     return 0; | 
|---|
| 239 |  | 
|---|
| 240 | } // end process_copy_init() | 
|---|
| 241 |  | 
|---|
| 242 | /////////////////////////////////////////// | 
|---|
| 243 | void process_destroy( process_t * process ) | 
|---|
| 244 | { | 
|---|
| 245 |         if( process->th_nr != 0 ) | 
|---|
| 246 |     { | 
|---|
| 247 |         panic("process %x in cluster %x has still active threads\n", | 
|---|
| 248 |               process->pid , local_cxy ); | 
|---|
| 249 |     } | 
|---|
| 250 |  | 
|---|
| 251 |     // get local process manager pointer | 
|---|
| 252 |     pmgr_t * pmgr = &LOCAL_CLUSTER->pmgr; | 
|---|
| 253 |  | 
|---|
| 254 |     // get the lock protecting the list of local process descriptors | 
|---|
| 255 |     remote_spinlock_lock( XPTR( local_cxy , &pmgr->local_lock ) ); | 
|---|
| 256 |  | 
|---|
| 257 |     // remove the process descriptor from local_list in local cluster manager | 
|---|
| 258 |     xlist_unlink( XPTR( local_cxy , &process->local_list ) ); | 
|---|
| 259 |  | 
|---|
| 260 |     // release the lock protecting the list of local process descriptors | 
|---|
| 261 |     remote_spinlock_unlock( XPTR( local_cxy , &pmgr->local_lock ) ); | 
|---|
| 262 |  | 
|---|
| 263 |     // get extended pointer on copies_lock in owner cluster manager | 
|---|
| 264 |     cxy_t  owner_cxy    = CXY_FROM_PID( process->pid ); | 
|---|
| 265 |         lpid_t lpid         = LPID_FROM_PID( process->pid ); | 
|---|
| 266 |     xptr_t copies_lock  = XPTR( owner_cxy , &pmgr->copies_lock[lpid] ); | 
|---|
| 267 |  | 
|---|
| 268 |     // remove the local process descriptor from copies_list | 
|---|
| 269 |     remote_spinlock_lock( copies_lock ); | 
|---|
| 270 |     xlist_unlink( XPTR( local_cxy , &process->copies_list ) ); | 
|---|
| 271 |     remote_spinlock_unlock( copies_lock ); | 
|---|
| 272 |  | 
|---|
| 273 |     // synchronize memory | 
|---|
| 274 |         hal_fence(); | 
|---|
| 275 |  | 
|---|
| 276 |     // From this point, the process descriptor is unreachable | 
|---|
| 277 |  | 
|---|
| 278 |     // close all open files and update dirty TODO [AG] | 
|---|
| 279 |  | 
|---|
| 280 |     // release signal manager TODO [AG] | 
|---|
| 281 |  | 
|---|
| 282 |     // Decrease refcount for bin file, root file and cwd file | 
|---|
| 283 |         if( process->vfs_bin_xp  != XPTR_NULL ) vfs_file_count_down( process->vfs_bin_xp ); | 
|---|
| 284 |         if( process->vfs_root_xp != XPTR_NULL ) vfs_file_count_down( process->vfs_root_xp ); | 
|---|
| 285 |         if( process->vfs_cwd_xp  != XPTR_NULL ) vfs_file_count_down( process->vfs_cwd_xp ); | 
|---|
| 286 |  | 
|---|
| 287 |     // Destroy VMM | 
|---|
| 288 |     vmm_destroy( process ); | 
|---|
| 289 |  | 
|---|
| 290 |         process_dmsg("\n[INFO] %s for pid %d / page_faults = %d\n", | 
|---|
| 291 |                  __FUNCTION__ , process->pid, process->vmm.pgfault_nr ); | 
|---|
| 292 | } | 
|---|
| 293 |  | 
|---|
| 294 | //////////////////////////////////////// | 
|---|
| 295 | void process_kill( process_t * process ) | 
|---|
| 296 | { | 
|---|
| 297 |     thread_t     * thread;    // pointer on current thead descriptor | 
|---|
| 298 |     uint32_t       ltid;      // index in process th_tbl | 
|---|
| 299 |     uint32_t       count;     // thread counter | 
|---|
| 300 |  | 
|---|
| 301 |     // get lock protecting th_tbl[] | 
|---|
| 302 |     spinlock_lock( &process->th_lock ); | 
|---|
| 303 |  | 
|---|
| 304 |     // first loop on threads to send the THREAD_SIG_KILL signal to all process threads | 
|---|
| 305 |     // we use both "ltid" and "count" indexes, because it can exist "holes" in th_tbl | 
|---|
| 306 |     for( ltid = 0 , count = 0  ; | 
|---|
| 307 |          (ltid < CONFIG_THREAD_MAX_PER_CLUSTER) && (count < process->th_nr) ; | 
|---|
| 308 |          ltid++ ) | 
|---|
| 309 |     { | 
|---|
| 310 |         thread = process->th_tbl[ltid]; | 
|---|
| 311 |  | 
|---|
| 312 |         if( thread != NULL ) | 
|---|
| 313 |         { | 
|---|
| 314 |             thread_kill( thread ); | 
|---|
| 315 |             count++; | 
|---|
| 316 |         } | 
|---|
| 317 |     } | 
|---|
| 318 |  | 
|---|
| 319 |     volatile uint32_t ko; | 
|---|
| 320 |  | 
|---|
| 321 |     // second loop on threads to wait acknowledge from scheduler, | 
|---|
| 322 |     // unlink thread from process and parent thread, and release thread descriptor | 
|---|
| 323 |     for( ltid = 0 , count = 0  ; | 
|---|
| 324 |          (ltid < CONFIG_THREAD_MAX_PER_CLUSTER) && (count < process->th_nr) ; | 
|---|
| 325 |          ltid++ ) | 
|---|
| 326 |     { | 
|---|
| 327 |         thread = process->th_tbl[ltid]; | 
|---|
| 328 |  | 
|---|
| 329 |         if( thread != NULL ) | 
|---|
| 330 |         { | 
|---|
| 331 |             // wait scheduler acknowledge | 
|---|
| 332 |             do { ko = (thread->signals & THREAD_SIG_KILL); } while( ko ); | 
|---|
| 333 |  | 
|---|
| 334 |             // unlink thread from brothers list if required | 
|---|
| 335 |             if( (thread->flags & THREAD_FLAG_DETACHED) == 0 ) | 
|---|
| 336 |             xlist_unlink( XPTR( local_cxy , &thread->brothers_list ) ); | 
|---|
| 337 |  | 
|---|
| 338 |             // unlink thread from process | 
|---|
| 339 |             process_remove_thread( thread ); | 
|---|
| 340 |  | 
|---|
| 341 |             // release memory for thread descriptor | 
|---|
| 342 |             thread_destroy( thread ); | 
|---|
| 343 |  | 
|---|
| 344 |             count++; | 
|---|
| 345 |         } | 
|---|
| 346 |     } | 
|---|
| 347 |  | 
|---|
| 348 |     // release lock protecting th_tbl[] | 
|---|
| 349 |     spinlock_unlock( &process->th_lock ); | 
|---|
| 350 |  | 
|---|
| 351 |     // release memory allocated for process descriptor | 
|---|
| 352 |     process_destroy( process ); | 
|---|
| 353 | } | 
|---|
| 354 |  | 
|---|
| 355 | /////////////////////////////////////////////// | 
|---|
| 356 | process_t * process_get_local_copy( pid_t pid ) | 
|---|
| 357 | { | 
|---|
| 358 |     error_t        error; | 
|---|
| 359 |     process_t    * process_ptr;   // local pointer on process | 
|---|
| 360 |     xptr_t         process_xp;    // extended pointer on process | 
|---|
| 361 |  | 
|---|
| 362 |     cluster_t * cluster = LOCAL_CLUSTER; | 
|---|
| 363 |  | 
|---|
| 364 |     // get lock protecting local list of processes | 
|---|
| 365 |     remote_spinlock_lock( XPTR( local_cxy , &cluster->pmgr.local_lock ) ); | 
|---|
| 366 |  | 
|---|
| 367 |     // scan the local list of process descriptors to find the process | 
|---|
| 368 |     xptr_t  iter; | 
|---|
| 369 |     bool_t  found = false; | 
|---|
| 370 |     XLIST_FOREACH( XPTR( local_cxy , &cluster->pmgr.local_root ) , iter ) | 
|---|
| 371 |     { | 
|---|
| 372 |         process_xp  = XLIST_ELEMENT( iter , process_t , local_list ); | 
|---|
| 373 |         process_ptr = (process_t *)GET_PTR( process_xp ); | 
|---|
| 374 |         if( process_ptr->pid == pid ) | 
|---|
| 375 |         { | 
|---|
| 376 |             found = true; | 
|---|
| 377 |             break; | 
|---|
| 378 |         } | 
|---|
| 379 |     } | 
|---|
| 380 |  | 
|---|
| 381 |     // release lock protecting local list of processes | 
|---|
| 382 |     remote_spinlock_unlock( XPTR( local_cxy , &cluster->pmgr.local_lock ) ); | 
|---|
| 383 |  | 
|---|
| 384 |     // allocate memory for a new local process descriptor | 
|---|
| 385 |     // and initialise it from reference cluster if required | 
|---|
| 386 |     if( !found ) | 
|---|
| 387 |     { | 
|---|
| 388 |         // get extended pointer on reference process descriptor | 
|---|
| 389 |         xptr_t ref_xp = cluster_get_reference_process_from_pid( pid ); | 
|---|
| 390 |  | 
|---|
| 391 |         assert( (ref_xp != XPTR_NULL) , __FUNCTION__ , "illegal pid\n" ); | 
|---|
| 392 |  | 
|---|
| 393 |         // allocate memory for local process descriptor | 
|---|
| 394 |         process_ptr = process_alloc(); | 
|---|
| 395 |         if( process_ptr == NULL )  return NULL; | 
|---|
| 396 |  | 
|---|
| 397 |         // initialize local process descriptor copy | 
|---|
| 398 |         error = process_copy_init( process_ptr , ref_xp ); | 
|---|
| 399 |         if( error ) return NULL; | 
|---|
| 400 |     } | 
|---|
| 401 |  | 
|---|
| 402 |     return process_ptr; | 
|---|
| 403 | } | 
|---|
| 404 |  | 
|---|
| 405 | ////////////////////////////////////////////////////////////////////////////////////////// | 
|---|
| 406 | // File descriptor array related functions | 
|---|
| 407 | ////////////////////////////////////////////////////////////////////////////////////////// | 
|---|
| 408 |  | 
|---|
| 409 | /////////////////////////////////////////// | 
|---|
| 410 | void process_fd_init( process_t * process ) | 
|---|
| 411 | { | 
|---|
| 412 |     uint32_t fd; | 
|---|
| 413 |  | 
|---|
| 414 |     remote_spinlock_init( XPTR( local_cxy , &process->fd_array.lock ) ); | 
|---|
| 415 |  | 
|---|
| 416 |     process->fd_array.current = 0; | 
|---|
| 417 |  | 
|---|
| 418 |     // initialize array | 
|---|
| 419 |     for ( fd = 0 ; fd < CONFIG_PROCESS_FILE_MAX_NR ; fd++ ) | 
|---|
| 420 |     { | 
|---|
| 421 |         process->fd_array.array[fd] = XPTR_NULL; | 
|---|
| 422 |     } | 
|---|
| 423 | } | 
|---|
| 424 |  | 
|---|
| 425 | ////////////////////////////// | 
|---|
| 426 | bool_t process_fd_array_full() | 
|---|
| 427 | { | 
|---|
| 428 |     // get extended pointer on reference process | 
|---|
| 429 |     xptr_t ref_xp = CURRENT_THREAD->process->ref_xp; | 
|---|
| 430 |  | 
|---|
| 431 |     // get reference process cluster and local pointer | 
|---|
| 432 |     process_t * ref_ptr = (process_t *)GET_PTR( ref_xp ); | 
|---|
| 433 |     cxy_t       ref_cxy = GET_CXY( ref_xp ); | 
|---|
| 434 |  | 
|---|
| 435 |     // get number of open file descriptors from reference fd_array | 
|---|
| 436 |     uint32_t current = hal_remote_lw( XPTR( ref_cxy , &ref_ptr->fd_array.current ) ); | 
|---|
| 437 |  | 
|---|
| 438 |         return ( current >= CONFIG_PROCESS_FILE_MAX_NR ); | 
|---|
| 439 | } | 
|---|
| 440 |  | 
|---|
| 441 | ///////////////////////////////////////////////// | 
|---|
| 442 | error_t process_fd_register(  xptr_t     file_xp, | 
|---|
| 443 |                               uint32_t * file_id ) | 
|---|
| 444 | { | 
|---|
| 445 |     bool_t    found; | 
|---|
| 446 |     uint32_t  id; | 
|---|
| 447 |     xptr_t    xp; | 
|---|
| 448 |  | 
|---|
| 449 |     // get extended pointer on reference process | 
|---|
| 450 |     xptr_t ref_xp = CURRENT_THREAD->process->ref_xp; | 
|---|
| 451 |  | 
|---|
| 452 |     // get reference process cluster and local pointer | 
|---|
| 453 |     process_t * ref_ptr = (process_t *)GET_PTR( ref_xp ); | 
|---|
| 454 |     cxy_t       ref_cxy = GET_CXY( ref_xp ); | 
|---|
| 455 |  | 
|---|
| 456 |     // take lock protecting reference fd_array | 
|---|
| 457 |         remote_spinlock_lock( XPTR( ref_cxy , &ref_ptr->fd_array.lock ) ); | 
|---|
| 458 |  | 
|---|
| 459 |     found   = false; | 
|---|
| 460 |  | 
|---|
| 461 |     for ( id = 0; id < CONFIG_PROCESS_FILE_MAX_NR ; id++ ) | 
|---|
| 462 |     { | 
|---|
| 463 |         xp = hal_remote_lwd( XPTR( ref_cxy , &ref_ptr->fd_array.array[id] ) ); | 
|---|
| 464 |         if ( xp == XPTR_NULL ) | 
|---|
| 465 |         { | 
|---|
| 466 |             found = true; | 
|---|
| 467 |             hal_remote_swd( XPTR( ref_cxy , &ref_ptr->fd_array.array[id] ) , file_xp ); | 
|---|
| 468 |                 hal_remote_atomic_add( XPTR( ref_cxy , &ref_ptr->fd_array.current ) , 1 ); | 
|---|
| 469 |                         *file_id = id; | 
|---|
| 470 |             break; | 
|---|
| 471 |         } | 
|---|
| 472 |     } | 
|---|
| 473 |  | 
|---|
| 474 |     // release lock protecting reference fd_array | 
|---|
| 475 |         remote_spinlock_unlock( XPTR( ref_cxy , &ref_ptr->fd_array.lock ) ); | 
|---|
| 476 |  | 
|---|
| 477 |     if ( !found ) return EMFILE; | 
|---|
| 478 |     else          return 0; | 
|---|
| 479 | } | 
|---|
| 480 |  | 
|---|
| 481 | //////////////////////////////////////////////// | 
|---|
| 482 | xptr_t process_fd_get_xptr( process_t * process, | 
|---|
| 483 |                             uint32_t    file_id ) | 
|---|
| 484 | { | 
|---|
| 485 |     xptr_t  file_xp; | 
|---|
| 486 |  | 
|---|
| 487 |     // access local copy of process descriptor | 
|---|
| 488 |     file_xp = process->fd_array.array[file_id]; | 
|---|
| 489 |  | 
|---|
| 490 |     if( file_xp == XPTR_NULL ) | 
|---|
| 491 |     { | 
|---|
| 492 |         // get reference process cluster and local pointer | 
|---|
| 493 |         xptr_t      ref_xp  = process->ref_xp; | 
|---|
| 494 |         cxy_t       ref_cxy = GET_CXY( ref_xp ); | 
|---|
| 495 |         process_t * ref_ptr = (process_t *)GET_PTR( ref_xp ); | 
|---|
| 496 |  | 
|---|
| 497 |         // access reference process descriptor | 
|---|
| 498 |         file_xp = hal_remote_lwd( XPTR( ref_cxy , &ref_ptr->fd_array.array[file_id] ) ); | 
|---|
| 499 |  | 
|---|
| 500 |         // update local fd_array if found | 
|---|
| 501 |         if( file_xp != XPTR_NULL ) | 
|---|
| 502 |         { | 
|---|
| 503 |             process->fd_array.array[file_id] = file_xp; | 
|---|
| 504 |         } | 
|---|
| 505 |     } | 
|---|
| 506 |  | 
|---|
| 507 |     return file_xp; | 
|---|
| 508 | } | 
|---|
| 509 |  | 
|---|
| 510 | /////////////////////////////////////////// | 
|---|
| 511 | void process_fd_remote_copy( xptr_t dst_xp, | 
|---|
| 512 |                              xptr_t src_xp ) | 
|---|
| 513 | { | 
|---|
| 514 |     uint32_t fd; | 
|---|
| 515 |     xptr_t   entry; | 
|---|
| 516 |  | 
|---|
| 517 |     // get cluster and local pointer for src fd_array | 
|---|
| 518 |     cxy_t        src_cxy = GET_CXY( src_xp ); | 
|---|
| 519 |     fd_array_t * src_ptr = (fd_array_t *)GET_PTR( src_xp ); | 
|---|
| 520 |  | 
|---|
| 521 |     // get cluster and local pointer for dst fd_array | 
|---|
| 522 |     cxy_t        dst_cxy = GET_CXY( dst_xp ); | 
|---|
| 523 |     fd_array_t * dst_ptr = (fd_array_t *)GET_PTR( dst_xp ); | 
|---|
| 524 |  | 
|---|
| 525 |     // get the remote lock protecting the src fd_array | 
|---|
| 526 |         remote_spinlock_lock( XPTR( src_cxy , &src_ptr->lock ) ); | 
|---|
| 527 |  | 
|---|
| 528 |     // loop on all entries in source process fd_array | 
|---|
| 529 |     for( fd = 0 ; fd < CONFIG_PROCESS_FILE_MAX_NR ; fd++ ) | 
|---|
| 530 |         { | 
|---|
| 531 |                 entry = (xptr_t)hal_remote_lwd( XPTR( src_cxy , &src_ptr->array[fd] ) ); | 
|---|
| 532 |  | 
|---|
| 533 |                 if( entry != XPTR_NULL ) | 
|---|
| 534 |                 { | 
|---|
| 535 |             // increment file descriptor ref count | 
|---|
| 536 |             vfs_file_count_up( entry ); | 
|---|
| 537 |  | 
|---|
| 538 |                         // copy entry in destination process fd_array | 
|---|
| 539 |                         hal_remote_swd( XPTR( dst_cxy , &dst_ptr->array[fd] ) , entry ); | 
|---|
| 540 |                 } | 
|---|
| 541 |         } | 
|---|
| 542 |  | 
|---|
| 543 |     // release lock on source process fd_array | 
|---|
| 544 |         remote_spinlock_unlock( XPTR( src_cxy , &src_ptr->lock ) ); | 
|---|
| 545 | } | 
|---|
| 546 |  | 
|---|
| 547 | //////////////////////////////////////////////////////////////////////////////////// | 
|---|
| 548 | //  Thread related functions | 
|---|
| 549 | //////////////////////////////////////////////////////////////////////////////////// | 
|---|
| 550 |  | 
|---|
| 551 | ///////////////////////////////////////////////////// | 
|---|
| 552 | error_t process_register_thread( process_t * process, | 
|---|
| 553 |                                  thread_t  * thread, | 
|---|
| 554 |                                  trdid_t   * trdid ) | 
|---|
| 555 | { | 
|---|
| 556 |     ltid_t   ltid; | 
|---|
| 557 |     bool_t   found; | 
|---|
| 558 |  | 
|---|
| 559 |     assert( (process != NULL) , __FUNCTION__ , "process argument is NULL" ); | 
|---|
| 560 |  | 
|---|
| 561 |     assert( (thread != NULL) , __FUNCTION__ , "thread argument is NULL" ); | 
|---|
| 562 |  | 
|---|
| 563 |     // search a free slot in th_tbl[] | 
|---|
| 564 |     found = false; | 
|---|
| 565 |     for( ltid = 0 ; ltid < CONFIG_THREAD_MAX_PER_CLUSTER ; ltid++ ) | 
|---|
| 566 |     { | 
|---|
| 567 |         if( process->th_tbl[ltid] == NULL ) | 
|---|
| 568 |         { | 
|---|
| 569 |             found = true; | 
|---|
| 570 |             break; | 
|---|
| 571 |         } | 
|---|
| 572 |     } | 
|---|
| 573 |  | 
|---|
| 574 |     if( found ) | 
|---|
| 575 |     { | 
|---|
| 576 |         // register thread in th_tbl[] | 
|---|
| 577 |         process->th_tbl[ltid] = thread; | 
|---|
| 578 |         process->th_nr++; | 
|---|
| 579 |  | 
|---|
| 580 |         // returns trdid | 
|---|
| 581 |         *trdid = TRDID( local_cxy , ltid ); | 
|---|
| 582 |     } | 
|---|
| 583 |  | 
|---|
| 584 |     return (found) ? 0 : ENOMEM; | 
|---|
| 585 |  | 
|---|
| 586 | }  // end process_register_thread() | 
|---|
| 587 |  | 
|---|
| 588 | /////////////////////////////////////////////// | 
|---|
| 589 | void process_remove_thread( thread_t * thread ) | 
|---|
| 590 | { | 
|---|
| 591 |     assert( (thread != NULL) , __FUNCTION__ , "thread argument is NULL" ); | 
|---|
| 592 |  | 
|---|
| 593 |     process_t * process = thread->process; | 
|---|
| 594 |  | 
|---|
| 595 |     // get thread local index | 
|---|
| 596 |     ltid_t  ltid = LTID_FROM_TRDID( thread->trdid ); | 
|---|
| 597 |  | 
|---|
| 598 |     // remove thread from th_tbl[] | 
|---|
| 599 |     process->th_tbl[ltid] = NULL; | 
|---|
| 600 |     process->th_nr--; | 
|---|
| 601 |  | 
|---|
| 602 | }  // process_remove_thread() | 
|---|
| 603 |  | 
|---|
| 604 | ///////////////////////////////////////////////////// | 
|---|
| 605 | error_t process_make_exec( exec_info_t  * exec_info ) | 
|---|
| 606 | { | 
|---|
| 607 |     char           * path;                            // pathname to .elf file | 
|---|
| 608 |     process_t      * process;                         // local pointer on new process | 
|---|
| 609 |     pid_t            pid;                             // new process pid | 
|---|
| 610 |     xptr_t           parent_xp;                       // extended pointer on parent process | 
|---|
| 611 |     cxy_t            parent_cxy; | 
|---|
| 612 |     process_t      * parent_ptr; | 
|---|
| 613 |     uint32_t         parent_pid; | 
|---|
| 614 |     thread_t       * thread;                          // pointer on new thread | 
|---|
| 615 |     pthread_attr_t   attr;                            // main thread attributes | 
|---|
| 616 |     core_t         * core;                            // pointer on selected core | 
|---|
| 617 |     lid_t            lid;                             // selected core local index | 
|---|
| 618 |         error_t          error; | 
|---|
| 619 |  | 
|---|
| 620 |         // get parent and .elf pathname from exec_info | 
|---|
| 621 |         path      = exec_info->path; | 
|---|
| 622 |     parent_xp = exec_info->parent_xp; | 
|---|
| 623 |  | 
|---|
| 624 |     // get parent process cluster and local pointer | 
|---|
| 625 |     parent_cxy = GET_CXY( parent_xp ); | 
|---|
| 626 |     parent_ptr = (process_t *)GET_PTR( parent_xp ); | 
|---|
| 627 |     parent_pid = hal_remote_lw( XPTR( parent_cxy , &parent_ptr->pid ) ); | 
|---|
| 628 |  | 
|---|
| 629 |     exec_dmsg("\n[INFO] %s : thread %x on core[%x,‰d] enters for path = %s\n", | 
|---|
| 630 |     __FUNCTION__, CURRENT_THREAD->trdid, local_cxy, CURRENT_THREAD->core->lid, path ); | 
|---|
| 631 |  | 
|---|
| 632 |     // create new process descriptor | 
|---|
| 633 |     process = process_alloc(); | 
|---|
| 634 |  | 
|---|
| 635 |     if( process == NULL ) | 
|---|
| 636 |     { | 
|---|
| 637 |         printk("\n[ERROR] in %s : no memory / cluster = %x / ppid = %x / path = %s\n", | 
|---|
| 638 |                __FUNCTION__ , local_cxy , parent_pid , path ); | 
|---|
| 639 |         return ENOMEM; | 
|---|
| 640 |     } | 
|---|
| 641 |  | 
|---|
| 642 |     // get a pid from the local cluster | 
|---|
| 643 |     error = cluster_pid_alloc( XPTR( local_cxy , process ) , &pid ); | 
|---|
| 644 |  | 
|---|
| 645 |     if( error ) | 
|---|
| 646 |     { | 
|---|
| 647 |         printk("\n[ERROR] in %s : cannot get PID / cluster = %x / ppid = %x / path = %s\n", | 
|---|
| 648 |                __FUNCTION__ , local_cxy , parent_pid , path ); | 
|---|
| 649 |         process_free( process ); | 
|---|
| 650 |                 return ENOMEM; | 
|---|
| 651 |     } | 
|---|
| 652 |  | 
|---|
| 653 |     // initialize the process descriptor as the reference | 
|---|
| 654 |     process_reference_init( process , pid , parent_xp ); | 
|---|
| 655 |  | 
|---|
| 656 |     exec_dmsg("\n[INFO] %s : thread %x on core[%x,‰d] created process %x / path = %s\n", | 
|---|
| 657 |     __FUNCTION__, CURRENT_THREAD->trdid, local_cxy, CURRENT_THREAD->core->lid, pid, path ); | 
|---|
| 658 |  | 
|---|
| 659 |     // initialize vfs_root and vfs_cwd from parent process | 
|---|
| 660 |     xptr_t  vfs_root_xp = hal_remote_lwd( XPTR( parent_cxy , &parent_ptr->vfs_root_xp ) ); | 
|---|
| 661 |         vfs_file_count_up( vfs_root_xp ); | 
|---|
| 662 |         process->vfs_root_xp = vfs_root_xp; | 
|---|
| 663 |  | 
|---|
| 664 |     xptr_t  vfs_cwd_xp = hal_remote_lwd( XPTR( parent_cxy , &parent_ptr->vfs_cwd_xp ) ); | 
|---|
| 665 |         vfs_file_count_up( vfs_cwd_xp ); | 
|---|
| 666 |         process->vfs_cwd_xp = vfs_cwd_xp; | 
|---|
| 667 |  | 
|---|
| 668 |     // initialize embedded fd_array from parent process | 
|---|
| 669 |     process_fd_remote_copy( XPTR( local_cxy  , &process->fd_array ), | 
|---|
| 670 |                             XPTR( parent_cxy , &parent_ptr->fd_array) ); | 
|---|
| 671 |  | 
|---|
| 672 |     exec_dmsg("\n[INFO] %s : fd_array copied from process %x to process %x\n", | 
|---|
| 673 |     __FUNCTION__, parent_pid , pid ); | 
|---|
| 674 |  | 
|---|
| 675 |         // initialize signal manager TODO ??? [AG] | 
|---|
| 676 |         // signal_manager_init( process ); | 
|---|
| 677 |  | 
|---|
| 678 |     // register "code" and "data" vsegs as well as the process entry-point in VMM, | 
|---|
| 679 |     // using information contained in the elf file. | 
|---|
| 680 |         error = elf_load_process( path , process ); | 
|---|
| 681 |  | 
|---|
| 682 |         if( error ) | 
|---|
| 683 |         { | 
|---|
| 684 |                 printk("\n[ERROR] in %s : failed to access elf file for process %x / path = %s\n", | 
|---|
| 685 |                        __FUNCTION__, pid , path ); | 
|---|
| 686 |         process_destroy( process ); | 
|---|
| 687 |         return error; | 
|---|
| 688 |         } | 
|---|
| 689 |  | 
|---|
| 690 |     exec_dmsg("\n[INFO] %s : code and data vsegs registered for process %x / path = %s\n", | 
|---|
| 691 |     __FUNCTION__ , pid , path ); | 
|---|
| 692 |  | 
|---|
| 693 |     // select a core in cluster | 
|---|
| 694 |     lid  = cluster_select_local_core(); | 
|---|
| 695 |     core = &LOCAL_CLUSTER->core_tbl[lid]; | 
|---|
| 696 |  | 
|---|
| 697 |     // initialize pthread attributes for main thread | 
|---|
| 698 |     attr.attributes = PT_ATTR_DETACH | PT_ATTR_CLUSTER_DEFINED | PT_ATTR_CORE_DEFINED; | 
|---|
| 699 |     attr.cxy        = local_cxy; | 
|---|
| 700 |     attr.lid        = lid; | 
|---|
| 701 |  | 
|---|
| 702 |     // create and initialize thread descriptor | 
|---|
| 703 |         error = thread_user_create( pid, | 
|---|
| 704 |                                 (void *)process->vmm.entry_point, | 
|---|
| 705 |                                 exec_info->args_pointers, | 
|---|
| 706 |                                 &attr, | 
|---|
| 707 |                                 &thread ); | 
|---|
| 708 |         if( error ) | 
|---|
| 709 |         { | 
|---|
| 710 |                 printk("\n[ERROR] in %s : cannot create thread for process %x / path = %s\n", | 
|---|
| 711 |                        __FUNCTION__, pid ); | 
|---|
| 712 |         process_destroy( process ); | 
|---|
| 713 |         return error; | 
|---|
| 714 |         } | 
|---|
| 715 |  | 
|---|
| 716 |         exec_dmsg("\n[INFO] %s : thread created for process %x on core %d in cluster %x\n", | 
|---|
| 717 |                __FUNCTION__ , pid , core->lid , local_cxy ); | 
|---|
| 718 |  | 
|---|
| 719 |     // update children list in parent process | 
|---|
| 720 |         xlist_add_last( XPTR( parent_cxy , &parent_ptr->children_root ), | 
|---|
| 721 |                     XPTR( local_cxy  , &process->brothers_list ) ); | 
|---|
| 722 |         hal_remote_atomic_add( XPTR( parent_cxy , &parent_ptr->children_nr) , 1 ); | 
|---|
| 723 |  | 
|---|
| 724 |     // activate new thread | 
|---|
| 725 |         thread_unblock( XPTR( local_cxy , thread ) , THREAD_BLOCKED_GLOBAL ); | 
|---|
| 726 |  | 
|---|
| 727 |     exec_dmsg("\n[INFO] %s : exit for process %x\n", | 
|---|
| 728 |                 __FUNCTION__, process->pid ); | 
|---|
| 729 |  | 
|---|
| 730 |         return 0; | 
|---|
| 731 |  | 
|---|
| 732 | }  // end proces_make_exec() | 
|---|
| 733 |  | 
|---|
| 734 | ////////////////////////// | 
|---|
| 735 | void process_init_create() | 
|---|
| 736 | { | 
|---|
| 737 |     exec_info_t   exec_info;     // structure to be passed to process_make_exec() | 
|---|
| 738 |  | 
|---|
| 739 |         error_t   error1; | 
|---|
| 740 |         error_t   error2; | 
|---|
| 741 |         error_t   error3; | 
|---|
| 742 |     xptr_t    stdin_xp; | 
|---|
| 743 |     xptr_t    stdout_xp; | 
|---|
| 744 |     xptr_t    stderr_xp; | 
|---|
| 745 |     uint32_t  stdin_id; | 
|---|
| 746 |     uint32_t  stdout_id; | 
|---|
| 747 |     uint32_t  stderr_id; | 
|---|
| 748 |  | 
|---|
| 749 |         process_dmsg("\n[INFO] %s : enters in cluster %x\n", __FUNCTION__ , local_cxy ); | 
|---|
| 750 |  | 
|---|
| 751 |     // open stdin / stdout / stderr pseudo-files | 
|---|
| 752 |         error1 = vfs_open( XPTR_NULL, CONFIG_DEV_STDIN , O_RDONLY, 0, &stdin_xp , &stdin_id  ); | 
|---|
| 753 |         error2 = vfs_open( XPTR_NULL, CONFIG_DEV_STDOUT, O_WRONLY, 0, &stdout_xp, &stdout_id ); | 
|---|
| 754 |         error3 = vfs_open( XPTR_NULL, CONFIG_DEV_STDERR, O_WRONLY, 0, &stderr_xp, &stderr_id ); | 
|---|
| 755 |  | 
|---|
| 756 |         assert( ((error1 == 0) && (error2 == 0) && (error3 == 0)) , __FUNCTION__ , | 
|---|
| 757 |             "cannot open stdin/stdout/stderr pseudo files\n"); | 
|---|
| 758 |  | 
|---|
| 759 |     assert( ((stdin_id == 0) && (stdout_id == 1) && (stderr_id == 2)) , __FUNCTION__ , | 
|---|
| 760 |             "bad indexes for stdin/stdout/stderr\n"); | 
|---|
| 761 |  | 
|---|
| 762 |     // initialize the exec_info structure | 
|---|
| 763 |     exec_info.parent_xp    = XPTR( local_cxy , &process_zero ); | 
|---|
| 764 |     strcpy( exec_info.path , CONFIG_PROCESS_INIT_PATH ); | 
|---|
| 765 |     exec_info.args_nr      = 0; | 
|---|
| 766 |     exec_info.envs_nr      = 0; | 
|---|
| 767 |  | 
|---|
| 768 |     // create process_init and thread_init | 
|---|
| 769 |         error1 = process_make_exec( &exec_info ); | 
|---|
| 770 |  | 
|---|
| 771 |         assert( (error1 == 0) , __FUNCTION__ , "cannot create process_init\n"); | 
|---|
| 772 |  | 
|---|
| 773 |         process_dmsg("\n[INFO] %s : exit in cluster %x\n", __FUNCTION__ , local_cxy ); | 
|---|
| 774 |                  | 
|---|
| 775 |     hal_fence(); | 
|---|
| 776 |  | 
|---|
| 777 | }  // end process_init_create() | 
|---|
| 778 |  | 
|---|