Subversion Repositories HelenOS

Compare Revisions

Ignore whitespace Rev 4580 → Rev 4581

/branches/network/uspace/srv/ns/clonable.c
0,0 → 1,143
/*
* Copyright (c) 2009 Martin Decky
* 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 ns
* @{
*/
 
#include <ipc/ipc.h>
#include <ipc/services.h>
#include <adt/list.h>
#include <bool.h>
#include <errno.h>
#include <assert.h>
#include <stdio.h>
#include <malloc.h>
#include <loader/loader.h>
#include "clonable.h"
#include "ns.h"
 
/** 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;
 
int clonable_init(void)
{
list_initialize(&cs_req);
return EOK;
}
 
/** Return true if @a service is clonable. */
bool service_clonable(int service)
{
return (service == SERVICE_LOAD);
}
 
/** 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)
{
if (list_empty(&cs_req)) {
/* There was no pending connection request. */
printf(NAME ": Unexpected clonable server.\n");
ipc_answer_0(callid, EBUSY);
return;
}
cs_req_t *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);
ipc_forward_fast(csr->callid, phone, IPC_GET_ARG2(csr->call),
IPC_GET_ARG3(csr->call), 0, IPC_FF_NONE);
free(csr);
ipc_hangup(phone);
}
 
/** 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)
{
assert(service == SERVICE_LOAD);
cs_req_t *csr = malloc(sizeof(cs_req_t));
if (csr == NULL) {
ipc_answer_0(callid, ENOMEM);
return;
}
/* Spawn a loader. */
int 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);
}
 
/**
* @}
*/
/branches/network/uspace/srv/ns/ns.c
35,93 → 35,28
* @brief Naming service for HelenOS IPC.
*/
 
 
#include <ipc/ipc.h>
#include <ipc/services.h>
#include <ipc/ns.h>
#include <ipc/services.h>
#include <unistd.h>
#include <stdio.h>
#include <bool.h>
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>
#include <assert.h>
#include <libadt/list.h>
#include <libadt/hash_table.h>
#include <as.h>
#include <ddi.h>
#include <event.h>
#include <macros.h>
#include <sysinfo.h>
#include <loader/loader.h>
#include <ddi.h>
#include <as.h>
#include "ns.h"
#include "service.h"
#include "clonable.h"
#include "task.h"
 
#define NAME "ns"
 
#define NS_HASH_TABLE_CHAINS 20
 
static int register_service(ipcarg_t service, ipcarg_t phone, ipc_call_t *call);
static void 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);
static void ns_remove(link_t *item);
 
/** Operations for NS hash table. */
static hash_table_operations_t ns_hash_table_ops = {
.hash = ns_hash,
.compare = ns_compare,
.remove_callback = ns_remove
};
 
/** NS hash table structure. */
static hash_table_t ns_hash_table;
 
/** NS hash table item. */
typedef struct {
link_t link;
ipcarg_t service; /**< Number of the service. */
ipcarg_t phone; /**< Phone registered with the service. */
ipcarg_t in_phone_hash; /**< Incoming phone hash. */
} hashed_service_t;
 
/** Pending connection structure. */
typedef struct {
link_t link;
ipcarg_t service; /**< Number of the service. */
ipc_callid_t callid; /**< Call ID waiting for the connection */
ipcarg_t arg2; /**< Second argument */
ipcarg_t arg3; /**< Third argument */
} pending_req_t;
 
static link_t pending_req;
 
/** 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;
 
static void *clockaddr = NULL;
static void *klogaddr = NULL;
 
/** Return true if @a service is clonable. */
static bool service_clonable(int service)
static void get_as_area(ipc_callid_t callid, ipc_call_t *call, void *ph_addr,
size_t pages, void **addr)
{
return (service == SERVICE_LOAD);
}
 
