Blame openhpid/session.c

Packit db01ca
/*      -*- linux-c -*-
Packit db01ca
 *
Packit db01ca
 * (C) Copyright IBM Corp. 2004, 2005
Packit db01ca
 *
Packit db01ca
 * This program is distributed in the hope that it will be useful,
Packit db01ca
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit db01ca
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  This
Packit db01ca
 * file and program are licensed under a BSD style license.  See
Packit db01ca
 * the Copying file included with the OpenHPI distribution for
Packit db01ca
 * full licensing terms.
Packit db01ca
 *
Packit db01ca
 * Author(s):
Packit db01ca
 *      Renier Morales <renier@openhpi.org>
Packit db01ca
 *
Packit db01ca
 */
Packit db01ca
Packit db01ca
#include <string.h>
Packit db01ca
Packit db01ca
#include <oHpi.h>
Packit db01ca
Packit db01ca
#include <oh_domain.h>
Packit db01ca
#include <oh_error.h>
Packit db01ca
#include <oh_session.h>
Packit db01ca
#include <oh_utils.h>
Packit db01ca
Packit db01ca
#include "conf.h"
Packit db01ca
#include "event.h"
Packit db01ca
#include "lock.h"
Packit db01ca
#include <sahpi_wrappers.h>
Packit db01ca
Packit db01ca
struct oh_session_table oh_sessions = {
Packit db01ca
        .table = NULL,
Packit db01ca
#if !GLIB_CHECK_VERSION (2, 32, 0)
Packit db01ca
        .lock = G_STATIC_REC_MUTEX_INIT
Packit db01ca
#endif
Packit db01ca
};
Packit db01ca
Packit db01ca
Packit db01ca
/**
Packit db01ca
 * oh_create_session
Packit db01ca
 * @did:
Packit db01ca
 *
Packit db01ca
 *
Packit db01ca
 *
Packit db01ca
 * Returns:
Packit db01ca
 **/
Packit db01ca
SaHpiSessionIdT oh_create_session(SaHpiDomainIdT did)
Packit db01ca
{
Packit db01ca
        struct oh_session *session = NULL;
Packit db01ca
        struct oh_domain *domain = NULL;
Packit db01ca
        static SaHpiSessionIdT id = 1;        /* Session ids will start at 1 */
Packit db01ca
Packit db01ca
        if (did == SAHPI_UNSPECIFIED_DOMAIN_ID)
Packit db01ca
                did = OH_DEFAULT_DOMAIN_ID;
Packit db01ca
Packit db01ca
        session = g_new0(struct oh_session, 1);
Packit db01ca
        if (!session)
Packit db01ca
                return 0;
Packit db01ca
Packit db01ca
        session->did = did;
Packit db01ca
        session->eventq = g_async_queue_new();
Packit db01ca
        session->subscribed = SAHPI_FALSE;
Packit db01ca
Packit db01ca
        domain = oh_get_domain(did);
Packit db01ca
        if (!domain) {
Packit db01ca
                g_async_queue_unref(session->eventq);
Packit db01ca
                g_free(session);
Packit db01ca
                return 0;
Packit db01ca
        }
Packit db01ca
        wrap_g_static_rec_mutex_lock(&oh_sessions.lock); /* Locked session table */
Packit db01ca
        session->id = id++;
Packit db01ca
        g_hash_table_insert(oh_sessions.table, &(session->id), session);
Packit db01ca
        oh_sessions.list = g_slist_append(oh_sessions.list, session);
Packit db01ca
        wrap_g_static_rec_mutex_unlock(&oh_sessions.lock); /* Unlocked session table */
Packit db01ca
        oh_release_domain(domain);
Packit db01ca
Packit db01ca
        return session->id;
Packit db01ca
}
Packit db01ca
Packit db01ca
/**
Packit db01ca
 * oh_get_session_domain
Packit db01ca
 * @sid:
Packit db01ca
 *
Packit db01ca
 *
Packit db01ca
 *
Packit db01ca
 * Returns: SAHPI_UNSPECIFIED_DOMAIN_ID if domain id was not found.
Packit db01ca
 **/
