source: mainline/uspace/lib/c/generic/task.c@ a35b458

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since a35b458 was a35b458, checked in by Jiří Zárevúcky <zarevucky.jiri@…>, 7 years ago

style: Remove trailing whitespace on _all_ lines, including empty ones, for particular file types.

Command used: tools/srepl '\s\+$' '' -- *.c *.h *.py *.sh *.s *.S *.ag

Currently, whitespace on empty lines is very inconsistent.
There are two basic choices: Either remove the whitespace, or keep empty lines
indented to the level of surrounding code. The former is AFAICT more common,
and also much easier to do automatically.

Alternatively, we could write script for automatic indentation, and use that
instead. However, if such a script exists, it's possible to use the indented
style locally, by having the editor apply relevant conversions on load/save,
without affecting remote repository. IMO, it makes more sense to adopt
the simpler rule.

  • Property mode set to 100644
File size: 10.9 KB
Line 
1/*
2 * Copyright (c) 2006 Jakub Jermar
3 * Copyright (c) 2008 Jiri Svoboda
4 * Copyright (c) 2014 Martin Sucha
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 *
11 * - Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * - Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * - The name of the author may not be used to endorse or promote products
17 * derived from this software without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
20 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
21 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
22 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
23 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
24 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
28 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 */
30
31/** @addtogroup libc
32 * @{
33 */
34/** @file
35 */
36
37#include <task.h>
38#include <loader/loader.h>
39#include <stdarg.h>
40#include <str.h>
41#include <ipc/ns.h>
42#include <macros.h>
43#include <assert.h>
44#include <async.h>
45#include <errno.h>
46#include <ns.h>
47#include <stdlib.h>
48#include <libc.h>
49#include "private/ns.h"
50#include <vfs/vfs.h>
51
52task_id_t task_get_id(void)
53{
54#ifdef __32_BITS__
55 task_id_t task_id;
56 (void) __SYSCALL1(SYS_TASK_GET_ID, (sysarg_t) &task_id);
57
58 return task_id;
59#endif /* __32_BITS__ */
60
61#ifdef __64_BITS__
62 return (task_id_t) __SYSCALL0(SYS_TASK_GET_ID);
63#endif /* __64_BITS__ */
64}
65
66/** Set the task name.
67 *
68 * @param name The new name, typically the command used to execute the
69 * program.
70 *
71 * @return Zero on success or an error code.
72 */
73errno_t task_set_name(const char *name)
74{
75 assert(name);
76
77 return (errno_t) __SYSCALL2(SYS_TASK_SET_NAME, (sysarg_t) name, str_size(name));
78}
79
80/** Kill a task.
81 *
82 * @param task_id ID of task to kill.
83 *
84 * @return Zero on success or an error code.
85 */
86
87errno_t task_kill(task_id_t task_id)
88{
89 return (errno_t) __SYSCALL1(SYS_TASK_KILL, (sysarg_t) &task_id);
90}
91
92/** Create a new task by running an executable from the filesystem.
93 *
94 * This is really just a convenience wrapper over the more complicated
95 * loader API. Arguments are passed as a null-terminated array of strings.
96 *
97 * @param id If not NULL, the ID of the task is stored here on success.
98 * @param wait If not NULL, setup waiting for task's return value and store
99 * the information necessary for waiting here on success.
100 * @param path Pathname of the binary to execute.
101 * @param argv Command-line arguments.
102 *
103 * @return Zero on success or an error code.
104 *
105 */
106errno_t task_spawnv(task_id_t *id, task_wait_t *wait, const char *path,
107 const char *const args[])
108{
109 /* Send default files */
110
111 int fd_stdin = -1;
112 int fd_stdout = -1;
113 int fd_stderr = -1;
114
115 if (stdin != NULL) {
116 (void) vfs_fhandle(stdin, &fd_stdin);
117 }
118
119 if (stdout != NULL) {
120 (void) vfs_fhandle(stdout, &fd_stdout);
121 }
122
123 if (stderr != NULL) {
124 (void) vfs_fhandle(stderr, &fd_stderr);
125 }
126
127 return task_spawnvf(id, wait, path, args, fd_stdin, fd_stdout,
128 fd_stderr);
129}
130
131/** Create a new task by running an executable from the filesystem.
132 *
133 * This is really just a convenience wrapper over the more complicated
134 * loader API. Arguments are passed as a null-terminated array of strings.
135 * Files are passed as null-terminated array of pointers to fdi_node_t.
136 *
137 * @param id If not NULL, the ID of the task is stored here on success.
138 * @param wait If not NULL, setup waiting for task's return value and store
139 * @param path Pathname of the binary to execute.
140 * @param argv Command-line arguments.
141 * @param std_in File to use as stdin.
142 * @param std_out File to use as stdout.
143 * @param std_err File to use as stderr.
144 *
145 * @return Zero on success or an error code.
146 *
147 */
148errno_t task_spawnvf(task_id_t *id, task_wait_t *wait, const char *path,
149 const char *const args[], int fd_stdin, int fd_stdout, int fd_stderr)
150{
151 /* Connect to a program loader. */
152 loader_t *ldr = loader_connect();
153 if (ldr == NULL)
154 return EREFUSED;
155
156 bool wait_initialized = false;
157
158 /* Get task ID. */
159 task_id_t task_id;
160 errno_t rc = loader_get_task_id(ldr, &task_id);
161 if (rc != EOK)
162 goto error;
163
164 /* Send spawner's current working directory. */
165 rc = loader_set_cwd(ldr);
166 if (rc != EOK)
167 goto error;
168
169 /* Send program binary. */
170 rc = loader_set_program_path(ldr, path);
171 if (rc != EOK)
172 goto error;
173
174 /* Send arguments. */
175 rc = loader_set_args(ldr, args);
176 if (rc != EOK)
177 goto error;
178
179 /* Send files */
180 int root = vfs_root();
181 if (root >= 0) {
182 rc = loader_add_inbox(ldr, "root", root);
183 vfs_put(root);
184 if (rc != EOK)
185 goto error;
186 }
187
188 if (fd_stdin >= 0) {
189 rc = loader_add_inbox(ldr, "stdin", fd_stdin);
190 if (rc != EOK)
191 goto error;
192 }
193
194 if (fd_stdout >= 0) {
195 rc = loader_add_inbox(ldr, "stdout", fd_stdout);
196 if (rc != EOK)
197 goto error;
198 }
199
200 if (fd_stderr >= 0) {
201 rc = loader_add_inbox(ldr, "stderr", fd_stderr);
202 if (rc != EOK)
203 goto error;
204 }
205
206 /* Load the program. */
207 rc = loader_load_program(ldr);
208 if (rc != EOK)
209 goto error;
210
211 /* Setup waiting for return value if needed */
212 if (wait) {
213 rc = task_setup_wait(task_id, wait);
214 if (rc != EOK)
215 goto error;
216 wait_initialized = true;
217 }
218
219 /* Run it. */
220 rc = loader_run(ldr);
221 if (rc != EOK)
222 goto error;
223
224 /* Success */
225 if (id != NULL)
226 *id = task_id;
227
228 return EOK;
229
230error:
231 if (wait_initialized)
232 task_cancel_wait(wait);
233
234 /* Error exit */
235 loader_abort(ldr);
236 return rc;
237}
238
239/** Create a new task by running an executable from the filesystem.
240 *
241 * This is really just a convenience wrapper over the more complicated
242 * loader API. Arguments are passed in a va_list.
243 *
244 * @param id If not NULL, the ID of the task is stored here on success.
245 * @param wait If not NULL, setup waiting for task's return value and store
246 * the information necessary for waiting here on success.
247 * @param path Pathname of the binary to execute.
248 * @param cnt Number of arguments.
249 * @param ap Command-line arguments.
250 *
251 * @return Zero on success or an error code.
252 *
253 */
254errno_t task_spawn(task_id_t *task_id, task_wait_t *wait, const char *path,
255 int cnt, va_list ap)
256{
257 /* Allocate argument list. */
258 const char **arglist = malloc(cnt * sizeof(const char *));
259 if (arglist == NULL)
260 return ENOMEM;
261
262 /* Fill in arguments. */
263 const char *arg;
264 cnt = 0;
265 do {
266 arg = va_arg(ap, const char *);
267 arglist[cnt++] = arg;
268 } while (arg != NULL);
269
270 /* Spawn task. */
271 errno_t rc = task_spawnv(task_id, wait, path, arglist);
272
273 /* Free argument list. */
274 free(arglist);
275 return rc;
276}
277
278/** Create a new task by running an executable from the filesystem.
279 *
280 * This is really just a convenience wrapper over the more complicated
281 * loader API. Arguments are passed as a null-terminated list of arguments.
282 *
283 * @param id If not NULL, the ID of the task is stored here on success.
284 * @param wait If not NULL, setup waiting for task's return value and store
285 * the information necessary for waiting here on success.
286 * @param path Pathname of the binary to execute.
287 * @param ... Command-line arguments.
288 *
289 * @return Zero on success or an error code.
290 *
291 */
292errno_t task_spawnl(task_id_t *task_id, task_wait_t *wait, const char *path, ...)
293{
294 /* Count the number of arguments. */
295
296 va_list ap;
297 const char *arg;
298 int cnt = 0;
299
300 va_start(ap, path);
301 do {
302 arg = va_arg(ap, const char *);
303 cnt++;
304 } while (arg != NULL);
305 va_end(ap);
306
307 va_start(ap, path);
308 errno_t rc = task_spawn(task_id, wait, path, cnt, ap);
309 va_end(ap);
310
311 return rc;
312}
313
314/** Setup waiting for a task.
315 *
316 * If the task finishes after this call succeeds, it is guaranteed that
317 * task_wait(wait, &texit, &retval) will return correct return value for
318 * the task.
319 *
320 * @param id ID of the task to setup waiting for.
321 * @param wait Information necessary for the later task_wait call is stored here.
322 *
323 * @return EOK on success, else error code.
324 */
325errno_t task_setup_wait(task_id_t id, task_wait_t *wait)
326{
327 async_sess_t *sess_ns = ns_session_get();
328 if (sess_ns == NULL)
329 return EIO;
330
331 async_exch_t *exch = async_exchange_begin(sess_ns);
332 wait->aid = async_send_2(exch, NS_TASK_WAIT, LOWER32(id), UPPER32(id),
333 &wait->result);
334 async_exchange_end(exch);
335
336 return EOK;
337}
338
339/** Cancel waiting for a task.
340 *
341 * This can be called *instead of* task_wait if the caller is not interested
342 * in waiting for the task anymore.
343 *
344 * This function cannot be called if the task_wait was already called.
345 *
346 * @param wait task_wait_t previously initialized by task_setup_wait.
347 */
348void task_cancel_wait(task_wait_t *wait) {
349 async_forget(wait->aid);
350}
351
352/** Wait for a task to finish.
353 *
354 * This function returns correct values even if the task finished in
355 * between task_setup_wait and this task_wait call.
356 *
357 * This function cannot be called more than once with the same task_wait_t
358 * (it can be reused, but must be reinitialized with task_setup_wait first)
359 *
360 * @param wait task_wait_t previously initialized by task_setup_wait.
361 * @param texit Store type of task exit here.
362 * @param retval Store return value of the task here.
363 *
364 * @return EOK on success, else error code.
365 */
366errno_t task_wait(task_wait_t *wait, task_exit_t *texit, int *retval)
367{
368 assert(texit);
369 assert(retval);
370
371 errno_t rc;
372 async_wait_for(wait->aid, &rc);
373
374 if (rc == EOK) {
375 *texit = IPC_GET_ARG1(wait->result);
376 *retval = IPC_GET_ARG2(wait->result);
377 }
378
379 return rc;
380}
381
382/** Wait for a task to finish by its id.
383 *
384 * Note that this will fail with ENOENT if the task id is not registered in ns
385 * (e.g. if the task finished). If you are spawning a task and need to wait
386 * for its completion, use wait parameter of the task_spawn* functions instead
387 * to prevent a race where the task exits before you may have a chance to wait
388 * wait for it.
389 *
390 * @param id ID of the task to wait for.
391 * @param texit Store type of task exit here.
392 * @param retval Store return value of the task here.
393 *
394 * @return EOK on success, else error code.
395 */
396errno_t task_wait_task_id(task_id_t id, task_exit_t *texit, int *retval)
397{
398 task_wait_t wait;
399 errno_t rc = task_setup_wait(id, &wait);
400 if (rc != EOK)
401 return rc;
402
403 return task_wait(&wait, texit, retval);
404}
405
406errno_t task_retval(int val)
407{
408 async_sess_t *sess_ns = ns_session_get();
409 if (sess_ns == NULL)
410 return EIO;
411
412 async_exch_t *exch = async_exchange_begin(sess_ns);
413 errno_t rc = (errno_t) async_req_1_0(exch, NS_RETVAL, val);
414 async_exchange_end(exch);
415
416 return rc;
417}
418
419/** @}
420 */
Note: See TracBrowser for help on using the repository browser.