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, size_t hash,
    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, size_t hash, 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