/branches/dynload/uspace/lib/libc/include/task.h |
---|
40,7 → 40,7 |
typedef uint64_t task_id_t; |
extern task_id_t task_get_id(void); |
task_id_t task_spawn(const char *path, const char *argv[]); |
extern task_id_t task_spawn(const char *path, char *const argv[]); |
#endif |
/branches/dynload/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. |
/branches/dynload/uspace/lib/libc/include/loader/loader.h |
---|
0,0 → 1,57 |
/* |
* 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_load_program(loader_t *); |
extern int loader_run(loader_t *); |
extern void loader_abort(loader_t *); |
#endif |
/** |
* @} |
*/ |
/branches/dynload/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> |
42,6 → 42,7 |
LOADER_GET_TASKID, |
LOADER_SET_PATHNAME, |
LOADER_SET_ARGS, |
LOADER_LOAD, |
LOADER_RUN |
} fb_request_t; |
/branches/dynload/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,147 → 48,62 |
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. |
*/ |
task_id_t task_spawn(const char *path, const char *argv[]) |
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) |
/* Spawn a program loader. */ |
ldr = loader_spawn(); |
if (ldr == NULL) |
return 0; |
/* Spawn a program loader */ |
phone_id = task_spawn_loader(); |
if (phone_id < 0) |
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) |
/* Send program pathname. */ |
rc = loader_set_pathname(ldr, path); |
if (rc != 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) |
/* Send arguments. */ |
rc = loader_set_args(ldr, argv); |
if (rc != EOK) |
goto error; |
/* Send arguments */ |
rc = loader_set_args(phone_id, argv); |
/* Load the program. */ |
rc = loader_load_program(ldr); |
if (rc != EOK) |
goto error; |
/* Request loader to start the program */ |
rc = async_req_0_0(phone_id, LOADER_RUN); |
/* Run it. */ |
/* Load the program. */ |
rc = loader_run(ldr); |
if (rc != EOK) |
goto error; |
/* Success */ |
ipc_hangup(phone_id); |
free(ldr); |
return task_id; |
/* Error exit */ |
error: |
ipc_hangup(phone_id); |
loader_abort(ldr); |
free(ldr); |
return 0; |
} |
/branches/dynload/uspace/lib/libc/generic/loader.c |
---|
0,0 → 1,266 |
/* |
* 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 load the program. |
* |
* If this function succeeds, the program has been successfully loaded |
* and is ready to be executed. |
* |
* @param ldr Loader connection structure. |
* @return Zero on success or negative error code. |
*/ |
int loader_load_program(loader_t *ldr) |
{ |
int rc; |
rc = async_req_0_0(ldr->phone_id, LOADER_LOAD); |
if (rc != EOK) |
return rc; |
return EOK; |
} |
/** Instruct loader to execute the program. |
* |
* Note that this function blocks until the loader actually replies |
* so you cannot expect this function to return if you are debugging |
* the task and its thread is stopped. |
* |
* 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_run(loader_t *ldr) |
{ |
int rc; |
rc = async_req_0_0(ldr->phone_id, LOADER_RUN); |
if (rc != EOK) |
return rc; |
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; |
} |
/** @} |
*/ |
/branches/dynload/uspace/lib/libc/generic/udebug.c |
---|
57,10 → 57,16 |
int udebug_thread_read(int phoneid, void *buffer, size_t n, |
size_t *copied, size_t *needed) |
{ |
unsigned dest_addr; |
ipcarg_t a_copied, a_needed; |
int rc; |
return async_req_3_3(phoneid, IPC_M_DEBUG_ALL, UDEBUG_M_THREAD_READ, |
(sysarg_t)buffer, n, &dest_addr, copied, needed); |
rc = async_req_3_3(phoneid, IPC_M_DEBUG_ALL, UDEBUG_M_THREAD_READ, |
(sysarg_t)buffer, n, NULL, &a_copied, &a_needed); |
*copied = (size_t)a_copied; |
*needed = (size_t)a_needed; |
return rc; |
} |
int udebug_mem_read(int phoneid, void *buffer, uintptr_t addr, size_t n) |
78,8 → 84,14 |
int udebug_go(int phoneid, thash_t tid, udebug_event_t *ev_type, |
sysarg_t *val0, sysarg_t *val1) |
{ |
return async_req_2_3(phoneid, IPC_M_DEBUG_ALL, UDEBUG_M_GO, |
tid, (sysarg_t)ev_type, (sysarg_t)val0, (sysarg_t)val1); |
ipcarg_t a_ev_type; |
int rc; |
rc = async_req_2_3(phoneid, IPC_M_DEBUG_ALL, UDEBUG_M_GO, |
tid, &a_ev_type, val0, val1); |
*ev_type = a_ev_type; |
return rc; |
} |
int udebug_stop(int phoneid, thash_t tid) |
/branches/dynload/uspace/lib/libc/generic/vfs/vfs.c |
---|
599,6 → 599,7 |
cwd_path = pa; |
cwd_len = pa_len; |
futex_up(&cwd_futex); |
return EOK; |
} |
char *getcwd(char *buf, size_t size) |
/branches/dynload/uspace/lib/libc/Makefile |
---|
73,6 → 73,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 \ |