root/usr/src/lib/udapl/libdat/common/dat_dr.c
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License, Version 1.0 only
 * (the "License").  You may not use this file except in compliance
 * with the License.
 *
 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
 * or http://www.opensolaris.org/os/licensing.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
 * If applicable, add the following below this CDDL HEADER, with the
 * fields enclosed by brackets "[]" replaced with your own identifying
 * information: Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 */
/*
 * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved.
 */

/*
 * Copyright 2003 Sun Microsystems, Inc.  All rights reserved.
 * Use is subject to license terms.
 */

/*
 *
 * MODULE: dat_dr.c
 *
 * PURPOSE: dynamic registry implementation
 *
 * $Id: dat_dr.c,v 1.12 2003/08/20 14:28:40 hobie16 Exp $
 */


#include "dat_dr.h"

#include "dat_dictionary.h"


/*
 *
 * Global Variables
 *
 */

static DAT_OS_LOCK              g_dr_lock;
static DAT_DICTIONARY           *g_dr_dictionary = NULL;


/*
 *
 * External Functions
 *
 */


/*
 * Function: dat_dr_init
 */

DAT_RETURN
dat_dr_init(void)
{
        DAT_RETURN      status;

        status = dat_os_lock_init(&g_dr_lock);
        if (DAT_SUCCESS != status) {
                return (status);
        }

        status = dat_dictionary_create(&g_dr_dictionary);
        if (DAT_SUCCESS != status) {
                return (status);
        }

        return (DAT_SUCCESS);
}


/*
 * Function: dat_dr_fini
 */

DAT_RETURN
dat_dr_fini(void)
{
        DAT_RETURN                      status;

        status = dat_os_lock_destroy(&g_dr_lock);
        if (DAT_SUCCESS != status) {
                return (status);
        }

        status = dat_dictionary_destroy(g_dr_dictionary);
        if (DAT_SUCCESS != status) {
                return (status);
        }

        return (DAT_SUCCESS);
}


/*
 * Function: dat_dr_insert
 */

extern DAT_RETURN
dat_dr_insert(
    IN  const DAT_PROVIDER_INFO *info,
    IN  DAT_DR_ENTRY            *entry)
{
        DAT_RETURN              status;
        DAT_DICTIONARY_ENTRY    dict_entry;
        DAT_DR_ENTRY            *data;

        data = dat_os_alloc(sizeof (DAT_DR_ENTRY));
        if (NULL == data) {
                status = DAT_ERROR(DAT_INSUFFICIENT_RESOURCES,
                    DAT_RESOURCE_MEMORY);
                goto bail;
        }

        *data = *entry;

        dict_entry = NULL;
        status = dat_dictionary_entry_create(&dict_entry);
        if (DAT_SUCCESS != status) {
                goto bail;
        }

        dat_os_lock(&g_dr_lock);

        status = dat_dictionary_insert(g_dr_dictionary,
                dict_entry,
                info,
                (DAT_DICTIONARY_DATA *) data);

        dat_os_unlock(&g_dr_lock);

bail:
        if (DAT_SUCCESS != status) {
                if (NULL != data) {
                        dat_os_free(data, sizeof (DAT_DR_ENTRY));
                }


                if (NULL != dict_entry) {
                        (void) dat_dictionary_entry_destroy(dict_entry);
                }
        }

        return (status);
}


/*
 * Function: dat_dr_remove
 */

extern DAT_RETURN
dat_dr_remove(
    IN  const DAT_PROVIDER_INFO *info)
{
        DAT_DR_ENTRY            *data;
        DAT_DICTIONARY_ENTRY    dict_entry;
        DAT_RETURN              status;

        dat_os_lock(&g_dr_lock);

        status = dat_dictionary_search(g_dr_dictionary,
            info,
            (DAT_DICTIONARY_DATA *) &data);

        if (DAT_SUCCESS != status) {
                /* return status from dat_dictionary_search() */
                goto bail;
        }

        if (0 != data->ref_count) {
                status = DAT_ERROR(DAT_PROVIDER_IN_USE, 0);
                goto bail;
        }

        dict_entry = NULL;
        status = dat_dictionary_remove(g_dr_dictionary,
            &dict_entry,
            info,
            (DAT_DICTIONARY_DATA *) &data);

        if (DAT_SUCCESS != status) {
                /* return status from dat_dictionary_remove() */
                goto bail;
        }

        dat_os_free(data, sizeof (DAT_DR_ENTRY));

bail:
        dat_os_unlock(&g_dr_lock);

        if (NULL != dict_entry) {
                (void) dat_dictionary_entry_destroy(dict_entry);
        }

        return (status);
}


