1/* 2 * Copyright 2016, Data61 3 * Commonwealth Scientific and Industrial Research Organisation (CSIRO) 4 * ABN 41 687 119 230. 5 * 6 * This software may be distributed and modified according to the terms of 7 * the BSD 2-Clause license. Note that NO WARRANTY is provided. 8 * See "LICENSE_BSD2.txt" for details. 9 * 10 * @TAG(D61_BSD) 11 */ 12 13#include <stdio.h> 14#include <stdlib.h> 15#include <string.h> 16#include <assert.h> 17#include <autoconf.h> 18#include <sel4utils/elf.h> 19#include <refos/vmlayout.h> 20#include <refos/refos.h> 21#include <refos-rpc/proc_server.h> 22#include <sel4utils/process.h> 23 24#include "../../state.h" 25#include "pid.h" 26#include "process.h" 27#include "thread.h" 28#include "proc_client_watch.h" 29#include <refos/refos.h> 30 31/*! @file 32 @brief Process management module for process server. */ 33 34/* ------------------------------ Proc Helper functions ------------------------------------------*/ 35 36static int 37proc_staticparam_create_and_set(struct proc_pcb *p, char *param) 38{ 39 assert(p && param); 40 size_t paramLen = strlen(param); 41 assert(paramLen <= PROCESS_STATICPARAM_SIZE && paramLen <= REFOS_PAGE_SIZE); 42 struct vs_vspace *vs = &p->vspace; 43 int error = EINVALID; 44 45 /* Allocate the frame to map. */ 46 vka_object_t frame; 47 error = vka_alloc_frame(&procServ.vka, seL4_PageBits, &frame); 48 if (error != ESUCCESS || !frame.cptr) { 49 ROS_ERROR("Could not allocate frame kobj. Procserv out of memory."); 50 return ENOMEM; 51 } 52 53 /* Write param data to frame. */ 54 error = procserv_frame_write(frame.cptr, param, paramLen, 0); 55 if (error) { 56 ROS_ERROR("Could not write to param frame."); 57 error = ENOMEM; 58 goto exit0; 59 } 60 61 /* Create the static parameter window. */ 62 int windowID = W_INVALID_WINID; 63 error = vs_create_window(vs, PROCESS_STATICPARAM_ADDR, PROCESS_STATICPARAM_SIZE, 64 W_PERMISSION_WRITE | W_PERMISSION_READ, true, &windowID); 65 if (error) { 66 ROS_ERROR("Could not create static param window."); 67 goto exit0; 68 } 69 70 /* Map the static parameter window. */ 71 error = vs_map(vs, PROCESS_STATICPARAM_ADDR, &frame.cptr, 1); 72 if (error) { 73 ROS_ERROR("Could not map static param window."); 74 goto exit1; 75 } 76 77 return ESUCCESS; 78 79 /* Exit stack. */ 80exit1: 81 if (windowID != W_INVALID_WINID) { 82 vs_delete_window(vs, windowID); 83 } 84exit0: 85 vka_free_object(&procServ.vka, &frame); 86 return error; 87} 88 89static void 90proc_pass_badge(struct proc_pcb *p, seL4_CPtr destCSlot, seL4_CPtr ep, seL4_CapRights_t rights, 91 seL4_CapData_t badge) 92{ 93 cspacepath_t pathSrc, pathDest; 94 vka_cspace_make_path(&procServ.vka, ep, &pathSrc); 95 96 pathDest.root = p->vspace.cspace.capPtr; 97 pathDest.capPtr = destCSlot; 98 pathDest.capDepth = seL4_WordBits; 99 100 /* Mint a badged endpoint into the client's vspace. */ 101 int error = vka_cnode_mint(&pathDest, &pathSrc, seL4_AllRights, badge); 102 if (error) { 103 dprintf("WARNING: proc_pass_badge to dest cslot %d failed.\n", destCSlot); 104 assert(!"proc_pass_badge failed to pass badge."); 105 } 106} 107 108static void 109proc_copy_badge(struct proc_pcb *p, seL4_CPtr destCSlot, seL4_CPtr ep, seL4_CapRights_t rights) 110{ 111 cspacepath_t pathSrc, pathDest; 112 vka_cspace_make_path(&procServ.vka, ep, &pathSrc); 113 114 pathDest.root = p->vspace.cspace.capPtr; 115 pathDest.capPtr = destCSlot; 116 pathDest.capDepth = seL4_WordBits; 117 118 /* Move an object into the client's vspace. */ 119 int error = vka_cnode_copy(&pathDest, &pathSrc, rights); 120 if (error) { 121 dprintf("WARNING: proc_copy_badge to dest cslot %d failed.\n", destCSlot); 122 assert(!"proc_copy_badge failed to pass badge."); 123 } 124} 125 126static void 127proc_setup_environment(struct proc_pcb *p, char *param) 128{ 129 assert(p); 130 131 /* Pass the process its static parameter contents. */ 132 proc_staticparam_create_and_set(p, param); 133 134 /* Tell the process about ourself, the process server. */ 135 proc_pass_badge ( 136 p, REFOS_PROCSERV_EP, procServ.endpoint.cptr, 137 seL4_NoRead, 138 seL4_CapData_Badge_new(pid_get_badge(p->pid)) 139 ); 140 141 /* Tell the process about its own liveness cap. */ 142 proc_pass_badge ( 143 p, REFOS_LIVENESS, procServ.endpoint.cptr, 144 seL4_NoRead, 145 seL4_CapData_Badge_new(pid_get_liveness_badge(p->pid)) 146 ); 147 148 /* Tell the process about its initial thread. */ 149 struct proc_tcb *t0 = proc_get_thread(p, 0); 150 assert(t0); 151 proc_pass_badge ( 152 p, REFOS_THREAD_TCB, thread_tcb_obj(t0), seL4_AllRights, 153 seL4_CapData_Badge_new(0) 154 ); 155 156 #if defined(PLAT_PC99) 157 /* Give any process with IO port permission to read / write to IO ports. */ 158 if (p->systemCapabilitiesMask & PROCESS_PERMISSION_DEVICE_IOPORT) { 159 proc_copy_badge ( 160 p, REFOS_DEVICE_IO_PORTS, seL4_CapIOPort, seL4_AllRights 161 ); 162 } 163 #else 164 (void) proc_copy_badge; 165 #endif 166} 167 168static void 169proc_purge_pid_callback(struct proc_pcb *pcb, void *cookie) 170{ 171 uint32_t deathPID = (int) cookie; 172 assert(pcb && pcb->magic == REFOS_PCB_MAGIC); 173 if (pcb->pid == deathPID) { 174 return; 175 } 176 177 /* Orphan the child PID. */ 178 if (pcb->parentPID == deathPID) { 179 pcb->parentPID = PID_NULL; 180 pcb->parentWaiting = false; 181 } 182} 183 184/* ----------------------------- Proc interface functions ----------------------------------------*/ 185 186int 187proc_config_new(struct proc_pcb *p, uint32_t pid, uint8_t priority, char *imageName, 188 uint32_t systemCapabilitiesMask) 189{ 190 assert(p); 191 if (!imageName) { 192 return EINVALIDPARAM; 193 } 194 memset(p, 0, sizeof(struct proc_pcb)); 195 int error = EINVALID; 196 197 /* Set initial info. */ 198 p->magic = REFOS_PCB_MAGIC; 199 p->systemCapabilitiesMask = systemCapabilitiesMask; 200 p->pid = pid; 201 p->paramBuffer = NULL; 202 p->notificationBuffer = NULL; 203 204 /* Allocate a vspace. */ 205 dvprintf("Initialising vspace for %s...\n", imageName); 206 error = vs_initialise(&p->vspace, pid); 207 if (error != ESUCCESS) { 208 dprintf("Failed vspace allocation.\n"); 209 goto exit0; 210 } 211 212 /* Create thread. */ 213 dvprintf("Allocating thread structure for %s...\n", imageName); 214 cvector_init(&p->threads); 215 struct proc_tcb *thread = kmalloc(sizeof(struct proc_tcb)); 216 if (!thread) { 217 ROS_ERROR("Failed to malloc thread structure.\n"); 218 error = ENOMEM; 219 goto exit1; 220 } 221 222 /* Load ELF image from CPIO archive. */ 223 dvprintf("Loading ELF file %s...\n", imageName); 224 void *entryPoint = sel4utils_elf_load ( 225 &p->vspace.vspace, &procServ.vspace, &procServ.vka, 226 &procServ.vka, imageName 227 ); 228 if (entryPoint == NULL) { 229 ROS_ERROR("Failed to load ELF file %s.", imageName); 230 error = EINVALIDPARAM; 231 goto exit2; 232 } 233 234 uintptr_t sysInfo = sel4utils_elf_get_vsyscall(imageName); 235 236 /* Configure initial thread. Note that we do this after loading the ELF into vspace, to 237 avoid potentially clobbering the vspace ELF regions. */ 238 error = thread_config(thread, priority, (vaddr_t) entryPoint, &p->vspace); 239 if (error) { 240 ROS_ERROR("Failed to configure thread for %s.", imageName); 241 goto exit2; 242 } 243 244 /* Future Work 1: 245 How the process server creates and starts new processes and threads should be modified. 246 Currently the process server creates new processes by creating a 'dummy' 247 sel4utils_process_t structure and then making a call to sel4utils_spawn_process_v() 248 with the sel4utils_process_t structure. The existing vspace, sel4utilsThread and entryPoint 249 are copied into the sel4utils_process_t structure. Instead of using sel4utils_process_t the 250 conventional way, RefOS implements its own structure for managing processes and threads. The 251 RefOS defined proc_pcb structure performs overall the same functionality as the (now existing) 252 sel4utils_process_t which most seL4 projects rely on. Further RefOS work is to modify RefOS 253 so that it does not use its proc_pcb structure and instead uses the sel4utils_process_t structure 254 entirely. 255 */ 256 sel4utils_process_t n_process; 257 n_process.vspace = p->vspace.vspace; 258 n_process.thread = thread->sel4utilsThread; 259 n_process.sysinfo = sysInfo; 260 n_process.entry_point = entryPoint; 261 262 error = sel4utils_spawn_process_v(&n_process, &procServ.vka, &procServ.vspace, 0, NULL, 0); 263 if (error) { 264 ROS_ERROR("Failed to spawn process for %s.", imageName); 265 goto exit2; 266 } 267 268 thread->sel4utilsThread = n_process.thread; 269 270 /* Add thread to list. */ 271 dvprintf("Adding to threads list...\n"); 272 cvector_add(&p->threads, (cvector_item_t) thread); 273 assert(cvector_count(&p->threads) == 1); 274 275 /* Initialise miscellaneous process state. */ 276 client_watch_init(&p->clientWatchList); 277 strcpy(p->debugProcessName, imageName); 278 279 return ESUCCESS; 280 281 /* Exit stack. */ 282exit2: 283 kfree(thread); 284exit1: 285 vs_unref(&p->vspace); 286exit0: 287 memset(p, 0, sizeof(struct proc_pcb)); 288 return error; 289} 290 291int 292proc_start_thread(struct proc_pcb *p, int tindex, void* arg0, void* arg1) 293{ 294 dvprintf("Starting PID %d thread %d!!!\n", p->pid, tindex); 295 assert(cvector_count(&p->threads) >= 1); 296 struct proc_tcb *t = (struct proc_tcb *) cvector_get(&p->threads, tindex); 297 assert(t); 298 assert(t->entryPoint); 299 return thread_start(t, arg0, arg1); 300} 301 302int 303proc_load_direct(char *name, int priority, char *param, unsigned int parentPID, 304 uint32_t systemCapabilitiesMask) 305{ 306 /* Allocate a PID. */ 307 dprintf("Allocating PID and PCB...\n"); 308 uint32_t npid = pid_alloc(&procServ.PIDList); 309 if (npid == PID_NULL) { 310 dprintf("Failed PID allocation.\n"); 311 return ENOMEM; 312 } 313 dprintf("Allocated PID %d!...\n", npid); 314 struct proc_pcb *pcb = pid_get_pcb(&procServ.PIDList, npid); 315 assert(pcb); 316 317 /* Configure the process. */ 318 dprintf("Configuring process for PID %d!...\n", npid); 319 int error = proc_config_new(pcb, npid, priority, name, systemCapabilitiesMask); 320 if (error != ESUCCESS) { 321 pid_free(&procServ.PIDList, npid); 322 return error; 323 } 324 pcb->parentPID = parentPID; 325 326 /* If we are selfloading this process, then the actual image name is in the param string. 327 This is a bit of a hacky way, but the debug name is only used for debugging so its not too 328 bad. */ 329 if (!strcmp(name, "selfloader")) { 330 strcpy(pcb->debugProcessName, param); 331 } 332 333 /* Configure the process' vspace and cspace for the RefOS userland environment. */ 334 proc_setup_environment(pcb, param); 335 336 /* Start the initial thread (thread 0). */ 337 error = proc_start_thread(pcb, 0, NULL, NULL); 338 if (error) { 339 ROS_ERROR("Could not start thread 0!"); 340 pid_free(&procServ.PIDList, npid); 341 return error; 342 } 343 344 return ESUCCESS; 345} 346 347int 348proc_nice(struct proc_pcb *p, int tindex, int priority) 349{ 350 assert(cvector_count(&p->threads) >= 1); 351 struct proc_tcb *t = (struct proc_tcb *) cvector_get(&p->threads, tindex); 352 if (!t) { 353 ROS_WARNING("proc_nice warning: no such thread %d!", tindex); 354 return EINVALIDPARAM; 355 } 356 assert(thread_tcb_obj(t)); 357 int error = seL4_TCB_SetPriority(thread_tcb_obj(t), priority); 358 if (error) { 359 ROS_ERROR("proc_nice failed to set TCB priority."); 360 return EINVALID; 361 } 362 t->priority = priority; 363 return ESUCCESS; 364} 365 366static void proc_parent_reply(struct proc_pcb *p); 367 368void 369proc_release(struct proc_pcb *p) 370{ 371 assert(p && p->magic == REFOS_PCB_MAGIC); 372 memset(&p->rpcClient, 0, sizeof(rpc_client_state_t)); 373 374 /* For anybody that's watching us, they've got to be notified, and then unwatched. */ 375 pid_iterate(&procServ.PIDList, client_watch_notify_death_callback, (void*) p->pid); 376 377 /* For any children PID under us, they are now orphaned. */ 378 dvprintf(" orphaning children...\n"); 379 pid_iterate(&procServ.PIDList, proc_purge_pid_callback, (void*) p->pid); 380 381 /* If there's potentially a process waiting for us to exit, then notify that process. */ 382 dvprintf(" replying parent...\n"); 383 if (p->parentPID != PID_NULL) { 384 proc_parent_reply(p); 385 } 386 387 /* Unreference the parameter buffer. */ 388 dvprintf(" unreffing parameter buffer...\n"); 389 if (p->paramBuffer) { 390 ram_dspace_unref(p->paramBuffer->parentList, p->paramBuffer->ID); 391 p->paramBuffer = NULL; 392 } 393 394 /* Release notification buffer. */ 395 dvprintf(" releasing notification buffer...\n"); 396 if (p->notificationBuffer) { 397 rb_delete(p->notificationBuffer); 398 p->notificationBuffer = NULL; 399 } 400 401 /* Release fault reply cap. */ 402 dvprintf(" releasing caller EP...\n"); 403 if (p->faultReply.capPtr) { 404 vka_cnode_delete(&p->faultReply); 405 vka_cspace_free(&procServ.vka, p->faultReply.capPtr); 406 p->faultReply.capPtr = 0; 407 } 408 409 /* Unreference vspace. */ 410 dvprintf(" Unref vspace...\n"); 411 vs_unref(&p->vspace); 412 413 /* Clean up threads. */ 414 dvprintf(" Cleaning up threads...\n"); 415 int nthreads = cvector_count(&p->threads); 416 for (int i = 0; i < nthreads; i++) { 417 dvprintf(" Cleaning up thread %d...\n", i); 418 struct proc_tcb *thread = (struct proc_tcb *) cvector_get(&p->threads, i); 419 assert(thread && thread->magic == REFOS_PROCESS_THREAD_MAGIC); 420 thread_release(thread); 421 kfree(thread); 422 } 423 cvector_free(&p->threads); 424 425 dvprintf(" process released OK.\n"); 426 p->magic = 0; 427 p->pid = 0; 428 p->systemCapabilitiesMask = 0x0; 429} 430 431void 432proc_queue_release(struct proc_pcb *p) 433{ 434 assert(p && p->magic == REFOS_PCB_MAGIC); 435 assert(procServ.exitProcessPID == PID_NULL); 436 procServ.exitProcessPID = p->pid; 437} 438 439/* ------------------------------- Proc interface helper functions ------------------------------ */ 440 441void 442proc_set_parambuffer(struct proc_pcb *p, struct ram_dspace *paramBuffer) 443{ 444 assert(p && p->magic == REFOS_PCB_MAGIC); 445 if (p->paramBuffer == paramBuffer) { 446 /* Same parameter buffer, nothing to do here. */ 447 return; 448 } else if (p->paramBuffer != NULL) { 449 /* We need to undeference the previous parameter buffer. */ 450 ram_dspace_unref(p->paramBuffer->parentList, p->paramBuffer->ID); 451 p->paramBuffer = NULL; 452 } 453 if (paramBuffer != NULL) { 454 /* Now reference the new parameter buffer. */ 455 ram_dspace_ref(paramBuffer->parentList, paramBuffer->ID); 456 } 457 p->paramBuffer = paramBuffer; 458} 459 460int 461proc_set_notificationbuffer(struct proc_pcb *p, struct ram_dspace *notifBuffer) 462{ 463 /* Release old notification buffer. */ 464 if (p->notificationBuffer) { 465 rb_delete(p->notificationBuffer); 466 p->notificationBuffer = NULL; 467 } 468 if (!notifBuffer) { 469 return ESUCCESS; 470 } 471 p->notificationBuffer = rb_create(notifBuffer, RB_WRITEONLY); 472 if (!p->notificationBuffer) { 473 ROS_ERROR("Could not create notification buffer"); 474 return ENOMEM; 475 } 476 return ESUCCESS; 477} 478 479void 480proc_dspace_delete_callback(struct proc_pcb *p, void *cookie) 481{ 482 assert(p && p->magic == REFOS_PCB_MAGIC); 483 struct ram_dspace *dspace = (struct ram_dspace *) cookie; 484 assert(dspace && dspace->magic == RAM_DATASPACE_MAGIC); 485 486 if (p->paramBuffer) { 487 if (p->paramBuffer == dspace || (p->paramBuffer->parentList == dspace->parentList && 488 p->paramBuffer->ID == dspace->ID)) { 489 /* The process's parameter buffer just got deleted. Unset the process's parambuffer. */ 490 proc_set_parambuffer(p, NULL); 491 assert(p->paramBuffer == NULL); 492 } 493 } 494 495 if (p->notificationBuffer) { 496 if (p->notificationBuffer->dataspace == dspace || 497 (p->notificationBuffer->dataspace->parentList == dspace->parentList && 498 p->notificationBuffer->dataspace->ID == dspace->ID) ) { 499 rb_delete(p->notificationBuffer); 500 p->notificationBuffer = NULL; 501 } 502 } 503 504} 505 506struct proc_tcb * 507proc_get_thread(struct proc_pcb *p, int tindex) 508{ 509 assert(p && p->magic == REFOS_PCB_MAGIC); 510 if (tindex >= cvector_count(&p->threads)) { 511 return NULL; 512 } 513 struct proc_tcb *t = (struct proc_tcb *) cvector_get(&p->threads, tindex); 514 assert(t && t->magic == REFOS_PROCESS_THREAD_MAGIC); 515 assert(t->entryPoint); 516 return t; 517} 518 519int 520proc_save_caller(struct proc_pcb *p) 521{ 522 assert(p && p->magic == REFOS_PCB_MAGIC); 523 524 /* Release any previous fault reply cap. */ 525 if (p->faultReply.capPtr) { 526 vka_cnode_delete(&p->faultReply); 527 vka_cspace_free(&procServ.vka, p->faultReply.capPtr); 528 p->faultReply.capPtr = 0; 529 } 530 531 /* Allocate the cslot for reply cap to be saved to. */ 532 int error = vka_cspace_alloc_path(&procServ.vka, &p->faultReply); 533 if (error != seL4_NoError) { 534 ROS_ERROR("Could not allocate path to save caller. PRocserv outof cslots."); 535 return ENOMEM; 536 } 537 assert(p->faultReply.capPtr); 538 539 /* Save the caller cap. */ 540 error = vka_cnode_saveCaller(&p->faultReply); 541 if (error != seL4_NoError) { 542 ROS_ERROR("Could not copy out reply cap."); 543 return EINVALID; 544 } 545 546 return ESUCCESS; 547} 548 549int 550proc_clone(struct proc_pcb *p, int *threadID, vaddr_t stackAddr, vaddr_t entryPoint) 551{ 552 assert(p && p->magic == REFOS_PCB_MAGIC); 553 if (threadID) { 554 (*threadID) = -1; 555 } 556 557 /* No support for fork() behaviour. */ 558 if (!stackAddr || !entryPoint) { 559 return EINVALIDPARAM; 560 } 561 562 /* Get the main thread of process to read its priority. */ 563 struct proc_tcb * t = proc_get_thread(p, 0); 564 if (!t) { 565 ROS_ERROR("Failed to retrieve main thread.\n"); 566 return EINVALID; 567 } 568 569 /* Create the TCB struct for the clone thread. */ 570 dvprintf("Allocating thread structure...\n"); 571 struct proc_tcb *thread = kmalloc(sizeof(struct proc_tcb)); 572 if (!thread) { 573 ROS_ERROR("Failed to malloc thread structure.\n"); 574 return ENOMEM; 575 } 576 577 /* Configure new thread, sharing the process's address space */ 578 int error = thread_config(thread, t->priority, (vaddr_t) entryPoint, &p->vspace); 579 if (error) { 580 ROS_ERROR("Failed to configure thread for new thread."); 581 goto exit1; 582 } 583 584 /* Future Work 1: 585 How the process server creates and starts new processes and threads should be modified. 586 Currently the process server creates new processes by creating a 'dummy' 587 sel4utils_process_t structure and then making a call to sel4utils_spawn_process_v() 588 with the sel4utils_process_t structure. The existing vspace, sel4utilsThread and entryPoint 589 are copied into the sel4utils_process_t structure. Instead of using sel4utils_process_t the 590 conventional way, RefOS implements its own structure for managing processes and threads. The 591 RefOS defined proc_pcb structure performs overall the same functionality as the (now existing) 592 sel4utils_process_t which most seL4 projects rely on. Further RefOS work is to modify RefOS 593 so that it does not use its proc_pcb structure and instead uses the sel4utils_process_t structure 594 entirely. 595 */ 596 sel4utils_process_t n_process; 597 n_process.vspace = p->vspace.vspace; 598 n_process.thread = thread->sel4utilsThread; 599 n_process.sysinfo = 0; 600 n_process.entry_point = (void *) entryPoint; 601 602 error = sel4utils_spawn_process_v(&n_process, &procServ.vka, &procServ.vspace, 0, NULL, 0); 603 if (error) { 604 ROS_ERROR("Failed to spawn process."); 605 goto exit1; 606 } 607 608 thread->sel4utilsThread = n_process.thread; 609 610 /* Add thread to list. */ 611 dvprintf("Adding to threads list...\n"); 612 int tID = cvector_count(&p->threads); 613 if (threadID) { 614 (*threadID) = tID; 615 } 616 cvector_add(&p->threads, (cvector_item_t) thread); 617 assert(cvector_count(&p->threads) >= 1); 618 619 /* Start the new child thread. */ 620 error = proc_start_thread(p, tID, NULL, NULL); 621 if (error) { 622 ROS_ERROR("Could not start child thread %d!", tID); 623 goto exit2; 624 } 625 626 return ESUCCESS; 627 628 /* Exit stack. */ 629exit2: 630 cvector_delete(&p->threads, tID); 631 thread_release(thread); 632exit1: 633 kfree(thread); 634 assert(error != ESUCCESS); 635 return error; 636} 637 638extern seL4_MessageInfo_t _dispatcherEmptyReply; 639 640void 641proc_fault_reply(struct proc_pcb *p) 642{ 643 if (!p->faultReply.capPtr) { 644 return; 645 } 646 seL4_Send(p->faultReply.capPtr, _dispatcherEmptyReply); 647 vka_cnode_delete(&p->faultReply); 648 vka_cspace_free(&procServ.vka, p->faultReply.capPtr); 649 p->faultReply.capPtr = 0; 650} 651 652static void 653proc_parent_reply(struct proc_pcb *p) 654{ 655 assert(p->parentPID != PID_NULL); 656 657 /* Retrieve the parent PCB. */ 658 struct proc_pcb* parentPCB = pid_get_pcb(&procServ.PIDList, p->parentPID); 659 if (!parentPCB) { 660 ROS_WARNING("proc_parent_reply Could not get parent PID."); 661 return; 662 } 663 if (!parentPCB->parentWaiting) { 664 /* Nothing to do here. */ 665 return; 666 } 667 if (!parentPCB->faultReply.capPtr) { 668 ROS_WARNING("proc_parent_reply No reply endpoint! Book-keeping error."); 669 return; 670 } 671 672 dprintf("proc_parent_reply childPID %d parentPID %d.\n", p->pid, parentPCB->pid); 673 parentPCB->rpcClient.skip_reply = false; 674 parentPCB->rpcClient.reply = parentPCB->faultReply.capPtr; 675 reply_proc_new_proc((void*) parentPCB, &p->exitStatus, (refos_err_t) EXIT_SUCCESS); 676 677 vka_cnode_delete(&parentPCB->faultReply); 678 vka_cspace_free(&procServ.vka, parentPCB->faultReply.capPtr); 679 parentPCB->faultReply.capPtr = 0; 680} 681 682void 683proc_syscall_postaction(void) 684{ 685 if (procServ.exitProcessPID != PID_NULL) { 686 struct proc_pcb *pcb = pid_get_pcb(&procServ.PIDList, procServ.exitProcessPID); 687 if (!pcb) { 688 ROS_WARNING("proc_syscall_postaction error: No such PID!"); 689 procServ.exitProcessPID = PID_NULL; 690 return; 691 } 692 693 /* Delete the actual process. */ 694 uint32_t pid = pcb->pid; 695 pcb->rpcClient.skip_reply = true; 696 dprintf(" Releasing process %d [%s]...\n", pcb->pid, pcb->debugProcessName); 697 proc_release(pcb); 698 699 /* Kill the PID. */ 700 dvprintf(" Freeing PID...\n"); 701 pid_free(&procServ.PIDList, pid); 702 dvprintf(" Process exit OK!\n"); 703 704 procServ.exitProcessPID = PID_NULL; 705 } 706} 707