/* * exit() * * Copyright (C) 2008 Bahadir Balban */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* * Sends vfs task information about forked child, and its utcb */ int vfs_notify_exit(struct tcb *task, int status) { int err = 0; // printf("%s/%s\n", __TASKNAME__, __FUNCTION__); l4_save_ipcregs(); /* Write parent and child information */ write_mr(L4SYS_ARG0, task->tid); write_mr(L4SYS_ARG1, status); if ((err = l4_sendrecv(VFS_TID, VFS_TID, L4_IPC_TAG_NOTIFY_EXIT)) < 0) { printf("%s: L4 IPC Error: %d.\n", __FUNCTION__, err); goto out; } /* Check if syscall was successful */ if ((err = l4_get_retval()) < 0) { printf("%s: VFS returned ipc error: %d.\n", __FUNCTION__, err); goto out; } out: l4_restore_ipcregs(); return err; } /* Closes all file descriptors of a task */ int task_close_files(struct tcb *task) { int err = 0; /* Flush all file descriptors */ for (int fd = 0; fd < TASK_FILES_MAX; fd++) if (task->files->fd[fd].vmfile) if ((err = sys_close(task, fd)) < 0) { printf("File close error. Tid: %d," " fd: %d, error: %d\n", task->tid, fd, err); break; } return err; } /* Prepare old task's environment for new task */ int execve_recycle_task(struct tcb *new, struct tcb *orig) { int err; struct task_ids ids = { .tid = orig->tid, .spid = orig->spid, .tgid = orig->tgid, }; /* * Copy data to new task that is * to be retained from original */ /* Copy ids */ new->tid = orig->tid; new->spid = orig->spid; new->tgid = orig->tgid; new->pagerid = orig->pagerid; /* Copy shared page */ new->shared_page = orig->shared_page; /* Copy parent relationship */ BUG_ON(new->parent); new->parent = orig->parent; list_add(&new->child_ref, &orig->parent->children); /* Flush all IO on task's files and close fds */ task_close_files(orig); /* Destroy task's utcb slot */ task_destroy_utcb(orig); /* Vfs still knows the thread */ /* Keep the shared page on vfs */ /* Ask the kernel to recycle the thread */ if ((err = l4_thread_control(THREAD_RECYCLE, &ids)) < 0) { printf("%s: Suspending thread %d failed with %d.\n", __FUNCTION__, orig->tid, err); return err; } /* Destroy the locally known tcb */ tcb_destroy(orig); return 0; } void do_exit(struct tcb *task, int status) { struct task_ids ids = { .tid = task->tid, .spid = task->spid, .tgid = task->tgid, }; /* Flush all IO on task's files and close fds */ task_close_files(task); /* Destroy task's utcb slot */ task_destroy_utcb(task); /* Tell vfs that task is exiting */ vfs_notify_exit(task, status); /* Remove default shared page shm areas from vfs */ // printf("Unmapping 0x%p from vfs as shared-page of %d\n", task->shared_page, task->tid); shpage_unmap_from_task(task, find_task(VFS_TID)); /* Free task's local tcb */ tcb_destroy(task); /* Ask the kernel to delete the thread from its records */ l4_thread_control(THREAD_DESTROY, &ids); /* TODO: Wake up any waiters about task's destruction */ #if 0 struct tcb *parent = find_task(task->parentid); if (parent->waiting) { exregs_set_mr_return(status); l4_exchange_registers(parent->tid); l4_thread_control(THREAD_RUN, parent->tid); } #endif } void sys_exit(struct tcb *task, int status) { do_exit(task, status); }