lm_io.c revision d1d2228c6cf3ec632d28262810ab7902932a5d33
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (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
* 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 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#include "lm.h"
#include <lm_proto.h>
/*
* lm_remove_lmpl_cmd
*
* Parameters:
* tid The index into the response queue for the command being
* removed. A -1 value means that only the memory of ele is
* to be freed.
* ele The structure which contains the information about the lmpl
* command being removed.
*
* Gloabals:
* None
*
* This functions cleans up the response queue which handles responses for
* lmpl commands. Once the lmpl command has received its finial response
* this functions is called to free up the memory associated with ele and
* to open the index in the response queue associated with the task id of
* the lmpl command. There is no lock around the updates, since we are
* only removing an elements memory and setting the lm_rspq.rspq_cmd[tid]
* to NULL.
*
* Return Values:
* None
*/
void
/* LINTED tid in lm_remove_lmpl_cmd (E_FUNC_ARG_UNUSED) */
{
return;
}
"command element's condition variable");
}
"command element's mutex");
}
}
}
/*
* lm_obtain_task_id()
*
* Parameters:
* tid Next available task id for a LMPL command.
* rele Will be updated with the location of new element created for
* the lmpl command.
*
* This function obtains the necessary taskid for the cmd that is to
* be generated. It sets up a ptr to the lm_queue_ele in the lm_rspq
* based on the taskid as an index into lm_rspq.rspq_cmd array.
*
* Return Values:
* LM_OK If it was able to obtain a taskid and lock the necessary
* mutexes.
* LM_ERROR If it encountered an error while processing. All errors
* generate an internal processing error that are not
* currently recoverable from. Thus, any error encountered will
* set the global lm_internal_error indicating to LM that
* it should abort processing as quick as possible.
*
*/
int
{
== NULL) {
"for a new lmpl command element, errno - %s",
return (LM_ERROR);
}
"lmpl command element's mutex, errno - %s",
return (LM_ERROR);
}
"lmpl command element's condition variable, "
"lm_obtain_task_id: Unable to free lmpl "
"command element's mutex, errno - %s",
}
return (LM_ERROR);
}
/* any other cmd processing threads want to send */
/* a cmd to MM they will block here until the last */
/* thread that generated a cmd gets it's accept */
/* unaccept response. */
if (pthread_mutex_lock(&lm_acc_mutex) != 0) {
return (LM_ERROR);
}
/* Lock the response queue so that there is not */
/* more than one thread updating information in the */
/* queue at one time */
if (pthread_mutex_unlock(&lm_acc_mutex) != 0)
return (LM_ERROR);
}
/* Update the response queue task id to the next */
/* available one */
/* This is not an infinite loop because the */
/* lm_remove_lmpl_cmd does not need the resp queue */
/* mutex to free an element. Also, the number */
/* of outstanding LMPL commands is equal to the */
/* number of command processing threads, thus the */
/* most outstanding is equal to the number of */
/* processing threads and therefore there should */
/* always be an available taskid */
else
}
"queue's mutex failed with errno - %s",
if (pthread_mutex_unlock(&lm_acc_mutex) != 0)
return (LM_ERROR);
}
return (LM_OK);
}
/*
* lm_gen_lmpl_cmd
*
* Parameters:
* cmd_str The LMPL command to send to MM.
* ele The structure which contains the information about the lmpl
* command being being sent to MM.
* wait Indicates if the LMPL command should only take this many
* seconds to process. If it takes longer than this many
* seconds, LM will send a LMPL cancel command to MM to
* try to cancel the original LMPL command.
*
* Gloabals:
* None
*
* This functions sends the LMPL command to MM and waits for an accept
* response, and the final response to the command. Once the final
* response is received, it returns the lmpl response in ele.
*
* Return Values:
* MMS_OK If command was sent successfully and a valid response
* was received.
* MMS_ERROR If an error was encountered while sending the command
* or receiving the response.
*/
int
{
int rc;
int len;
int taskid;
/* Lock mutex to protect that only one thread is */
/* sending information over the socket to MM at */
/* one time */
"lm_gen_lmpl_cmd: Lock on write mutex failed, "
return (LM_ERROR);
}
/* Write out cmd to MM */
"send to MM: \n%s",
cmd_str);
(void) pthread_mutex_unlock(&lm_write_mutex);
return (LM_ERROR);
}
/* Unlock write mutex */
return (LM_ERROR);
}
/* Go to sleep until accept or unaccept is returned */
return (LM_ERROR);
}
mms_trace_flush(); /* flush mms_trace buffer */
if (!lm_internal_error)
continue;
else {
"waiting on an accept response, LM "
"encountered an internal processing error");
(void) pthread_mutex_unlock(&ele->
return (LM_ERROR);
}
} else if (rc != 0) {
"element cond var, errno - %s",
return (LM_ERROR);
}
"lm_gen_lmpl_cmd: Went to sleep waiting for "
"accept");
}
"an accept response, but accept response is still set "
"to NULL");
return (LM_ERROR);
}
"response for LMPL command:\n%s", cmd_str);
(void) pthread_mutex_unlock(&lm_acc_mutex);
return (LMPL_UNACCEPTABLE);
}
return (LM_ERROR);
}
"lm_gen_lmpl_cmd: Going to sleep waiting for "
"final response");
/* If the LMPL command that is being sent does not */
/* complete in the alotted time, then LM will */
/* send a LMPL cancel command to MM to cancel the */
/* original LMPL command */
if (wait) {
"lm_gen_lmpl_cmd: 2 Timeout "
"hit, send LMPL cancel command for command"
":\n%s", cmd_str);
wait = 0;
continue;
} else if (rc != 0) {
"lm_gen_lmpl_cmd: 2 Unable to "
"wait on element cond var, errno - %s",
(void) pthread_mutex_unlock(&ele->
return (LM_ERROR);
}
} else {
if (!lm_internal_error)
continue;
"lm_gen_lmpl_cmd: 2 Detected "
"an internal processing error");
(void) pthread_mutex_unlock(&ele->
return (LM_ERROR);
} else if (rc != 0) {
"lm_gen_lmpl_cmd: 2 Unable to "
"wait on element cond var, errno - %s",
(void) pthread_mutex_unlock(&ele->
return (LM_ERROR);
}
}
"lm_gen_lmpl_cmd: Woke up while waiting for "
"final reponse");
}
return (ele->lmpl_rsp_final);
}
/*
*
* lm_handle_event()
*
* Parameters:
* - cmd Ptr to parse tree of event command.
*
* This function will do any preprocessing of an event notification
* command. It currently only checks to see if the state of the LM is
* valid to process an event.
* NOTE: Currently LM does not register for any events.
*
* Return Values:
* LM_OK If it was able to process the event correctly
* LM_ERROR If routine encountered an internal error while
* processing event
*
*/
int
{
/* If LM is not active ignore event commands */
"lm_handle_event: LM is not in a valid state "
"to process event command, state - 0x%x", lm_state);
return (LM_OK);
}
return (LM_ERROR);
}
return (LM_OK);
}
/*
*
* lm_handle_response()
*
* Parameters:
* - cmd Ptr to parse tree of response cmd.
*
* This function will indicate to the correct thread waiting for a response
* from the MM that it has received it and wake it up. It is the cmd
* processing thread that will interrept the response based on its expectations
* This function's job is only to save the parsed cmd in the queue's element
* location and wake the cmd thread up.
*
* Return Values:
* LM_OK If it was able to process the response correctly
* LM_ERROR If routine encountered an internal error while
* processing response
*
*/
int
{
int found = LMPL_FINAL_INVALID;
int task_id;
"response queue mutex, errno - %s",
return (LM_ERROR);
}
!= NULL) {
"lm_handle_response: handle accept response "
found = LMPL_ACCEPT;
"lm_handle_response: handle unaccept response "
"response");
"response");
"response");
"response");
} else {
"accept, unacceptable, success, error, or cancelled in "
return (LM_ERROR);
}
return (LM_ERROR);
}
} else {
"task clause in response:\n%s",
return (LM_ERROR);
}
== NULL) {
"task value in response:\n%s",
return (LM_ERROR);
}
"- %d", task_id);
"response is not in the range of possible "
"LMPL task ids, range: %d - %d", task_id, 0,
return (LM_ERROR);
}
"handle a response for tid - %d, but response "
"element is NULL", task_id);
return (LM_ERROR);
}
== NULL) {
"space for a new lmpl node element, errno - %s",
return (LM_ERROR);
}
if (found == LMPL_FINAL_INTER) {
"intermediate response for task id - %d", task_id);
return (LM_OK);
}
/* clear entry in response array so that another */
/* LMPL command can use it */
}
"trying to signal thread waiting on wakeup call, "
return (LM_ERROR);
}
"condition mutex - %d", task_id);
"unlock lm_rspq.rspq_mutex mutex, errno - %s",
return (LM_ERROR);
}
return (LM_OK);
}
/*
* lm_handle_parser_error()
*
* Parameters:
* - cmd Parse tree of input generated by mms_lmpm_parse
* - err_list List of errors found by mms_lmpm_parse
*
* Globals:
*
* This function handle the case where mms_lmpm_parse detected a error. This
* routine tries to look at the errors that were detected and decide
* what should be done.
*
* NOTE: The input could be one of the following. This routine tries to
* look at the output from the parser and handle each case:
* - A new LMPM cmd sent to LM by MM.
* - A final response to a LMPL cmd that LM sent to MM.
*
* Return Values:
* MMS_OK: If error was a syntax error on a new command from MM. We send
* a unaccept response back to MM in this case.
* NOMEM: Have the parser retry parsing the cmd since memory may be freed
* since the first try.
* MMS_ERROR: This routine encountered an error that should not of occured
* and it could not recover.
*
*/
int
{
/* msg part of rsp_str */
char msg_str[256];
/* Determine type of errors detected */
line %d, col %d, near token \"%s\", err code %d, %s",
case MMS_PE_NOMEM:
"Parser error indicates that no memory "
"is available to create parse tree, try "
"parsing again");
return (LM_NOMEM);
case MMS_PE_SYNTAX:
break;
case MMS_PE_MAX_LEVEL:
"Parser error indicates that the max level "
"was reached");
return (LM_ERROR);
default:
/* Only above three possible error */
/* conditions exist, thus if this */
/* condition is ever hit, things */
/* are really messed up, system error */
"Encountered a unknown parser error - %d",
return (LM_ERROR);
}
}
/* Unable to tell what the input was at all, in this */
/* case we generate a system error and will exit */
"syntax error, but unable to determine if error is on a "
"new LMPM command or a LMPL response");
return (LM_SYNTAX_ERR);
}
"on LMPL response from MM");
return (LM_SYNTAX_RSP);
}
/* ASSUME THAT THE MM SENT US A CMD. NEED TO SEND AN UNACCEPT, SINCE */
/* WE ARE USING LMPM_PARSE, WE KNOW IT IS A LMPM COMMAND, JUST NOT */
/* VALID LMPM COMMAND */
"lm_handle_parser_error: Sending unacceptable "
"response on invalid LMPM command failed");
}
return (LM_SYNTAX_CMD);
}
/*
*
* lm_write_msg()
*
* Parameters:
* - msg The message that is to be sent to the MM. It is in BNF
* form defined in the IEEE spec for MMS.
* - conn The connection structure
* - mutex The mutex which allows only one thread of the LM to
* write to the MM at a time.
*
* This function sends a message from the LM to the MM over the socket that
* connects the LM and MM. Locks the mutex around output, and sends the message.
* This routine is not to be used to send a LMPL command to MM. Use
* lm_gen_lmpl_cmd() to do this. This routine is used to send messages where
* no response is expected.
*
* Return Values:
* - MMS_OK If the message was sent without errors.
* - MMS_ERROR If a error occurred while sending the message.
*
* NOTE: The calling routine should call lm_serr if LM_ERROR is returned.
* This routine only sends a mms_trace message indicating the write error.
*
*/
int
{
int len; /* length of xmlcmd string */
int rc; /* return code */
return (LM_ERROR);
}
"to MM, error - %d", rc);
(void) pthread_mutex_unlock(&mutex);
return (LM_ERROR);
}
return (LM_ERROR);
}
return (LM_OK);
}