static void get_as_area(ipc_callid_t callid, ipc_call_t *call, void *ph_addr, count_t pages, void **addr)
{
if (ph_addr == NULL) {
ipc_answer_0(callid, ENOENT);
return;
145,67 → 80,53
ipc_answer_2(callid, EOK, (ipcarg_t) *addr, AS_AREA_READ);
}
 
/** Process pending connection requests */
static void process_pending_req()
{
link_t *cur;
loop:
for (cur = pending_req.next; cur != &pending_req; cur = cur->next) {
pending_req_t *pr = list_get_instance(cur, pending_req_t, link);
unsigned long keys[3] = {
pr->service,
0,
0
};
link_t *link = hash_table_find(&ns_hash_table, keys);
if (!link)
continue;
hashed_service_t *hs = hash_table_get_instance(link, hashed_service_t, link);
ipcarg_t retval = ipc_forward_fast(pr->callid, hs->phone,
pr->arg2, pr->arg3, 0, IPC_FF_NONE);
if (!(pr->callid & IPC_CALLID_NOTIFICATION))
ipc_answer_0(pr->callid, retval);
list_remove(cur);
free(pr);
goto loop;
}
}
 
int main(int argc, char **argv)
{
printf(NAME ": HelenOS IPC Naming Service\n");
if (!hash_table_create(&ns_hash_table, NS_HASH_TABLE_CHAINS, 3,
&ns_hash_table_ops)) {
printf(NAME ": No memory available for services\n");
return ENOMEM;
}
int rc = service_init();
if (rc != EOK)
return rc;
list_initialize(&pending_req);
list_initialize(&cs_req);
rc = clonable_init();
if (rc != EOK)
return rc;
rc = task_init();
if (rc != EOK)
return rc;
printf(NAME ": Accepting connections\n");
while (true) {
process_pending_req();
process_pending_conn();
process_pending_wait();
ipc_call_t call;
ipc_callid_t callid = ipc_wait_for_call(&call);
task_id_t id;
ipcarg_t retval;
if (callid & IPC_CALLID_NOTIFICATION) {
id = (task_id_t)
MERGE_LOUP32(IPC_GET_ARG2(call), IPC_GET_ARG3(call));
wait_notification((wait_type_t) IPC_GET_ARG1(call), id);
continue;
}
switch (IPC_GET_METHOD(call)) {
case IPC_M_SHARE_IN:
switch (IPC_GET_ARG3(call)) {
case SERVICE_MEM_REALTIME:
get_as_area(callid, &call, sysinfo_value("clock.faddr"), 1, &clockaddr);
get_as_area(callid, &call,
(void *) sysinfo_value("clock.faddr"),
1, &clockaddr);
break;
case SERVICE_MEM_KLOG:
get_as_area(callid, &call, sysinfo_value("klog.faddr"), sysinfo_value("klog.pages"), &klogaddr);
get_as_area(callid, &call,
(void *) sysinfo_value("klog.faddr"),
sysinfo_value("klog.pages"), &klogaddr);
break;
default:
ipc_answer_0(callid, ENOENT);
241,6 → 162,14
continue;
}
break;
case NS_PING:
retval = EOK;
break;
case NS_TASK_WAIT:
id = (task_id_t)
MERGE_LOUP32(IPC_GET_ARG1(call), IPC_GET_ARG2(call));
wait_for_task(id, &call, callid);
continue;
default:
retval = ENOENT;
break;
254,213 → 183,6
return 0;
}
 
/** 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.
*
* @return Zero on success or a value from @ref errno.h.
*
*/
int register_service(ipcarg_t service, ipcarg_t phone, ipc_call_t *call)
{
unsigned long keys[3] = {
service,
call->in_phone_hash,
0
};
if (hash_table_find(&ns_hash_table, keys))
return EEXISTS;
hashed_service_t *hs = (hashed_service_t *) malloc(sizeof(hashed_service_t));
if (!hs)
return ENOMEM;
link_initialize(&hs->link);
hs->service = service;
hs->phone = phone;
hs->in_phone_hash = call->in_phone_hash;
hash_table_insert(&ns_hash_table, keys, &hs->link);
return 0;
}
 
/** Connect client to 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_service(ipcarg_t service, ipc_call_t *call, ipc_callid_t callid)
{
ipcarg_t retval;
unsigned long keys[3] = {
service,
0,
0
};
link_t *link = hash_table_find(&ns_hash_table, keys);
if (!link) {
if (IPC_GET_ARG4(*call) & IPC_FLAG_BLOCKING) {
/* Blocking connection, add to pending list */
pending_req_t *pr = (pending_req_t *) malloc(sizeof(pending_req_t));
if (!pr) {
retval = ENOMEM;
goto out;
}
pr->service = service;
pr->callid = callid;
pr->arg2 = IPC_GET_ARG2(*call);
pr->arg3 = IPC_GET_ARG3(*call);
list_append(&pr->link, &pending_req);
return;
}
retval = ENOENT;
goto out;
}
hashed_service_t *hs = hash_table_get_instance(link, hashed_service_t, link);
retval = ipc_forward_fast(callid, hs->phone, IPC_GET_ARG2(*call),
IPC_GET_ARG3(*call), 0, IPC_FF_NONE);
out:
if (!(callid & IPC_CALLID_NOTIFICATION))
ipc_answer_0(callid, retval);
}
 
