parlib: Move the provisioning of cores to a PID
[akaros.git] / user / parlib / parlib.c
1 /* Copyright (c) 2015 Google, Inc.
2  * Barret Rhoden <brho@cs.berkeley.edu>
3  * See LICENSE for details. */
4
5 #include <parlib/parlib.h>
6 #include <parlib/core_set.h>
7 #include <parlib/ros_debug.h>
8 #include <stdlib.h>
9
10 /* Control variables */
11 bool parlib_wants_to_be_mcp = TRUE;
12 bool parlib_never_yield = FALSE;
13 bool parlib_never_vc_request = FALSE;
14
15 /* Creates a child process for program @exe, with args and envs.  Will attempt
16  * to look in /bin/ if the initial lookup fails, and will invoke sh to handle
17  * non-elfs.  Returns the child's PID on success, -1 o/w. */
18 pid_t create_child(const char *exe, int argc, char *const argv[],
19                    char *const envp[])
20 {
21         pid_t kid;
22         char *path_exe;
23         char **sh_argv;
24         const char *sh_path = "/bin/sh";
25
26         kid = sys_proc_create(exe, strlen(exe), argv, envp, 0);
27         if (kid > 0)
28                 return kid;
29
30         /* Here's how we avoid infinite recursion.  We can only have ENOENT the
31          * first time through without bailing out, since all errno paths set exe to
32          * begin with '/'.  That includes calls from ENOEXEC, since sh_path begins
33          * with /.  To avoid repeated calls to ENOEXEC, we just look for sh_path as
34          * the exe, so if we have consecutive ENOEXECs, we'll bail out. */
35         switch (errno) {
36         case ENOENT:
37                 if (exe[0] == '/')
38                         return -1;
39                 path_exe = malloc(MAX_PATH_LEN);
40                 if (!path_exe)
41                         return -1;
42                 /* Our 'PATH' is only /bin. */
43                 snprintf(path_exe, MAX_PATH_LEN, "/bin/%s", exe);
44                 path_exe[MAX_PATH_LEN - 1] = 0;
45                 kid = create_child(path_exe, argc, argv, envp);
46                 free(path_exe);
47                 break;
48         case ENOEXEC:
49                 /* In case someone replaces /bin/sh with a non-elf. */
50                 if (!strcmp(sh_path, exe))
51                         return -1;
52                 /* We want enough space for the original argv, plus one entry at the
53                  * front for sh_path.  When we grab the original argv, we also need the
54                  * trailing NULL, which is at argv[argc].  That means we really want
55                  * argc + 1 entries from argv. */
56                 sh_argv = malloc(sizeof(char *) * (argc + 2));
57                 if (!sh_argv)
58                         return -1;
59                 memcpy(&sh_argv[1], argv, sizeof(char *) * (argc + 1));
60                 sh_argv[0] = (char*)sh_path;
61                 /* Replace the original argv[0] with the path to exe, which might have
62                  * been edited to include /bin/ */
63                 sh_argv[1] = (char*)exe;
64                 kid = create_child(sh_path, argc + 1, sh_argv, envp);
65                 free(sh_argv);
66                 break;
67         default:
68                 return -1;
69         }
70         return kid;
71 }
72
73 /* Creates a child process for exe, and shares the parent's standard FDs (stdin,
74  * stdout, stderr) with the child.  Returns the child's PID on success, -1 o/w.
75  */
76 pid_t create_child_with_stdfds(const char *exe, int argc, char *const argv[],
77                                char *const envp[])
78 {
79         struct childfdmap fd_dups[3] = { {0, 0}, {1, 1}, {2, 2} };
80         pid_t kid;
81         int ret;
82
83         kid = create_child(exe, argc, argv, envp);
84         if (kid < 0)
85                 return -1;
86         ret = syscall(SYS_dup_fds_to, kid, fd_dups, COUNT_OF(fd_dups));
87         if (ret != COUNT_OF(fd_dups)) {
88                 sys_proc_destroy(kid, -1);
89                 return -1;
90         }
91         return kid;
92 }
93
94 /* Provisions the CG cores to PID.  Returns -1 if any of them fail. */
95 int provision_core_set(pid_t pid, const struct core_set *cores)
96 {
97         struct core_set pvcores;
98         size_t max_cores = parlib_nr_total_cores();
99
100         parlib_get_ll_core_set(&pvcores);
101         parlib_not_core_set(&pvcores);
102         parlib_and_core_sets(&pvcores, cores);
103         for (size_t i = 0; i < max_cores; i++) {
104                 if (parlib_get_core(&pvcores, i)) {
105                         if (sys_provision(pid, RES_CORES, i))
106                                 return -1;
107                 }
108         }
109         return 0;
110 }