source: mainline/uspace/lib/libc/generic/loader.c@ a78d001

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since a78d001 was 482c86f, checked in by Jiri Svoboda <jirik.svoboda@…>, 16 years ago

NS was forgetting to hangup phones. One phone was leaked for every load attempt and when all 16 phones were exhausted, NS would lock up.

  • Property mode set to 100644
File size: 6.6 KB
Line 
1/*
2 * Copyright (c) 2008 Jiri Svoboda
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29/** @addtogroup libc
30 * @{
31 */
32/** @file
33 */
34
35#include <ipc/ipc.h>
36#include <ipc/loader.h>
37#include <ipc/services.h>
38#include <libc.h>
39#include <task.h>
40#include <string.h>
41#include <stdlib.h>
42#include <async.h>
43#include <errno.h>
44#include <vfs/vfs.h>
45#include <loader/loader.h>
46
47/** Connect to a new program loader.
48 *
49 * Spawns a new program loader task and returns the connection structure.
50 * @param name Symbolic name to set on the newly created task.
51 * @return Pointer to the loader connection structure (should be
52 * de-allocated using free() after use).
53 */
54int loader_spawn(const char *name)
55{
56 return __SYSCALL2(SYS_PROGRAM_SPAWN_LOADER,
57 (sysarg_t) name, strlen(name));
58}
59
60loader_t *loader_connect(void)
61{
62 loader_t *ldr;
63 int phone_id;
64
65 phone_id = ipc_connect_me_to_blocking(PHONE_NS, SERVICE_LOAD, 0, 0);
66 if (phone_id < 0)
67 return NULL;
68
69 ldr = malloc(sizeof(loader_t));
70 if (ldr == NULL)
71 return NULL;
72
73 ldr->phone_id = phone_id;
74 return ldr;
75}
76
77/** Get ID of the new task.
78 *
79 * Retrieves the ID of the new task from the loader.
80 *
81 * @param ldr Loader connection structure.
82 * @param task_id Points to a variable where the ID should be stored.
83 * @return Zero on success or negative error code.
84 */
85int loader_get_task_id(loader_t *ldr, task_id_t *task_id)
86{
87 ipc_call_t answer;
88 aid_t req;
89 int rc;
90 ipcarg_t retval;
91
92 /* Get task ID. */
93 req = async_send_0(ldr->phone_id, LOADER_GET_TASKID, &answer);
94 rc = ipc_data_read_start(ldr->phone_id, task_id, sizeof(task_id_t));
95 if (rc != EOK) {
96 async_wait_for(req, NULL);
97 return rc;
98 }
99
100 async_wait_for(req, &retval);
101 return (int)retval;
102}
103
104/** Set pathname of the program to load.
105 *
106 * Sets the name of the program file to load. The name can be relative
107 * to the current working directory (it will be absolutized before
108 * sending to the loader).
109 *
110 * @param ldr Loader connection structure.
111 * @param path Pathname of the program file.
112 * @return Zero on success or negative error code.
113 */
114int loader_set_pathname(loader_t *ldr, const char *path)
115{
116 ipc_call_t answer;
117 aid_t req;
118 int rc;
119 ipcarg_t retval;
120
121 char *pa;
122 size_t pa_len;
123
124 pa = absolutize(path, &pa_len);
125 if (!pa)
126 return 0;
127
128 /* Send program pathname */
129 req = async_send_0(ldr->phone_id, LOADER_SET_PATHNAME, &answer);
130 rc = ipc_data_write_start(ldr->phone_id, (void *)pa, pa_len);
131 if (rc != EOK) {
132 async_wait_for(req, NULL);
133 return rc;
134 }
135
136 free(pa);
137
138 async_wait_for(req, &retval);
139 return (int)retval;
140}
141
142
143/** Set command-line arguments for the program.
144 *
145 * Sets the vector of command-line arguments to be passed to the loaded
146 * program. By convention, the very first argument is typically the same as
147 * the command used to execute the program.
148 *
149 * @param ldr Loader connection structure.
150 * @param argv NULL-terminated array of pointers to arguments.
151 * @return Zero on success or negative error code.
152 */
153int loader_set_args(loader_t *ldr, char *const argv[])
154{
155 aid_t req;
156 ipc_call_t answer;
157 ipcarg_t rc;
158
159 char *const *ap;
160 char *dp;
161 char *arg_buf;
162 size_t buffer_size;
163
164 /*
165 * Serialize the arguments into a single array. First
166 * compute size of the buffer needed.
167 */
168 ap = argv;
169 buffer_size = 0;
170 while (*ap != NULL) {
171 buffer_size += strlen(*ap) + 1;
172 ++ap;
173 }
174
175 arg_buf = malloc(buffer_size);
176 if (arg_buf == NULL) return ENOMEM;
177
178 /* Now fill the buffer with null-terminated argument strings */
179 ap = argv;
180 dp = arg_buf;
181 while (*ap != NULL) {
182 strcpy(dp, *ap);
183 dp += strlen(*ap) + 1;
184
185 ++ap;
186 }
187
188 /* Send serialized arguments to the loader */
189
190 req = async_send_0(ldr->phone_id, LOADER_SET_ARGS, &answer);
191 rc = ipc_data_write_start(ldr->phone_id, (void *)arg_buf, buffer_size);
192 if (rc != EOK) {
193 async_wait_for(req, NULL);
194 return rc;
195 }
196
197 async_wait_for(req, &rc);
198 if (rc != EOK) return rc;
199
200 /* Free temporary buffer */
201 free(arg_buf);
202
203 return EOK;
204}
205
206/** Instruct loader to load the program.
207 *
208 * If this function succeeds, the program has been successfully loaded
209 * and is ready to be executed.
210 *
211 * @param ldr Loader connection structure.
212 * @return Zero on success or negative error code.
213 */
214int loader_load_program(loader_t *ldr)
215{
216 int rc;
217
218 rc = async_req_0_0(ldr->phone_id, LOADER_LOAD);
219 if (rc != EOK)
220 return rc;
221
222 return EOK;
223}
224
225/** Instruct loader to execute the program.
226 *
227 * Note that this function blocks until the loader actually replies
228 * so you cannot expect this function to return if you are debugging
229 * the task and its thread is stopped.
230 *
231 * After using this function, no further operations must be performed
232 * on the loader structure. It should be de-allocated using free().
233 *
234 * @param ldr Loader connection structure.
235 * @return Zero on success or negative error code.
236 */
237int loader_run(loader_t *ldr)
238{
239 int rc;
240
241 rc = async_req_0_0(ldr->phone_id, LOADER_RUN);
242 if (rc != EOK)
243 return rc;
244
245 ipc_hangup(ldr->phone_id);
246 ldr->phone_id = 0;
247 return EOK;
248}
249
250/** Cancel the loader session.
251 *
252 * Tells the loader not to load any program and terminate.
253 * After using this function, no further operations must be performed
254 * on the loader structure. It should be de-allocated using free().
255 *
256 * @param ldr Loader connection structure.
257 * @return Zero on success or negative error code.
258 */
259void loader_abort(loader_t *ldr)
260{
261 ipc_hangup(ldr->phone_id);
262 ldr->phone_id = 0;
263}
264
265/** @}
266 */
Note: See TracBrowser for help on using the repository browser.