/** 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)
{
if (list_empty(&cs_req)) {
/* There was no pending connection request. */
printf(NAME ": Unexpected clonable server.\n");
ipc_answer_0(callid, EBUSY);
return;
}
cs_req_t *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);
int rc = ipc_forward_fast(csr->callid, phone, IPC_GET_ARG2(csr->call),
IPC_GET_ARG3(csr->call), 0, IPC_FF_NONE);
 
free(csr);
ipc_hangup(phone);
}
 
/** 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)
{
assert(service == SERVICE_LOAD);
cs_req_t *csr = malloc(sizeof(cs_req_t));
if (csr == NULL) {
ipc_answer_0(callid, ENOMEM);
return;
}
/* Spawn a loader. */
int 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)
* is used to compute the hash index.
*
* @return Hash index corresponding to key[0].
*
*/
hash_index_t ns_hash(unsigned long *key)
{
assert(key);
return (*key % NS_HASH_TABLE_CHAINS);
}
 
/** Compare a key with hashed item.
*
* This compare function always ignores the third key.
* It exists only to make it possible to remove records
* originating from connection with key[1] in_phone_hash
* value. Note that this is close to being classified
* as a nasty hack.
*
* @param key Array of keys.
* @param keys Must be lesser or equal to 3.
* @param item Pointer to a hash table item.
*
* @return Non-zero if the key matches the item, zero otherwise.
*
*/
int ns_compare(unsigned long key[], hash_count_t keys, link_t *item)
{
assert(key);
assert(keys <= 3);
assert(item);
hashed_service_t *hs = hash_table_get_instance(item, hashed_service_t, link);
if (keys == 2)
return key[1] == hs->in_phone_hash;
else
return key[0] == hs->service;
}
 
/** Perform actions after removal of item from the hash table.
*
* @param item Item that was removed from the hash table.
*
*/
void ns_remove(link_t *item)
{
assert(item);
free(hash_table_get_instance(item, hashed_service_t, link));
}
 
/**
* @}
*/
/branches/network/uspace/srv/ns/service.c
0,0 → 1,254
/*
* Copyright (c) 2009 Martin Decky
* 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 ns
* @{
*/
 
#include <ipc/ipc.h>
#include <adt/hash_table.h>
#include <assert.h>
#include <errno.h>
#include "service.h"
#include "ns.h"
 
#define SERVICE_HASH_TABLE_CHAINS 20
 
/** Service hash table item. */
typedef struct {
link_t link;
ipcarg_t service; /**< Number of the service. */
ipcarg_t phone; /**< Phone registered with the service. */
ipcarg_t in_phone_hash; /**< Incoming phone hash. */
} hashed_service_t;
 
/** Compute hash index into service hash table.
*
* @param key Pointer keys. However, only the first key (i.e. service number)
* is used to compute the hash index.
*
* @return Hash index corresponding to key[0].
*
*/
static hash_index_t service_hash(unsigned long *key)
{
assert(key);
return (*key % SERVICE_HASH_TABLE_CHAINS);
}
 
/** Compare a key with hashed item.
*
* This compare function always ignores the third key.
* It exists only to make it possible to remove records
* originating from connection with key[1] in_phone_hash
* value. Note that this is close to being classified
* as a nasty hack.
*
* @param key Array of keys.
* @param keys Must be lesser or equal to 3.
* @param item Pointer to a hash table item.
*
* @return Non-zero if the key matches the item, zero otherwise.
*
*/
static int service_compare(unsigned long key[], hash_count_t keys, link_t *item)
{
assert(key);
assert(keys <= 3);
assert(item);
hashed_service_t *hs = hash_table_get_instance(item, hashed_service_t, link);
if (keys == 2)
return (key[1] == hs->in_phone_hash);
else
return (key[0] == hs->service);
}
 
/** Perform actions after removal of item from the hash table.
*
* @param item Item that was removed from the hash table.
*
*/
static void service_remove(link_t *item)
{
assert(item);
free(hash_table_get_instance(item, hashed_service_t, link));
}
 