/*
 * Function: dat_dr_provider_open
 */

extern DAT_RETURN
dat_dr_provider_open(
    IN  const DAT_PROVIDER_INFO *info,
    OUT DAT_IA_OPEN_FUNC        *p_ia_open_func)
{
        DAT_RETURN              status;
        DAT_DR_ENTRY            *data;

        dat_os_lock(&g_dr_lock);

        status = dat_dictionary_search(g_dr_dictionary,
                                info,
                                (DAT_DICTIONARY_DATA *) &data);

        dat_os_unlock(&g_dr_lock);

        if (DAT_SUCCESS == status) {
                data->ref_count++;
                *p_ia_open_func = data->ia_open_func;
        }

        return (status);
}


/*
 * Function: dat_dr_provider_close
 */

extern DAT_RETURN
dat_dr_provider_close(
    IN  const DAT_PROVIDER_INFO *info)
{
        DAT_RETURN              status;
        DAT_DR_ENTRY            *data;

        dat_os_lock(&g_dr_lock);

        status = dat_dictionary_search(g_dr_dictionary,
            info,
            (DAT_DICTIONARY_DATA *) &data);

        dat_os_unlock(&g_dr_lock);

        if (DAT_SUCCESS == status) {
                data->ref_count--;
        }

        return (status);
}


/*
 * Function: dat_dr_size
 */

DAT_RETURN
dat_dr_size(
    OUT DAT_COUNT               *size)
{
        return (dat_dictionary_size(g_dr_dictionary, size));
}


/*
 * Function: dat_dr_list
 */

DAT_RETURN
dat_dr_list(
    IN  DAT_COUNT               max_to_return,
    OUT DAT_COUNT               *entries_returned,
    OUT DAT_PROVIDER_INFO       * (dat_provider_list[]))
{
        DAT_DR_ENTRY            **array;
        DAT_COUNT               array_size;
        DAT_COUNT               i;
        DAT_RETURN              status;

        array = NULL;
        status = DAT_SUCCESS;

        /*
         * The dictionary size may increase between the call to
         * dat_dictionary_size() and dat_dictionary_enumerate().
         * Therefore we loop until a successful enumeration is made.
         */
        *entries_returned = 0;
        for (;;) {
                status = dat_dictionary_size(g_dr_dictionary, &array_size);
                if (status != DAT_SUCCESS) {
                        goto bail;
                }

                if (array_size == 0) {
                        status = DAT_SUCCESS;
                        goto bail;
                }

                array = dat_os_alloc(array_size * sizeof (DAT_DR_ENTRY *));
                if (array == NULL) {
                        status = DAT_ERROR(DAT_INSUFFICIENT_RESOURCES,
                            DAT_RESOURCE_MEMORY);
                        goto bail;
                }

                dat_os_lock(&g_dr_lock);

                status = dat_dictionary_enumerate(g_dr_dictionary,
                    (DAT_DICTIONARY_DATA *) array,
                    array_size);

                dat_os_unlock(&g_dr_lock);

                if (DAT_SUCCESS == status) {
                        break;
                } else {
                        dat_os_free(array,
                            array_size * sizeof (DAT_DR_ENTRY *));
                        array = NULL;
                        continue;
                }
        }

        for (i = 0; (i < max_to_return) && (i < array_size); i++) {
                if (NULL == dat_provider_list[i]) {
                        status = DAT_ERROR(DAT_INVALID_PARAMETER,
                            DAT_INVALID_ARG3);
                        goto bail;
                }

                *dat_provider_list[i] = array[i]->info;
        }

        *entries_returned = i;

bail:
        if (NULL != array) {
                dat_os_free(array, array_size * sizeof (DAT_DR_ENTRY *));
        }

        return (status);
}

/*
 * Local variables:
 *  c-indent-level: 4
 *  c-basic-offset: 4
 *  tab-width: 8
 * End:
 */