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