/** Operations for service hash table. */
static hash_table_operations_t service_hash_table_ops = {
.hash = service_hash,
.compare = service_compare,
.remove_callback = service_remove
};
 
/** Service hash table structure. */
static hash_table_t service_hash_table;
 
/** Pending connection structure. */
typedef struct {
link_t link;
ipcarg_t service; /**< Number of the service. */
ipc_callid_t callid; /**< Call ID waiting for the connection */
ipcarg_t arg2; /**< Second argument */
ipcarg_t arg3; /**< Third argument */
} pending_conn_t;
 
static link_t pending_conn;
 
int service_init(void)
{
if (!hash_table_create(&service_hash_table, SERVICE_HASH_TABLE_CHAINS,
3, &service_hash_table_ops)) {
printf(NAME ": No memory available for services\n");
return ENOMEM;
}
list_initialize(&pending_conn);
return EOK;
}
 
/** Process pending connection requests */
void process_pending_conn(void)
{
link_t *cur;
loop:
for (cur = pending_conn.next; cur != &pending_conn; cur = cur->next) {
pending_conn_t *pr = list_get_instance(cur, pending_conn_t, link);
unsigned long keys[3] = {
pr->service,
0,
0
};
link_t *link = hash_table_find(&service_hash_table, keys);
if (!link)
continue;
hashed_service_t *hs = hash_table_get_instance(link, hashed_service_t, link);
ipcarg_t retval = ipc_forward_fast(pr->callid, hs->phone,
pr->arg2, pr->arg3, 0, IPC_FF_NONE);
if (!(pr->callid & IPC_CALLID_NOTIFICATION))
ipc_answer_0(pr->callid, retval);
list_remove(cur);
free(pr);
goto loop;
}
}
 
/** 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.
*
* @return Zero on success or a value from @ref errno.h.
*
*/
int register_service(ipcarg_t service, ipcarg_t phone, ipc_call_t *call)
{
unsigned long keys[3] = {
service,
call->in_phone_hash,
0
};
if (hash_table_find(&service_hash_table, keys))
return EEXISTS;
hashed_service_t *hs = (hashed_service_t *) malloc(sizeof(hashed_service_t));
if (!hs)
return ENOMEM;
link_initialize(&hs->link);
hs->service = service;
hs->phone = phone;
hs->in_phone_hash = call->in_phone_hash;
hash_table_insert(&service_hash_table, keys, &hs->link);
return 0;
}
 
/** Connect client to 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_service(ipcarg_t service, ipc_call_t *call, ipc_callid_t callid)
{
ipcarg_t retval;
unsigned long keys[3] = {
service,
0,
0
};
link_t *link = hash_table_find(&service_hash_table, keys);
if (!link) {
if (IPC_GET_ARG4(*call) & IPC_FLAG_BLOCKING) {
/* Blocking connection, add to pending list */
pending_conn_t *pr =
(pending_conn_t *) malloc(sizeof(pending_conn_t));
if (!pr) {
retval = ENOMEM;
goto out;
}
pr->service = service;
pr->callid = callid;
pr->arg2 = IPC_GET_ARG2(*call);
pr->arg3 = IPC_GET_ARG3(*call);
list_append(&pr->link, &pending_conn);
return;
}
retval = ENOENT;
goto out;
}
hashed_service_t *hs = hash_table_get_instance(link, hashed_service_t, link);
retval = ipc_forward_fast(callid, hs->phone, IPC_GET_ARG2(*call),
IPC_GET_ARG3(*call), 0, IPC_FF_NONE);
out:
if (!(callid & IPC_CALLID_NOTIFICATION))
ipc_answer_0(callid, retval);
}
 
/**
* @}
*/
/branches/network/uspace/srv/ns/task.c
0,0 → 1,269
/*
* Copyright (c) 2009 Martin Decky
* 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 ns
* @{
*/
 
#include <ipc/ipc.h>
#include <adt/hash_table.h>
#include <bool.h>
#include <errno.h>
#include <assert.h>
#include <stdio.h>
#include <macros.h>
#include "task.h"
#include "ns.h"
 
#define TASK_HASH_TABLE_CHAINS 256
 