Packit db01ca
SaHpiDomainIdT oh_get_session_domain(SaHpiSessionIdT sid)
Packit db01ca
{
Packit db01ca
        struct oh_session *session = NULL;
Packit db01ca
        SaHpiDomainIdT did;
Packit db01ca
Packit db01ca
        if (sid < 1)
Packit db01ca
                return SAHPI_UNSPECIFIED_DOMAIN_ID;
Packit db01ca
Packit db01ca
        wrap_g_static_rec_mutex_lock(&oh_sessions.lock); /* Locked session table */
Packit db01ca
        session = g_hash_table_lookup(oh_sessions.table, &sid;;
Packit db01ca
        if (!session) {
Packit db01ca
                wrap_g_static_rec_mutex_unlock(&oh_sessions.lock);
Packit db01ca
                return SAHPI_UNSPECIFIED_DOMAIN_ID;
Packit db01ca
        }
Packit db01ca
Packit db01ca
        did = session->did;
Packit db01ca
        wrap_g_static_rec_mutex_unlock(&oh_sessions.lock); /* Unlocked session table */
Packit db01ca
Packit db01ca
Packit db01ca
        return did;
Packit db01ca
}
Packit db01ca
Packit db01ca
/**
Packit db01ca
 * oh_list_sessions
Packit db01ca
 * @did:
Packit db01ca
 *
Packit db01ca
 *
Packit db01ca
 *
Packit db01ca
 * Returns: A dynamically allocated array of session ids.
Packit db01ca
 * The caller needs to free this array when he is done with it.
Packit db01ca
 **/
Packit db01ca
GArray *oh_list_sessions(SaHpiDomainIdT did)
Packit db01ca
{
Packit db01ca
        struct oh_domain *domain = NULL;
Packit db01ca
        GArray *session_ids = NULL;
Packit db01ca
        GSList *node = NULL;
Packit db01ca
Packit db01ca
        if (did == SAHPI_UNSPECIFIED_DOMAIN_ID)
Packit db01ca
                did = OH_DEFAULT_DOMAIN_ID;
Packit db01ca
Packit db01ca
        domain = oh_get_domain(did);
Packit db01ca
        if (!domain)
Packit db01ca
                return NULL;
Packit db01ca
Packit db01ca
        session_ids = g_array_new(FALSE, TRUE, sizeof(SaHpiSessionIdT));
Packit db01ca
Packit db01ca
        wrap_g_static_rec_mutex_lock(&oh_sessions.lock); /* Locked session table */
Packit db01ca
        for (node = oh_sessions.list; node; node = node->next) {
Packit db01ca
                struct oh_session *s = node->data;
Packit db01ca
                if (s->did != did) continue;
Packit db01ca
                g_array_append_val(session_ids, s->id);
Packit db01ca
        }
Packit db01ca
        wrap_g_static_rec_mutex_unlock(&oh_sessions.lock); /* Unlocked session table */
Packit db01ca
        oh_release_domain(domain);
Packit db01ca
Packit db01ca
        return session_ids;
Packit db01ca
}
Packit db01ca
Packit db01ca
/**
Packit db01ca
 * oh_get_session_state
Packit db01ca
 * @sid:
Packit db01ca
 * @state:
Packit db01ca
 *
Packit db01ca
 *
Packit db01ca
 *
Packit db01ca
 * Returns:
Packit db01ca
 **/
Packit db01ca
SaErrorT oh_get_session_subscription(SaHpiSessionIdT sid,
Packit db01ca
                                     SaHpiBoolT * state)
Packit db01ca
{
Packit db01ca
        struct oh_session *session = NULL;        
Packit db01ca
                
Packit db01ca
        if (sid < 1)
Packit db01ca
        	return SA_ERR_HPI_INVALID_SESSION;
Packit db01ca
        	
Packit db01ca
	if (state == NULL)
Packit db01ca
                return SA_ERR_HPI_INVALID_PARAMS;       
Packit db01ca
                
Packit db01ca
        if (oh_sessions.table == NULL)
Packit db01ca
        	return SA_ERR_HPI_INTERNAL_ERROR;
Packit db01ca
Packit db01ca
        wrap_g_static_rec_mutex_lock(&oh_sessions.lock); /* Locked session table */
Packit db01ca
        session = g_hash_table_lookup(oh_sessions.table, &sid;;
Packit db01ca
        if (!session) {
Packit db01ca
                wrap_g_static_rec_mutex_unlock(&oh_sessions.lock);
Packit db01ca
                return SA_ERR_HPI_INVALID_SESSION;
Packit db01ca
        }
Packit db01ca
        *state = session->subscribed;
Packit db01ca
        wrap_g_static_rec_mutex_unlock(&oh_sessions.lock); /* Unlocked session table */
Packit db01ca
Packit db01ca
        return SA_OK;
Packit db01ca
}
Packit db01ca
Packit db01ca
/**
Packit db01ca
 * oh_set_session_state
Packit db01ca
 * @sid:
Packit db01ca
 * @state:
Packit db01ca
 *
Packit db01ca
 *
Packit db01ca
 *
Packit db01ca
 * Returns:
Packit db01ca
 **/
Packit db01ca
SaErrorT oh_set_session_subscription(SaHpiSessionIdT sid, SaHpiBoolT state)
Packit db01ca
{
Packit db01ca
        struct oh_session *session = NULL;
Packit db01ca
        struct oh_event e;
Packit db01ca
Packit db01ca
        if (sid < 1)
Packit db01ca
                return SA_ERR_HPI_INVALID_PARAMS;
Packit db01ca
Packit db01ca
        wrap_g_static_rec_mutex_lock(&oh_sessions.lock); /* Locked session table */
Packit db01ca
        session = g_hash_table_lookup(oh_sessions.table, &sid;;
Packit db01ca
        if (!session) {
Packit db01ca
               wrap_g_static_rec_mutex_unlock(&oh_sessions.lock);
Packit db01ca
                return SA_ERR_HPI_INVALID_SESSION;
Packit db01ca
        }
Packit db01ca
        session->subscribed = state;
Packit db01ca
Packit db01ca
        wrap_g_static_rec_mutex_unlock(&oh_sessions.lock); /* Unlocked session table */
Packit db01ca
        /* Flush session's event queue
Packit db01ca
         */
Packit db01ca
        if (state == SAHPI_FALSE) {
Packit db01ca
                while (oh_dequeue_session_event(sid,
Packit db01ca
                                                SAHPI_TIMEOUT_IMMEDIATE,
Packit db01ca
                                                &e, NULL) == SA_OK) {
Packit db01ca
			oh_event_free(&e, TRUE);
Packit db01ca
		}
Packit db01ca
        }
Packit db01ca
        return SA_OK;
Packit db01ca
}
Packit db01ca
Packit db01ca
/**
Packit db01ca
 * oh_queue_session_event
Packit db01ca
 * @sid:
Packit db01ca
 * @event:
Packit db01ca
 *
Packit db01ca
 *
Packit db01ca
 *
Packit db01ca
 * Returns:
Packit db01ca
 **/
Packit db01ca
SaErrorT oh_queue_session_event(SaHpiSessionIdT sid,
Packit db01ca
                                struct oh_event * event)
Packit db01ca
{
Packit db01ca
        struct oh_session *session = NULL;
Packit db01ca
        struct oh_event *qevent = NULL;
Packit db01ca
        struct oh_global_param param = {.type = OPENHPI_EVT_QUEUE_LIMIT };
Packit db01ca
        SaHpiBoolT nolimit = SAHPI_FALSE;
Packit db01ca
Packit db01ca
        if (sid < 1 || !event)
Packit db01ca
                return SA_ERR_HPI_INVALID_PARAMS;
Packit db01ca
Packit db01ca
        qevent = oh_dup_event(event);
Packit db01ca
        if (!qevent)
Packit db01ca
                return SA_ERR_HPI_OUT_OF_MEMORY;
Packit db01ca
Packit db01ca
        if (oh_get_global_param(&param)) {
Packit db01ca
                nolimit = SAHPI_TRUE;
Packit db01ca
        }
Packit db01ca
Packit db01ca
        wrap_g_static_rec_mutex_lock(&oh_sessions.lock); /* Locked session table */
Packit db01ca
        session = g_hash_table_lookup(oh_sessions.table, &sid;;
Packit db01ca
        if (!session) {
Packit db01ca
                wrap_g_static_rec_mutex_unlock(&oh_sessions.lock);
Packit db01ca
                oh_event_free(qevent, FALSE);
Packit db01ca
                return SA_ERR_HPI_INVALID_SESSION;
Packit db01ca
        }
Packit db01ca
Packit db01ca
        if (nolimit == SAHPI_FALSE) {
Packit db01ca
                SaHpiSessionIdT tmp_sid;
Packit db01ca
                tmp_sid = session->id;
Packit db01ca
                gint qlength = g_async_queue_length(session->eventq);
Packit db01ca
                if (qlength > 0 && qlength >= param.u.evt_queue_limit) {
Packit db01ca
                        /* Don't proceed with event push if queue is overflowed */
Packit db01ca
                        session->eventq_status = SAHPI_EVT_QUEUE_OVERFLOW;
Packit db01ca
                        wrap_g_static_rec_mutex_unlock(&oh_sessions.lock);
Packit db01ca
                        oh_event_free(qevent, FALSE);
Packit db01ca
                        CRIT("Session %d's queue is out of space; "
Packit db01ca
                            "# of events is %d; Max is %d",
Packit db01ca
                            tmp_sid, qlength, param.u.evt_queue_limit);
Packit db01ca
                        return SA_ERR_HPI_OUT_OF_SPACE;
Packit db01ca
                }
Packit db01ca
        }
Packit db01ca
Packit db01ca
        g_async_queue_push(session->eventq, qevent);
Packit db01ca
        wrap_g_static_rec_mutex_unlock(&oh_sessions.lock); /* Unlocked session table */
Packit db01ca
Packit db01ca
        return SA_OK;
Packit db01ca
}
Packit db01ca
Packit db01ca
/**
Packit db01ca
 * oh_dequeue_session_event
Packit db01ca
 * @sid:
Packit db01ca
 * @event:
Packit db01ca
 *
Packit db01ca
 *
Packit db01ca
 *
Packit db01ca
 * Returns:
Packit db01ca
 **/
Packit db01ca
SaErrorT oh_dequeue_session_event(SaHpiSessionIdT sid,
Packit db01ca
                                  SaHpiTimeoutT timeout,
Packit db01ca
                                  struct oh_event * event,
Packit db01ca
                                  SaHpiEvtQueueStatusT * eventq_status)
Packit db01ca
{
Packit db01ca
        struct oh_session *session = NULL;
Packit db01ca
        struct oh_event *devent = NULL;
Packit db01ca
        GAsyncQueue *eventq = NULL;
Packit db01ca
        SaHpiBoolT subscribed;
Packit db01ca
        SaErrorT invalid;
Packit db01ca
Packit db01ca
        if (sid < 1 || (event == NULL))
Packit db01ca
                return SA_ERR_HPI_INVALID_PARAMS;
Packit db01ca
Packit db01ca
        wrap_g_static_rec_mutex_lock(&oh_sessions.lock); /* Locked session table */
Packit db01ca
        session = g_hash_table_lookup(oh_sessions.table, &sid;;
Packit db01ca
        if (!session) {
Packit db01ca
                wrap_g_static_rec_mutex_unlock(&oh_sessions.lock);
Packit db01ca
                return SA_ERR_HPI_INVALID_SESSION;
Packit db01ca
        }
Packit db01ca
Packit db01ca
        if (eventq_status) {
Packit db01ca
                *eventq_status = session->eventq_status;
Packit db01ca
        }
Packit db01ca
        session->eventq_status = 0;
Packit db01ca
        eventq = session->eventq;
Packit db01ca
        g_async_queue_ref(eventq);
Packit db01ca
        wrap_g_static_rec_mutex_unlock(&oh_sessions.lock);
Packit db01ca
Packit db01ca
        if (timeout == SAHPI_TIMEOUT_IMMEDIATE) {
Packit db01ca
                devent = g_async_queue_try_pop(eventq);
Packit db01ca
        } else if (timeout == SAHPI_TIMEOUT_BLOCK) {
Packit db01ca
                while (devent == NULL) {
Packit db01ca
                        #if GLIB_CHECK_VERSION (2, 32, 0)
Packit db01ca
                        guint64 gfinaltime;
Packit db01ca
                        gfinaltime = (guint64) 5000000L;
Packit db01ca
                        devent =
Packit db01ca
                            wrap_g_async_queue_timed_pop(eventq, gfinaltime);
Packit db01ca
                        #else
Packit db01ca
                        GTimeVal gfinaltime;
Packit db01ca
                        g_get_current_time(&gfinaltime);
Packit db01ca
                        g_time_val_add(&gfinaltime, 5000000L);
Packit db01ca
                        devent =
Packit db01ca
                            wrap_g_async_queue_timed_pop(eventq, &gfinaltime);
Packit db01ca
                        #endif
Packit db01ca
                        /* compliance with spec page 63 */
Packit db01ca
                        invalid =
Packit db01ca
                            oh_get_session_subscription(sid, &subscribed);
Packit db01ca
                        /* Is the session still open? or still subscribed? */
Packit db01ca
                        if (invalid || !subscribed) {
Packit db01ca
                                g_async_queue_unref(eventq);
Packit db01ca
                                oh_event_free(devent, FALSE);
Packit db01ca
                                return invalid ? SA_ERR_HPI_INVALID_SESSION
Packit db01ca
                                    : SA_ERR_HPI_INVALID_REQUEST;
Packit db01ca
                        }
Packit db01ca
                }
Packit db01ca
        } else {
Packit db01ca
                #if GLIB_CHECK_VERSION (2, 32, 0)
Packit db01ca
                guint64 gfinaltime;
Packit db01ca
                gfinaltime = (guint64) (timeout / 1000);
Packit db01ca
                devent = wrap_g_async_queue_timed_pop(eventq, gfinaltime);
Packit db01ca
                #else
Packit db01ca
                GTimeVal gfinaltime;
Packit db01ca
                g_get_current_time(&gfinaltime);
Packit db01ca
                g_time_val_add(&gfinaltime, (glong) (timeout / 1000));
Packit db01ca
                devent = wrap_g_async_queue_timed_pop(eventq, &gfinaltime);
Packit db01ca
                #endif
Packit db01ca
                invalid = oh_get_session_subscription(sid, &subscribed);
Packit db01ca
                if (invalid || !subscribed) {
Packit db01ca
                        g_async_queue_unref(eventq);
Packit db01ca
                        oh_event_free(devent, FALSE);
Packit db01ca
                        return invalid ? SA_ERR_HPI_INVALID_SESSION :
Packit db01ca
                            SA_ERR_HPI_INVALID_REQUEST;
Packit db01ca
                }
Packit db01ca
        }
Packit db01ca
        g_async_queue_unref(eventq);
Packit db01ca
Packit db01ca
        if (devent) {
Packit db01ca
                int cc;
Packit db01ca
                cc = oh_detect_quit_event(devent);
Packit db01ca
                if (cc == 0) {
Packit db01ca
                        // OpenHPI is about to quit
Packit db01ca
                        oh_event_free(devent, FALSE);
Packit db01ca
                        return SA_ERR_HPI_NO_RESPONSE;
Packit db01ca
                }
Packit db01ca
                memcpy(event, devent, sizeof(struct oh_event));
Packit db01ca
                g_free(devent);
Packit db01ca
                return SA_OK;
Packit db01ca
        } else {
Packit db01ca
                memset(event, 0, sizeof(struct oh_event));
Packit db01ca
                return SA_ERR_HPI_TIMEOUT;
Packit db01ca
        }
Packit db01ca
}
Packit db01ca
Packit db01ca
/**
Packit db01ca
 * oh_destroy_session
Packit db01ca
 * @sid:
Packit db01ca
 * @update_domain:
Packit db01ca
 *
Packit db01ca
 *
Packit db01ca
 * Returns:
Packit db01ca
 **/
Packit db01ca
SaErrorT oh_destroy_session(SaHpiSessionIdT sid)
Packit db01ca
{
Packit db01ca
        struct oh_session *session = NULL;
Packit db01ca
        gpointer event = NULL;
Packit db01ca
        int i, len;
Packit db01ca
Packit db01ca
        if (sid < 1)
Packit db01ca
                return SA_ERR_HPI_INVALID_PARAMS;
Packit db01ca
Packit db01ca
        wrap_g_static_rec_mutex_lock(&oh_sessions.lock); /* Locked session table */
Packit db01ca
        session = g_hash_table_lookup(oh_sessions.table, &sid;;
Packit db01ca
        if (!session) {
Packit db01ca
                wrap_g_static_rec_mutex_unlock(&oh_sessions.lock);
Packit db01ca
                return SA_ERR_HPI_INVALID_SESSION;
Packit db01ca
        }
Packit db01ca
        oh_sessions.list = g_slist_remove(oh_sessions.list, session);
Packit db01ca
        g_hash_table_remove(oh_sessions.table, &(session->id));
Packit db01ca
        wrap_g_static_rec_mutex_unlock(&oh_sessions.lock); /* Unlocked session table */
Packit db01ca
Packit db01ca
        /* Finalize session */
Packit db01ca
        len = g_async_queue_length(session->eventq);
Packit db01ca
        if (len > 0) {
Packit db01ca
                for (i = 0; i < len; i++) {
Packit db01ca
                        event = g_async_queue_try_pop(session->eventq);
Packit db01ca
                        if (event)
Packit db01ca
                                oh_event_free(event, FALSE);
Packit db01ca
                        event = NULL;
Packit db01ca
                }
Packit db01ca
        }
Packit db01ca
        g_async_queue_unref(session->eventq);
Packit db01ca
        g_free(session);
Packit db01ca
Packit db01ca
        return SA_OK;
Packit db01ca
}
Packit db01ca