|  | /* Copyright (c) 2015 Google, Inc. | 
|  | * Barret Rhoden <brho@cs.berkeley.edu> | 
|  | * See LICENSE for details. */ | 
|  |  | 
|  | #include <parlib/parlib.h> | 
|  | #include <parlib/core_set.h> | 
|  | #include <parlib/ros_debug.h> | 
|  | #include <parlib/event.h> | 
|  | #include <stdlib.h> | 
|  | #include <sys/wait.h> | 
|  |  | 
|  | /* Control variables */ | 
|  | bool parlib_wants_to_be_mcp = TRUE; | 
|  | bool parlib_never_yield = FALSE; | 
|  | bool parlib_never_vc_request = FALSE; | 
|  |  | 
|  | /* Creates a child process for program @exe, with args and envs.  Will attempt | 
|  | * to look in /bin/ if the initial lookup fails, and will invoke sh to handle | 
|  | * non-elfs.  Returns the child's PID on success, -1 o/w. */ | 
|  | pid_t create_child(const char *exe, int argc, char *const argv[], | 
|  | char *const envp[]) | 
|  | { | 
|  | pid_t kid; | 
|  | char *path_exe; | 
|  | char **sh_argv; | 
|  | const char *sh_path = "/bin/sh"; | 
|  |  | 
|  | kid = sys_proc_create(exe, strlen(exe), argv, envp, 0); | 
|  | if (kid > 0) | 
|  | return kid; | 
|  |  | 
|  | /* Here's how we avoid infinite recursion.  We can only have ENOENT the | 
|  | * first time through without bailing out, since all errno paths set exe | 
|  | * to begin with '/'.  That includes calls from ENOEXEC, since sh_path | 
|  | * begins with /.  To avoid repeated calls to ENOEXEC, we just look for | 
|  | * sh_path as the exe, so if we have consecutive ENOEXECs, we'll bail | 
|  | * out. */ | 
|  | switch (errno) { | 
|  | case ENOENT: | 
|  | if (exe[0] == '/') | 
|  | return -1; | 
|  | path_exe = malloc(MAX_PATH_LEN); | 
|  | if (!path_exe) | 
|  | return -1; | 
|  | /* Our 'PATH' is only /bin. */ | 
|  | snprintf(path_exe, MAX_PATH_LEN, "/bin/%s", exe); | 
|  | path_exe[MAX_PATH_LEN - 1] = 0; | 
|  | kid = create_child(path_exe, argc, argv, envp); | 
|  | free(path_exe); | 
|  | break; | 
|  | case ENOEXEC: | 
|  | /* In case someone replaces /bin/sh with a non-elf. */ | 
|  | if (!strcmp(sh_path, exe)) | 
|  | return -1; | 
|  | /* We want enough space for the original argv, plus one entry at | 
|  | * the front for sh_path.  When we grab the original argv, we | 
|  | * also need the trailing NULL, which is at argv[argc].  That | 
|  | * means we really want argc + 1 entries from argv. */ | 
|  | sh_argv = malloc(sizeof(char *) * (argc + 2)); | 
|  | if (!sh_argv) | 
|  | return -1; | 
|  | memcpy(&sh_argv[1], argv, sizeof(char *) * (argc + 1)); | 
|  | sh_argv[0] = (char*)sh_path; | 
|  | /* Replace the original argv[0] with the path to exe, which | 
|  | * might have been edited to include /bin/ */ | 
|  | sh_argv[1] = (char*)exe; | 
|  | kid = create_child(sh_path, argc + 1, sh_argv, envp); | 
|  | free(sh_argv); | 
|  | break; | 
|  | default: | 
|  | return -1; | 
|  | } | 
|  | return kid; | 
|  | } | 
|  |  | 
|  | /* Creates a child process for exe, and shares the parent's standard FDs (stdin, | 
|  | * stdout, stderr) with the child.  Returns the child's PID on success, -1 o/w. | 
|  | */ | 
|  | pid_t create_child_with_stdfds(const char *exe, int argc, char *const argv[], | 
|  | char *const envp[]) | 
|  | { | 
|  | struct childfdmap fd_dups[3] = { {0, 0}, {1, 1}, {2, 2} }; | 
|  | pid_t kid; | 
|  | int ret; | 
|  |  | 
|  | kid = create_child(exe, argc, argv, envp); | 
|  | if (kid < 0) | 
|  | return -1; | 
|  | ret = syscall(SYS_dup_fds_to, kid, fd_dups, COUNT_OF(fd_dups)); | 
|  | if (ret != COUNT_OF(fd_dups)) { | 
|  | sys_proc_destroy(kid, -1); | 
|  | return -1; | 
|  | } | 
|  | return kid; | 
|  | } | 
|  |  | 
|  | /* Helper for kicking off a process, but with little specific error handling */ | 
|  | int run_and_wait(const char *exe, int argc, char *const argv[]) | 
|  | { | 
|  | extern char **environ; | 
|  |  | 
|  | pid_t kid; | 
|  |  | 
|  | kid = create_child_with_stdfds(exe, argc, argv, environ); | 
|  | if (kid < 0) | 
|  | return -1; | 
|  | if (sys_proc_run(kid) < 0) | 
|  | return -1; | 
|  | if (waitpid(kid, NULL, 0) != kid) | 
|  | return -1; | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | /* Provisions the CG cores to PID.  Returns -1 if any of them fail. */ | 
|  | int provision_core_set(pid_t pid, const struct core_set *cores) | 
|  | { | 
|  | struct core_set pvcores; | 
|  | size_t max_cores = parlib_nr_total_cores(); | 
|  |  | 
|  | parlib_get_ll_core_set(&pvcores); | 
|  | parlib_not_core_set(&pvcores); | 
|  | parlib_and_core_sets(&pvcores, cores); | 
|  | for (size_t i = 0; i < max_cores; i++) { | 
|  | if (parlib_get_core(&pvcores, i)) { | 
|  | if (sys_provision(pid, RES_CORES, i)) | 
|  | return -1; | 
|  | } | 
|  | } | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | /* This sets up 'handler' to be run when the process receives EV_FREE_APPLE_PIE | 
|  | * (9).  You can send this event with the notify utility: | 
|  | * | 
|  | *	notify PID 9 [Arg1 Arg2 0xArg3 Arg4] | 
|  | * | 
|  | * A simple debug handler can switch on an arg: | 
|  |  | 
|  | static void notify_ipi(struct event_msg *ev_msg, unsigned int ev_type, | 
|  | void *data) | 
|  | { | 
|  | switch (ev_msg->ev_arg1) { | 
|  | case 1: | 
|  | // do something | 
|  | break; | 
|  | case 2: | 
|  | // do something else | 
|  | break; | 
|  | default: | 
|  | printf("Unknown arg %d\n", ev_msg->ev_arg1); | 
|  | break; | 
|  | } | 
|  | } | 
|  |  | 
|  | */ | 
|  | void set_notify_9(void (*handler)(struct event_msg *ev_msg, | 
|  | unsigned int ev_type, void *data), | 
|  | void *data) | 
|  | { | 
|  | struct event_queue *evq; | 
|  |  | 
|  | register_ev_handler(EV_FREE_APPLE_PIE, handler, data); | 
|  | evq = get_eventq(EV_MBOX_UCQ); | 
|  | evq->ev_flags = EVENT_IPI | EVENT_INDIR | EVENT_SPAM_INDIR | | 
|  | EVENT_WAKEUP; | 
|  | register_kevent_q(evq, EV_FREE_APPLE_PIE); | 
|  | } |