Loading...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 | // SPDX-License-Identifier: GPL-2.0+ /* * Copyright (c) 2011 The Chromium OS Authors. */ #include <command.h> #include <console.h> #include <malloc.h> #include <vsprintf.h> #include <uthread.h> /* Spawn arguments and job index */ struct spa { int argc; char **argv; unsigned int job_idx; }; /* * uthread group identifiers for each running job * 0: job slot available, != 0: uthread group id * Note that job[0] is job_id 1, job[1] is job_id 2 etc. */ static unsigned int job[CONFIG_CMD_SPAWN_NUM_JOBS]; /* Return values of the commands run as jobs */ static enum command_ret_t job_ret[CONFIG_CMD_SPAWN_NUM_JOBS]; static void spa_free(struct spa *spa) { int i; if (!spa) return; for (i = 0; i < spa->argc; i++) free(spa->argv[i]); free(spa->argv); free(spa); } static struct spa *spa_create(int argc, char *const argv[]) { struct spa *spa; int i; spa = calloc(1, sizeof(*spa)); if (!spa) return NULL; spa->argc = argc; spa->argv = malloc(argc * sizeof(char *)); if (!spa->argv) goto err; for (i = 0; i < argc; i++) { spa->argv[i] = strdup(argv[i]); if (!spa->argv[i]) goto err; } return spa; err: spa_free(spa); return NULL; } static void spawn_thread(void *arg) { struct spa *spa = (struct spa *)arg; ulong cycles = 0; int repeatable = 0; job_ret[spa->job_idx] = cmd_process(0, spa->argc, spa->argv, &repeatable, &cycles); spa_free(spa); } static unsigned int next_job_id(void) { int i; for (i = 0; i < CONFIG_CMD_SPAWN_NUM_JOBS; i++) if (!job[i]) return i + 1; /* No job available */ return 0; } static void refresh_jobs(void) { int i; for (i = 0; i < CONFIG_CMD_SPAWN_NUM_JOBS; i++) if (job[i] && uthread_grp_done(job[i])) job[i] = 0; } static int do_spawn(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]) { unsigned int id; unsigned int idx; struct spa *spa; int ret; if (argc == 1) return CMD_RET_USAGE; spa = spa_create(argc - 1, argv + 1); if (!spa) return CMD_RET_FAILURE; refresh_jobs(); id = next_job_id(); if (!id) return CMD_RET_FAILURE; idx = id - 1; job[idx] = uthread_grp_new_id(); ret = uthread_create(NULL, spawn_thread, spa, 0, job[idx]); if (ret) { job[idx] = 0; return CMD_RET_FAILURE; } ret = env_set_ulong("job_id", id); if (ret) return CMD_RET_FAILURE; return CMD_RET_SUCCESS; } U_BOOT_CMD(spawn, CONFIG_SYS_MAXARGS, 0, do_spawn, "run commands and summarize execution time", "command [args...]\n"); static enum command_ret_t wait_job(unsigned int idx) { int prev = disable_ctrlc(false); while (!uthread_grp_done(job[idx])) { if (ctrlc()) { puts("<INTERRUPT>\n"); disable_ctrlc(prev); return CMD_RET_FAILURE; } uthread_schedule(); } job[idx] = 0; disable_ctrlc(prev); return job_ret[idx]; } static int do_wait(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]) { enum command_ret_t ret = CMD_RET_SUCCESS; unsigned long id; unsigned int idx; int i; if (argc == 1) { for (i = 0; i < CONFIG_CMD_SPAWN_NUM_JOBS; i++) if (job[i]) ret = wait_job(i); } else { for (i = 1; i < argc; i++) { id = dectoul(argv[i], NULL); if (id < 1 || id > CONFIG_CMD_SPAWN_NUM_JOBS) return CMD_RET_USAGE; idx = (int)id - 1; ret = wait_job(idx); } } return ret; } U_BOOT_CMD(wait, CONFIG_SYS_MAXARGS, 0, do_wait, "wait for one or more jobs to complete", "[job_id ...]\n" " - Wait until all specified jobs have exited and return the\n" " exit status of the last job waited for. When no job_id is\n" " given, wait for all the background jobs.\n"); |