Subversion Repositories HelenOS

Compare Revisions

Ignore whitespace Rev 3895 → Rev 3896

/trunk/kernel/generic/include/proc/program.h
59,8 → 59,7
extern int program_create_loader(program_t *p, char *name);
extern void program_ready(program_t *p);
 
extern unative_t sys_program_spawn_loader(int *uspace_phone_id,
char *uspace_name, size_t name_len);
extern unative_t sys_program_spawn_loader(char *uspace_name, size_t name_len);
 
#endif
 
/trunk/kernel/generic/src/proc/program.c
190,32 → 190,20
 
/** Syscall for creating a new loader instance from userspace.
*
* Creates a new task from the program loader image, connects a phone
* to it and stores the phone id into the provided buffer.
* Creates a new task from the program loader image and sets
* the task name.
*
* @param uspace_phone_id Userspace address where to store the phone id.
* @param name Name to set on the new task (typically the same
* as the command used to execute it).
*
* @return 0 on success or an error code from @ref errno.h.
*/
unative_t sys_program_spawn_loader(int *uspace_phone_id, char *uspace_name,
size_t name_len)
unative_t sys_program_spawn_loader(char *uspace_name, size_t name_len)
{
program_t p;
int fake_id;
int rc;
int phone_id;
char namebuf[TASK_NAME_BUFLEN];
 
fake_id = 0;
 
/* Before we even try creating the task, see if we can write the id */
rc = (unative_t) copy_to_uspace(uspace_phone_id, &fake_id,
sizeof(fake_id));
if (rc != 0)
return rc;
 
/* Cap length of name and copy it from userspace. */
 
if (name_len > THREAD_NAME_BUFLEN - 1)
227,12 → 215,6
 
namebuf[name_len] = '\0';
 
/* Allocate the phone for communicating with the new task. */
 
phone_id = phone_alloc();
if (phone_id < 0)
return ELIMIT;
 
/* Spawn the new task. */
 
rc = program_create_loader(&p, namebuf);
239,18 → 221,6
if (rc != 0)
return rc;
 
phone_connect(phone_id, &p.task->answerbox);
 
/* No need to aquire lock before task_ready() */
rc = (unative_t) copy_to_uspace(uspace_phone_id, &phone_id,
sizeof(phone_id));
if (rc != 0) {
/* Ooops */
ipc_phone_hangup(&TASK->phones[phone_id]);
task_kill(p.task->taskid);
return rc;
}
 
// FIXME: control the capabilities
cap_set(p.task, cap_get(TASK));
 
/trunk/uspace/lib/libc/include/loader/loader.h
44,7 → 44,8
int phone_id;
} loader_t;
 
extern loader_t *loader_spawn(const char *name);
extern int loader_spawn(const char *);
extern loader_t *loader_connect(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 []);
/trunk/uspace/lib/libc/include/ipc/services.h
38,7 → 38,8
#define LIBIPC_SERVICES_H_
 
