HelenOS sources
This source file includes following definitions.
- service_key_hash
- service_hash
- service_key_equal
- iface_key_hash
- iface_hash
- iface_key_equal
- ns_service_init
- ns_forward
- ns_pending_conn_process
- ns_iface_register
- ns_broker_register
- ns_service_register
- ns_service_register_broker
- ns_pending_conn_add
- ns_service_forward
#include <adt/hash_table.h>
#include <assert.h>
#include <async.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include "service.h"
#include "ns.h"
typedef struct {
ht_link_t link;
service_t service;
hash_table_t iface_hash_table;
async_sess_t *broker_sess;
} hashed_service_t;
typedef struct {
ht_link_t link;
iface_t iface;
async_sess_t *sess;
} hashed_iface_t;
static size_t service_key_hash(const void *key)
{
const service_t *srv = key;
return *srv;
}
static size_t service_hash(const ht_link_t *item)
{
hashed_service_t *service =
hash_table_get_inst(item, hashed_service_t, link);
return service->service;
}
static bool service_key_equal(const void *key, const ht_link_t *item)
{
const service_t *srv = key;
hashed_service_t *service =
hash_table_get_inst(item, hashed_service_t, link);
return service->service == *srv;
}
static size_t iface_key_hash(const void *key)
{
const iface_t *iface = key;
return *iface;
}
static size_t iface_hash(const ht_link_t *item)
{
hashed_iface_t *iface =
hash_table_get_inst(item, hashed_iface_t, link);
return iface->iface;
}
static bool iface_key_equal(const void *key, const ht_link_t *item)
{
const iface_t *kiface = key;
hashed_iface_t *iface =
hash_table_get_inst(item, hashed_iface_t, link);
return iface->iface == *kiface;
}
static const hash_table_ops_t service_hash_table_ops = {
.hash = service_hash,
.key_hash = service_key_hash,
.key_equal = service_key_equal,
.equal = NULL,
.remove_callback = NULL
};
static const hash_table_ops_t iface_hash_table_ops = {
.hash = iface_hash,
.key_hash = iface_key_hash,
.key_equal = iface_key_equal,
.equal = NULL,
.remove_callback = NULL
};
static hash_table_t service_hash_table;
typedef struct {
link_t link;
service_t service;
iface_t iface;
ipc_call_t call;
} pending_conn_t;
static list_t pending_conn;
errno_t ns_service_init(void)
{
if (!hash_table_create(&service_hash_table, 0, 0,
&service_hash_table_ops)) {
printf("%s: No memory available for services\n", NAME);
return ENOMEM;
}
list_initialize(&pending_conn);
return EOK;
}
static void ns_forward(async_sess_t *sess, ipc_call_t *call, iface_t iface)
{
async_exch_t *exch = async_exchange_begin(sess);
async_forward_1(call, exch, iface, ipc_get_arg3(call), IPC_FF_NONE);
async_exchange_end(exch);
}
void ns_pending_conn_process(void)
{
loop:
list_foreach(pending_conn, link, pending_conn_t, pending) {
ht_link_t *link =
hash_table_find(&service_hash_table, &pending->service);
if (!link)
continue;
hashed_service_t *hashed_service =
hash_table_get_inst(link, hashed_service_t, link);
link = hash_table_find(&hashed_service->iface_hash_table,
&pending->iface);
if (!link) {
if (hashed_service->broker_sess != NULL) {
ns_forward(hashed_service->broker_sess, &pending->call,
pending->iface);
list_remove(&pending->link);
free(pending);
goto loop;
}
continue;
}
hashed_iface_t *hashed_iface =
hash_table_get_inst(link, hashed_iface_t, link);
ns_forward(hashed_iface->sess, &pending->call, pending->iface);
list_remove(&pending->link);
free(pending);
goto loop;
}
}
static errno_t ns_iface_register(hashed_service_t *hashed_service, iface_t iface)
{
ht_link_t *link = hash_table_find(&hashed_service->iface_hash_table,
&iface);
if (link)
return EEXIST;
hashed_iface_t *hashed_iface =
(hashed_iface_t *) malloc(sizeof(hashed_iface_t));
if (!hashed_iface)
return ENOMEM;
hashed_iface->iface = iface;
hashed_iface->sess = async_callback_receive(EXCHANGE_SERIALIZE);
if (hashed_iface->sess == NULL) {
free(hashed_iface);
return EIO;
}
hash_table_insert(&hashed_service->iface_hash_table,
&hashed_iface->link);
return EOK;
}
static errno_t ns_broker_register(hashed_service_t *hashed_service)
{
if (hashed_service->broker_sess != NULL)
return EEXIST;
hashed_service->broker_sess = async_callback_receive(EXCHANGE_SERIALIZE);
if (hashed_service->broker_sess == NULL)
return EIO;
return EOK;
}
errno_t ns_service_register(service_t service, iface_t iface)
{
ht_link_t *link = hash_table_find(&service_hash_table, &service);
if (link) {
hashed_service_t *hashed_service =
hash_table_get_inst(link, hashed_service_t, link);
assert(hashed_service->service == service);
return ns_iface_register(hashed_service, iface);
}
hashed_service_t *hashed_service =
(hashed_service_t *) malloc(sizeof(hashed_service_t));
if (!hashed_service)
return ENOMEM;
if (!hash_table_create(&hashed_service->iface_hash_table, 0, 0,
&iface_hash_table_ops)) {
free(hashed_service);
return ENOMEM;
}
hashed_service->broker_sess = NULL;
hashed_service->service = service;
errno_t rc = ns_iface_register(hashed_service, iface);
if (rc != EOK) {
free(hashed_service);
return rc;
}
hash_table_insert(&service_hash_table, &hashed_service->link);
return EOK;
}
errno_t ns_service_register_broker(service_t service)
{
ht_link_t *link = hash_table_find(&service_hash_table, &service);
if (link) {
hashed_service_t *hashed_service =
hash_table_get_inst(link, hashed_service_t, link);
assert(hashed_service->service == service);
return ns_broker_register(hashed_service);
}
hashed_service_t *hashed_service =
(hashed_service_t *) malloc(sizeof(hashed_service_t));
if (!hashed_service)
return ENOMEM;
if (!hash_table_create(&hashed_service->iface_hash_table, 0, 0,
&iface_hash_table_ops)) {
free(hashed_service);
return ENOMEM;
}
hashed_service->broker_sess = NULL;
hashed_service->service = service;
errno_t rc = ns_broker_register(hashed_service);
if (rc != EOK) {
free(hashed_service);
return rc;
}
hash_table_insert(&service_hash_table, &hashed_service->link);
return EOK;
}
static errno_t ns_pending_conn_add(service_t service, iface_t iface,
ipc_call_t *call)
{
pending_conn_t *pending =
(pending_conn_t *) malloc(sizeof(pending_conn_t));
if (!pending)
return ENOMEM;
link_initialize(&pending->link);
pending->service = service;
pending->iface = iface;
pending->call = *call;
list_append(&pending->link, &pending_conn);
return EOK;
}
void ns_service_forward(service_t service, iface_t iface, ipc_call_t *call)
{
sysarg_t flags = ipc_get_arg4(call);
errno_t retval;
ht_link_t *link = hash_table_find(&service_hash_table, &service);
if (!link) {
if (flags & IPC_FLAG_BLOCKING) {
errno_t rc = ns_pending_conn_add(service, iface, call);
if (rc == EOK)
return;
retval = rc;
goto out;
}
retval = ENOENT;
goto out;
}
hashed_service_t *hashed_service =
hash_table_get_inst(link, hashed_service_t, link);
link = hash_table_find(&hashed_service->iface_hash_table, &iface);
if (!link) {
if (hashed_service->broker_sess != NULL) {
ns_forward(hashed_service->broker_sess, call, iface);
return;
}
if (flags & IPC_FLAG_BLOCKING) {
errno_t rc = ns_pending_conn_add(service, iface, call);
if (rc == EOK)
return;
retval = rc;
goto out;
}
retval = ENOENT;
goto out;
}
hashed_iface_t *hashed_iface =
hash_table_get_inst(link, hashed_iface_t, link);
ns_forward(hashed_iface->sess, call, iface);
return;
out:
async_answer_0(call, retval);
}
HelenOS homepage, sources at GitHub