/* TODO:
*
* The current implementation of waiting on a task is not perfect. If somebody
* wants to wait on a task which has already finished before the NS asked
* the kernel to receive notifications, it would block indefinitively.
*
* A solution to this is to fail immediately on a task for which no creation
* notification was received yet. However, there is a danger of a race condition
* in this solution -- the caller has to make sure that it is not trying to wait
* before the NS has a change to receive the task creation notification. This
* can be assured by waiting for this event in task_spawn().
*
* Finally, as there is currently no convention that each task has to be waited
* for, the NS can leak memory because of the zombie tasks.
*
*/
 
/** Task hash table item. */
typedef struct {
link_t link;
task_id_t id; /**< Task ID. */
bool destroyed;
} hashed_task_t;
 
/** Compute hash index into task hash table.
*
* @param key Pointer keys. However, only the first key (i.e. truncated task
* number) is used to compute the hash index.
*
* @return Hash index corresponding to key[0].
*
*/
static hash_index_t task_hash(unsigned long *key)
{
assert(key);
return (LOWER32(*key) % TASK_HASH_TABLE_CHAINS);
}
 
/** Compare a key with hashed item.
*
* @param key Array of keys.
* @param keys Must be lesser or equal to 2.
* @param item Pointer to a hash table item.
*
* @return Non-zero if the key matches the item, zero otherwise.
*
*/
static int task_compare(unsigned long key[], hash_count_t keys, link_t *item)
{
assert(key);
assert(keys <= 2);
assert(item);
hashed_task_t *ht = hash_table_get_instance(item, hashed_task_t, link);
if (keys == 2)
return ((LOWER32(key[1]) == UPPER32(ht->id))
&& (LOWER32(key[0]) == LOWER32(ht->id)));
else
return (LOWER32(key[0]) == LOWER32(ht->id));
}
 
/** Perform actions after removal of item from the hash table.
*
* @param item Item that was removed from the hash table.
*
*/
static void task_remove(link_t *item)
{
assert(item);
free(hash_table_get_instance(item, hashed_task_t, link));
}
 
/** Operations for task hash table. */
static hash_table_operations_t task_hash_table_ops = {
.hash = task_hash,
.compare = task_compare,
.remove_callback = task_remove
};
 
/** Task hash table structure. */
static hash_table_t task_hash_table;
 
/** Pending task wait structure. */
typedef struct {
link_t link;
task_id_t id; /**< Task ID. */
ipc_callid_t callid; /**< Call ID waiting for the connection */
} pending_wait_t;
 
static link_t pending_wait;
 
int task_init(void)
{
if (!hash_table_create(&task_hash_table, TASK_HASH_TABLE_CHAINS,
2, &task_hash_table_ops)) {
printf(NAME ": No memory available for tasks\n");
return ENOMEM;
}
if (event_subscribe(EVENT_WAIT, 0) != EOK)
printf(NAME ": Error registering wait notifications\n");
list_initialize(&pending_wait);
return EOK;
}
 
/** Process pending wait requests */
void process_pending_wait(void)
{
link_t *cur;
loop:
for (cur = pending_wait.next; cur != &pending_wait; cur = cur->next) {
pending_wait_t *pr = list_get_instance(cur, pending_wait_t, link);
unsigned long keys[2] = {
LOWER32(pr->id),
UPPER32(pr->id)
};
link_t *link = hash_table_find(&task_hash_table, keys);
if (!link)
continue;
hashed_task_t *ht = hash_table_get_instance(link, hashed_task_t, link);
if (!ht->destroyed)
continue;
if (!(pr->callid & IPC_CALLID_NOTIFICATION))
ipc_answer_0(pr->callid, EOK);
hash_table_remove(&task_hash_table, keys, 2);
list_remove(cur);
free(pr);
goto loop;
}
}
 
static void fail_pending_wait(task_id_t id, int rc)
{
link_t *cur;
loop:
for (cur = pending_wait.next; cur != &pending_wait; cur = cur->next) {
pending_wait_t *pr = list_get_instance(cur, pending_wait_t, link);
if (pr->id == id) {
if (!(pr->callid & IPC_CALLID_NOTIFICATION))
ipc_answer_0(pr->callid, rc);
list_remove(cur);
free(pr);
goto loop;
}
}
}
 