typedef enum {
SERVICE_PCI = 1,
SERVICE_LOAD = 1,
SERVICE_PCI,
SERVICE_KEYBOARD,
SERVICE_VIDEO,
SERVICE_CONSOLE,
/trunk/uspace/lib/libc/generic/task.c
63,8 → 63,8
task_id_t task_id;
int rc;
 
/* Spawn a program loader. */
ldr = loader_spawn(path);
/* Connect to a program loader. */
ldr = loader_connect();
if (ldr == NULL)
return 0;
 
89,7 → 89,6
goto error;
 
/* Run it. */
/* Load the program. */
rc = loader_run(ldr);
if (rc != EOK)
goto error;
/trunk/uspace/lib/libc/generic/loader.c
34,6 → 34,7
 
#include <ipc/ipc.h>
#include <ipc/loader.h>
#include <ipc/services.h>
#include <libc.h>
#include <task.h>
#include <string.h>
50,33 → 51,27
* @return Pointer to the loader connection structure (should be
* de-allocated using free() after use).
*/
loader_t *loader_spawn(const char *name)
int loader_spawn(const char *name)
{
int phone_id, rc;
return __SYSCALL2(SYS_PROGRAM_SPAWN_LOADER,
(sysarg_t) name, strlen(name));
}
 
loader_t *loader_connect(void)
{
loader_t *ldr;
int phone_id;
 
/*
* Ask kernel to spawn a new loader task.
*/
rc = __SYSCALL3(SYS_PROGRAM_SPAWN_LOADER, (sysarg_t) &phone_id,
(sysarg_t) name, strlen(name));
if (rc != 0)
phone_id = ipc_connect_me_to(PHONE_NS, SERVICE_LOAD, 0, 0);
if (phone_id < 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;
return ldr;
}
 
/** Get ID of the new task.
/trunk/uspace/srv/ns/ns.c
40,6 → 40,7
#include <ipc/ns.h>
#include <ipc/services.h>
#include <stdio.h>
#include <bool.h>
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>
47,6 → 48,7
#include <libadt/list.h>
#include <libadt/hash_table.h>
#include <sysinfo.h>
#include <loader/loader.h>
#include <ddi.h>
#include <as.h>
 
58,6 → 60,11
static int connect_to_service(ipcarg_t service, ipc_call_t *call,
ipc_callid_t callid);
 
void register_clonable(ipcarg_t service, ipcarg_t phone, ipc_call_t *call,
ipc_callid_t callid);
void connect_to_clonable(ipcarg_t service, ipc_call_t *call,
ipc_callid_t callid);
 
/* Static functions implementing NS hash table operations. */
static hash_index_t ns_hash(unsigned long *key);
static int ns_compare(unsigned long *key, hash_count_t keys, link_t *item);
84,6 → 91,23
static void *clockaddr = NULL;
static void *klogaddr = NULL;
 
/** Request for connection to a clonable service. */
typedef struct {
link_t link;
ipcarg_t service;
ipc_call_t *call;
ipc_callid_t callid;
} cs_req_t;
 
/** List of clonable-service connection requests. */
static link_t cs_req;
 
/** Return true if @a service is clonable. */
static bool service_clonable(int service)
{
return service == SERVICE_LOAD;
}
 
static void get_as_area(ipc_callid_t callid, ipc_call_t *call, char *name,
void **addr)
{
116,6 → 140,8
printf(NAME ": No memory available\n");
return ENOMEM;
}
 
list_initialize(&cs_req);
printf(NAME ": Accepting connections\n");
while (1) {
142,15 → 168,27
/*
* Server requests service registration.
*/
retval = register_service(IPC_GET_ARG1(call),
IPC_GET_ARG5(call), &call);
if (service_clonable(IPC_GET_ARG1(call))) {
register_clonable(IPC_GET_ARG1(call),
IPC_GET_ARG5(call), &call, callid);
continue;
} else {
retval = register_service(IPC_GET_ARG1(call),
IPC_GET_ARG5(call), &call);
}
break;
case IPC_M_CONNECT_ME_TO:
/*
* Client requests to be connected to a service.
*/
retval = connect_to_service(IPC_GET_ARG1(call), &call,
callid);
if (service_clonable(IPC_GET_ARG1(call))) {
connect_to_clonable(IPC_GET_ARG1(call),
&call, callid);
continue;
} else {
retval = connect_to_service(IPC_GET_ARG1(call),
&call, callid);
}
break;
default:
retval = ENOENT;
167,11 → 205,11
 
/** Register service.
*
* @param service Service to be registered.
* @param phone Phone to be used for connections to the service.
* @param call Pointer to call structure.
* @param service Service to be registered.
* @param phone Phone to be used for connections to the service.
* @param call Pointer to call structure.
*
* @return Zero on success or a value from @ref errno.h.
* @return Zero on success or a value from @ref errno.h.
*/
int register_service(ipcarg_t service, ipcarg_t phone, ipc_call_t *call)
{
181,7 → 219,7
0
};
hashed_service_t *hs;
 
if (hash_table_find(&ns_hash_table, keys)) {
return EEXISTS;
}
202,9 → 240,9
 
/** Connect client to service.
*
* @param service Service to be connected to.
* @param call Pointer to call structure.
* @param callid Call ID of the request.
* @param service Service to be connected to.
* @param call Pointer to call structure.
* @param callid Call ID of the request.
*
* @return Zero on success or a value from @ref errno.h.
*/
213,7 → 251,7
unsigned long keys[3] = { service, 0, 0 };
link_t *hlp;
hashed_service_t *hs;
 
hlp = hash_table_find(&ns_hash_table, keys);
if (!hlp) {
return ENOENT;
223,6 → 261,82
IPC_GET_ARG3(*call), 0, IPC_FF_NONE);
}
 
/** Register clonable service.
*
* @param service Service to be registered.
* @param phone Phone to be used for connections to the service.
* @param call Pointer to call structure.
*/
void register_clonable(ipcarg_t service, ipcarg_t phone, ipc_call_t *call,
ipc_callid_t callid)
{
int rc;
cs_req_t *csr;
 
if (list_empty(&cs_req)) {
/* There was no pending connection request. */
printf(NAME ": Unexpected clonable server.\n");
ipc_answer_0(callid, EBUSY);
return;
}
 
csr = list_get_instance(cs_req.next, cs_req_t, link);
list_remove(&csr->link);
 
/* Currently we can only handle a single type of clonable service. */
assert(csr->service == SERVICE_LOAD);
 
ipc_answer_0(callid, EOK);
 
rc = ipc_forward_fast(csr->callid, phone, IPC_GET_ARG2(*csr->call),
IPC_GET_ARG3(*csr->call), 0, IPC_FF_NONE);
 
free(csr);
}
 
/** Connect client to clonable service.
*
* @param service Service to be connected to.
* @param call Pointer to call structure.
* @param callid Call ID of the request.
*
* @return Zero on success or a value from @ref errno.h.
*/
void connect_to_clonable(ipcarg_t service, ipc_call_t *call,
ipc_callid_t callid)
{
int rc;
cs_req_t *csr;
 
assert(service == SERVICE_LOAD);
 
csr = malloc(sizeof(cs_req_t));
if (csr == NULL) {
ipc_answer_0(callid, ENOMEM);
return;
}
 
/* Spawn a loader. */
rc = loader_spawn("loader");
 
if (rc < 0) {
free(csr);
ipc_answer_0(callid, rc);
return;
}
 
csr->service = service;
csr->call = call;
csr->callid = callid;
 
/*
* We can forward the call only after the server we spawned connects
* to us. Meanwhile we might need to service more connection requests.
* Thus we store the call in a queue.
*/
list_append(&csr->link, &cs_req);
}
 
/** Compute hash index into NS hash table.
*
* @param key Pointer keys. However, only the first key (i.e. service number)
/trunk/uspace/srv/loader/main.c
50,6 → 50,7
#include <fcntl.h>
#include <sys/types.h>
#include <ipc/ipc.h>
#include <ipc/services.h>
#include <ipc/loader.h>
#include <loader/pcb.h>
#include <errno.h>
79,6 → 80,8
 
static bool is_dyn_linked;
 
/** Used to limit number of connections to one. */
static bool connected;
 
static void loader_get_taskid(ipc_callid_t rid, ipc_call_t *request)
{
297,6 → 300,17
ipc_call_t call;
int retval;
 
/* Already have a connection? */
if (connected) {
ipc_answer_0(iid, ELIMIT);
return;
}
 
connected = true;
/* Accept the connection */
ipc_answer_0(iid, EOK);
 
/* Ignore parameters, the connection is already open */
(void)iid; (void)icall;
 
338,31 → 352,20
*/
int main(int argc, char *argv[])
{
ipc_callid_t callid;
ipc_call_t call;
ipcarg_t phone_hash;
ipcarg_t phonead;
 
/* The first call only communicates the incoming phone hash */
callid = ipc_wait_for_call(&call);
connected = false;
/* Set a handler of incomming connections. */
async_set_client_connection(loader_connection);
 
if (IPC_GET_METHOD(call) != LOADER_HELLO) {
if (IPC_GET_METHOD(call) != IPC_M_PHONE_HUNGUP)
ipc_answer_0(callid, EINVAL);
return 1;
}
 
ipc_answer_0(callid, EOK);
phone_hash = call.in_phone_hash;
 
/*
* Up until now async must not be used as it couldn't
* handle incoming requests. (Which means e.g. printf()
* cannot be used)
*/
async_new_connection(phone_hash, 0, NULL, loader_connection);
/* Register at naming service. */
if (ipc_connect_to_me(PHONE_NS, SERVICE_LOAD, 0, 0, &phonead) != 0)
return -1;
async_manager();
 
/* not reached */
/* Never reached */
return 0;
}