/trunk/uspace/lib/libc/include/loader/pcb.h |
---|
40,7 → 40,8 |
typedef void (*entry_point_t)(void); |
/** |
/** Program Control Block. |
* |
* Holds pointers to data passed from the program loader to the program |
* and/or to the dynamic linker. This includes the program entry point, |
* arguments, environment variables etc. |
/trunk/uspace/lib/libc/include/loader/loader.h |
---|
0,0 → 1,56 |
/* |
* Copyright (c) 2008 Jiri Svoboda |
* All rights reserved. |
* |
* Redistribution and use in source and binary forms, with or without |
* modification, are permitted provided that the following conditions |
* are met: |
* |
* - Redistributions of source code must retain the above copyright |
* notice, this list of conditions and the following disclaimer. |
* - Redistributions in binary form must reproduce the above copyright |
* notice, this list of conditions and the following disclaimer in the |
* documentation and/or other materials provided with the distribution. |
* - The name of the author may not be used to endorse or promote products |
* derived from this software without specific prior written permission. |
* |
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR |
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. |
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, |
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT |
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF |
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
*/ |
/** @addtogroup fs |
* @{ |
*/ |
/** @file |
* @brief Program loader interface. |
*/ |
#ifndef LIBC_LOADER_H_ |
#define LIBC_LOADER_H_ |
/** Abstraction of a loader connection */ |
typedef struct { |
/** ID of the phone connected to the loader. */ |
int phone_id; |
} loader_t; |
extern loader_t *loader_spawn(void); |
extern int loader_get_task_id(loader_t *, task_id_t *); |
extern int loader_set_pathname(loader_t *, const char *); |
extern int loader_set_args(loader_t *, char *const []); |
extern int loader_start_program(loader_t *); |
extern void loader_abort(loader_t *); |
#endif |
/** |
* @} |
*/ |
/trunk/uspace/lib/libc/include/ipc/loader.h |
---|
32,8 → 32,8 |
/** @file |
*/ |
#ifndef LIBC_LOADER_H_ |
#define LIBC_LOADER_H_ |
#ifndef LIBC_IPC_LOADER_H_ |
#define LIBC_IPC_LOADER_H_ |
#include <ipc/ipc.h> |
/trunk/uspace/lib/libc/generic/task.c |
---|
34,14 → 34,10 |
*/ |
#include <task.h> |
#include <ipc/ipc.h> |
#include <ipc/loader.h> |
#include <libc.h> |
#include <string.h> |
#include <stdlib.h> |
#include <async.h> |
#include <errno.h> |
#include <vfs/vfs.h> |
#include <loader/loader.h> |
task_id_t task_get_id(void) |
{ |
52,73 → 48,11 |
return task_id; |
} |
static int task_spawn_loader(void) |
{ |
int phone_id, rc; |
rc = __SYSCALL1(SYS_PROGRAM_SPAWN_LOADER, (sysarg_t) &phone_id); |
if (rc != 0) |
return rc; |
return phone_id; |
} |
static int loader_set_args(int phone_id, const char *argv[]) |
{ |
aid_t req; |
ipc_call_t answer; |
ipcarg_t rc; |
const char **ap; |
char *dp; |
char *arg_buf; |
size_t buffer_size; |
size_t len; |
/* |
* Serialize the arguments into a single array. First |
* compute size of the buffer needed. |
*/ |
ap = argv; |
buffer_size = 0; |
while (*ap != NULL) { |
buffer_size += strlen(*ap) + 1; |
++ap; |
} |
arg_buf = malloc(buffer_size); |
if (arg_buf == NULL) return ENOMEM; |
/* Now fill the buffer with null-terminated argument strings */ |
ap = argv; |
dp = arg_buf; |
while (*ap != NULL) { |
strcpy(dp, *ap); |
dp += strlen(*ap) + 1; |
++ap; |
} |
/* Send serialized arguments to the loader */ |
req = async_send_0(phone_id, LOADER_SET_ARGS, &answer); |
rc = ipc_data_write_start(phone_id, (void *)arg_buf, buffer_size); |
if (rc != EOK) { |
async_wait_for(req, NULL); |
return rc; |
} |
async_wait_for(req, &rc); |
if (rc != EOK) return rc; |
/* Free temporary buffer */ |
free(arg_buf); |
return EOK; |
} |
/** Create a new task by running an executable from VFS. |
/** Create a new task by running an executable from the filesystem. |
* |
* This is really just a convenience wrapper over the more complicated |
* loader API. |
* |
* @param path pathname of the binary to execute |
* @param argv command-line arguments |
* @return ID of the newly created task or zero on error. |
125,74 → 59,41 |
*/ |
task_id_t task_spawn(const char *path, char *const argv[]) |
{ |
int phone_id; |
ipc_call_t answer; |
aid_t req; |
loader_t *ldr; |
task_id_t task_id; |
int rc; |
ipcarg_t retval; |
char *pa; |
size_t pa_len; |
task_id_t task_id; |
pa = absolutize(path, &pa_len); |
if (!pa) |
return 0; |
/* Spawn a program loader */ |
phone_id = task_spawn_loader(); |
if (phone_id < 0) |
ldr = loader_spawn(); |
if (ldr == NULL) |
return 0; |
/* |
* Say hello so that the loader knows the incoming connection's |
* phone hash. |
*/ |
rc = async_req_0_0(phone_id, LOADER_HELLO); |
/* Get task ID. */ |
rc = loader_get_task_id(ldr, &task_id); |
if (rc != EOK) |
return 0; |
/* Get task ID. */ |
req = async_send_0(phone_id, LOADER_GET_TASKID, &answer); |
rc = ipc_data_read_start(phone_id, &task_id, sizeof(task_id)); |
if (rc != EOK) { |
async_wait_for(req, NULL); |
goto error; |
} |
async_wait_for(req, &retval); |
if (retval != EOK) |
goto error; |
/* Send program pathname */ |
req = async_send_0(phone_id, LOADER_SET_PATHNAME, &answer); |
rc = ipc_data_write_start(phone_id, (void *)pa, pa_len); |
if (rc != EOK) { |
async_wait_for(req, NULL); |
return 1; |
} |
async_wait_for(req, &retval); |
if (retval != EOK) |
rc = loader_set_pathname(ldr, path); |
if (rc != EOK) |
goto error; |
/* Send arguments */ |
rc = loader_set_args(phone_id, argv); |
rc = loader_set_args(ldr, argv); |
if (rc != EOK) |
goto error; |
/* Request loader to start the program */ |
rc = async_req_0_0(phone_id, LOADER_RUN); |
rc = loader_start_program(ldr); |
if (rc != EOK) |
goto error; |
/* Success */ |
ipc_hangup(phone_id); |
return task_id; |
/* Error exit */ |
error: |
ipc_hangup(phone_id); |
loader_abort(ldr); |
return 0; |
} |
/trunk/uspace/lib/libc/generic/loader.c |
---|
0,0 → 1,244 |
/* |
* Copyright (c) 2008 Jiri Svoboda |
* All rights reserved. |
* |
* Redistribution and use in source and binary forms, with or without |
* modification, are permitted provided that the following conditions |
* are met: |
* |
* - Redistributions of source code must retain the above copyright |
* notice, this list of conditions and the following disclaimer. |
* - Redistributions in binary form must reproduce the above copyright |
* notice, this list of conditions and the following disclaimer in the |
* documentation and/or other materials provided with the distribution. |
* - The name of the author may not be used to endorse or promote products |
* derived from this software without specific prior written permission. |
* |
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR |
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. |
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, |
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT |
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF |
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
*/ |
/** @addtogroup libc |
* @{ |
*/ |
/** @file |
*/ |
#include <ipc/ipc.h> |
#include <ipc/loader.h> |
#include <libc.h> |
#include <string.h> |
#include <stdlib.h> |
#include <async.h> |
#include <errno.h> |
#include <vfs/vfs.h> |
#include <loader/loader.h> |
/** Connect to a new program loader. |
* |
* Spawns a new program loader task and returns the connection structure. |
* @return Pointer to the loader connection structure (should be |
* de-allocated using free() after use). |
*/ |
loader_t *loader_spawn(void) |
{ |
int phone_id, rc; |
loader_t *ldr; |
/* |
* Ask kernel to spawn a new loader task. |
*/ |
rc = __SYSCALL1(SYS_PROGRAM_SPAWN_LOADER, (sysarg_t) &phone_id); |
if (rc != 0) |
return NULL; |
/* |
* Say hello so that the loader knows the incoming connection's |
* phone hash. |
*/ |
rc = async_req_0_0(phone_id, LOADER_HELLO); |
if (rc != EOK) |
return NULL; |
ldr = malloc(sizeof(loader_t)); |
if (ldr == NULL) |
return NULL; |
ldr->phone_id = phone_id; |
return ldr; |
} |
/** Get ID of the new task. |
* |
* Retrieves the ID of the new task from the loader. |
* |
* @param ldr Loader connection structure. |
* @param task_id Points to a variable where the ID should be stored. |
* @return Zero on success or negative error code. |
*/ |
int loader_get_task_id(loader_t *ldr, task_id_t *task_id) |
{ |
ipc_call_t answer; |
aid_t req; |
int rc; |
ipcarg_t retval; |
/* Get task ID. */ |
req = async_send_0(ldr->phone_id, LOADER_GET_TASKID, &answer); |
rc = ipc_data_read_start(ldr->phone_id, task_id, sizeof(task_id)); |
if (rc != EOK) { |
async_wait_for(req, NULL); |
return rc; |
} |
async_wait_for(req, &retval); |
return (int)retval; |
} |
/** Set pathname of the program to load. |
* |
* Sets the name of the program file to load. The name can be relative |
* to the current working directory (it will be absolutized before |
* sending to the loader). |
* |
* @param ldr Loader connection structure. |
* @param path Pathname of the program file. |
* @return Zero on success or negative error code. |
*/ |
int loader_set_pathname(loader_t *ldr, const char *path) |
{ |
ipc_call_t answer; |
aid_t req; |
int rc; |
ipcarg_t retval; |
char *pa; |
size_t pa_len; |
pa = absolutize(path, &pa_len); |
if (!pa) |
return 0; |
/* Send program pathname */ |
req = async_send_0(ldr->phone_id, LOADER_SET_PATHNAME, &answer); |
rc = ipc_data_write_start(ldr->phone_id, (void *)pa, pa_len); |
if (rc != EOK) { |
async_wait_for(req, NULL); |
return rc; |
} |
free(pa); |
async_wait_for(req, &retval); |
return (int)retval; |
} |
/** Set command-line arguments for the program. |
* |
* Sets the vector of command-line arguments to be passed to the loaded |
* program. By convention, the very first argument is typically the same as |
* the command used to execute the program. |
* |
* @param ldr Loader connection structure. |
* @param argv NULL-terminated array of pointers to arguments. |
* @return Zero on success or negative error code. |
*/ |
int loader_set_args(loader_t *ldr, char *const argv[]) |
{ |
aid_t req; |
ipc_call_t answer; |
ipcarg_t rc; |
char *const *ap; |
char *dp; |
char *arg_buf; |
size_t buffer_size; |
/* |
* Serialize the arguments into a single array. First |
* compute size of the buffer needed. |
*/ |
ap = argv; |
buffer_size = 0; |
while (*ap != NULL) { |
buffer_size += strlen(*ap) + 1; |
++ap; |
} |
arg_buf = malloc(buffer_size); |
if (arg_buf == NULL) return ENOMEM; |
/* Now fill the buffer with null-terminated argument strings */ |
ap = argv; |
dp = arg_buf; |
while (*ap != NULL) { |
strcpy(dp, *ap); |
dp += strlen(*ap) + 1; |
++ap; |
} |
/* Send serialized arguments to the loader */ |
req = async_send_0(ldr->phone_id, LOADER_SET_ARGS, &answer); |
rc = ipc_data_write_start(ldr->phone_id, (void *)arg_buf, buffer_size); |
if (rc != EOK) { |
async_wait_for(req, NULL); |
return rc; |
} |
async_wait_for(req, &rc); |
if (rc != EOK) return rc; |
/* Free temporary buffer */ |
free(arg_buf); |
return EOK; |
} |
/** Instruct loader to execute the program. |
* |
* After using this function, no further operations must be performed |
* on the loader structure. It should be de-allocated using free(). |
* |
* @param ldr Loader connection structure. |
* @return Zero on success or negative error code. |
*/ |
int loader_start_program(loader_t *ldr) |
{ |
int rc; |
rc = async_req_0_0(ldr->phone_id, LOADER_RUN); |
if (rc != EOK) |
return rc; |
ipc_hangup(ldr->phone_id); |
return EOK; |
} |
/** Cancel the loader session. |
* |
* Tells the loader not to load any program and terminate. |
* After using this function, no further operations must be performed |
* on the loader structure. It should be de-allocated using free(). |
* |
* @param ldr Loader connection structure. |
* @return Zero on success or negative error code. |
*/ |
void loader_abort(loader_t *ldr) |
{ |
ipc_hangup(ldr->phone_id); |
ldr->phone_id = 0; |
} |
/** @} |
*/ |
/trunk/uspace/lib/libc/Makefile |
---|
71,6 → 71,7 |
generic/sysinfo.c \ |
generic/ipc.c \ |
generic/async.c \ |
generic/loader.c \ |
generic/getopt.c \ |
generic/libadt/list.o \ |
generic/libadt/hash_table.o \ |