void wait_notification(wait_type_t et, task_id_t id)
{
unsigned long keys[2] = {
LOWER32(id),
UPPER32(id)
};
link_t *link = hash_table_find(&task_hash_table, keys);
if (link == NULL) {
hashed_task_t *ht =
(hashed_task_t *) malloc(sizeof(hashed_task_t));
if (ht == NULL) {
fail_pending_wait(id, ENOMEM);
return;
}
link_initialize(&ht->link);
ht->id = id;
ht->destroyed = (et == TASK_CREATE) ? false : true;
hash_table_insert(&task_hash_table, keys, &ht->link);
} else {
hashed_task_t *ht =
hash_table_get_instance(link, hashed_task_t, link);
ht->destroyed = (et == TASK_CREATE) ? false : true;
}
}
 
void wait_for_task(task_id_t id, ipc_call_t *call, ipc_callid_t callid)
{
ipcarg_t retval;
unsigned long keys[2] = {
LOWER32(id),
UPPER32(id)
};
link_t *link = hash_table_find(&task_hash_table, keys);
hashed_task_t *ht = (link != NULL) ?
hash_table_get_instance(link, hashed_task_t, link) : NULL;
if ((ht == NULL) || (!ht->destroyed)) {
/* Add to pending list */
pending_wait_t *pr =
(pending_wait_t *) malloc(sizeof(pending_wait_t));
if (!pr) {
retval = ENOMEM;
goto out;
}
pr->id = id;
pr->callid = callid;
list_append(&pr->link, &pending_wait);
return;
}
hash_table_remove(&task_hash_table, keys, 2);
retval = EOK;
out:
if (!(callid & IPC_CALLID_NOTIFICATION))
ipc_answer_0(callid, retval);
}
 
/**
* @}
*/
/branches/network/uspace/srv/ns/clonable.h
0,0 → 1,51
/*
* Copyright (c) 2009 Martin Decky
* 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 ns
* @{
*/
 
#ifndef NS_CLONABLE_H__
#define NS_CLONABLE_H__
 
#include <ipc/ipc.h>
#include <bool.h>
 
extern int clonable_init(void);
 
extern bool service_clonable(int service);
extern void register_clonable(ipcarg_t service, ipcarg_t phone,
ipc_call_t *call, ipc_callid_t callid);
extern void connect_to_clonable(ipcarg_t service, ipc_call_t *call,
ipc_callid_t callid);
 
#endif
 
/**
* @}
*/
/branches/network/uspace/srv/ns/ns.h
0,0 → 1,42
/*
* Copyright (c) 2009 Martin Decky
* 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 ns
* @{
*/
 
#ifndef NS_NS_H__
#define NS_NS_H__
 
#define NAME "ns"
 
#endif
 
/**
* @}
*/
/branches/network/uspace/srv/ns/service.h
0,0 → 1,49
/*
* Copyright (c) 2009 Martin Decky
* 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 ns
* @{
*/
 
#ifndef NS_SERVICE_H__
#define NS_SERVICE_H__
 
#include <ipc/ipc.h>
 
extern int service_init(void);
extern void process_pending_conn(void);
 
extern int register_service(ipcarg_t service, ipcarg_t phone, ipc_call_t *call);
extern void connect_to_service(ipcarg_t service, ipc_call_t *call,
ipc_callid_t callid);
 
#endif
 
/**
* @}
*/
/branches/network/uspace/srv/ns/task.h
0,0 → 1,49
/*
* Copyright (c) 2009 Martin Decky
* 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 ns
* @{
*/
 
#ifndef NS_TASK_H__
#define NS_TASK_H__
 
#include <ipc/ipc.h>
#include <event.h>
 
extern int task_init(void);
extern void process_pending_wait(void);
 
extern void wait_notification(wait_type_t et, task_id_t id);
extern void wait_for_task(task_id_t id, ipc_call_t *call, ipc_callid_t callid);
 
#endif
 
/**
* @}
*/
/branches/network/uspace/srv/ns/Makefile
41,7 → 41,10
 
OUTPUT = ns
SOURCES = \
ns.c
ns.c \
service.c \
clonable.c \
task.c
 
OBJECTS := $(addsuffix .o,$(basename $(SOURCES)))
 
63,7 → 66,7
disasm: $(OUTPUT).disasm
 
$(OUTPUT).disasm: $(OUTPUT)
$(OBJDUMP) -d $< >$@
$(OBJDUMP) -d $< > $@
 
%.o: %.S
$(CC) $(DEFS) $(AFLAGS) $(CFLAGS) -D__ASM__ -c $< -o $@