blob: 2de799a59bd5b6e308464596c91d0dfc5753d5a0 [file] [log] [blame]
/**********************************************************************
// @@@ START COPYRIGHT @@@
//
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
//
// @@@ END COPYRIGHT @@@
**********************************************************************/
/* -*-C++-*-
*****************************************************************************
*
* File: EHException.C
* Description: methods for class EHExceptionHandler
*
*
* Created: 5/19/95
* Language: C++
*
*
*
*
*****************************************************************************
*/
#include "EHCommonDefs.h"
#include "NAError.h"
#include <setjmp.h>
#include <string.h>
#ifndef EH_USE_GLOB_NEW
#include <stdlib.h>
#endif
#include "EHExceptionTypeEnum.h"
#include "EHExceptionTypeNode.h"
#include "EHException.h"
#include "EHCallBack.h"
// -----------------------------------------------------------------------
// methods for class EHExceptionHandler
// -----------------------------------------------------------------------
EHExceptionHandler::EHExceptionHandler()
{
pEHCallBack_=0;
}
//
// virtual destructor
//
EHExceptionHandler::~EHExceptionHandler()
{
}
//int CompEHCounter::counter_ = 0;
//
// mutators
//
void
EHExceptionHandler::registerThrowCallBack(EHCallBack *pEHCallBack)
{
pEHCallBack_ = pEHCallBack;
}
void
EHExceptionHandler::endTryBlock()
{
if (getExceptionType() NEQ EH_NORMAL)
{
return; // does nothing, the method throwException() already did the work
}
//
// exits the try block normally.
//
isCaught_ = FALSE;
EHExceptionJmpBufNode * pJmpBufNode = exceptionJmpBufStack_.pop();
EH_ASSERT(pJmpBufNode NEQ NULL);
//
// pExceptionTypeNode points to a list of exceptions that can be
// caught by the catch block(s) associating with the try block.
//
EHExceptionTypeNode * pExceptionTypeNode
= pJmpBufNode->getExceptionTypeList();
//
// deallocates the list of exceptions associating with the try
// block. It is no longer needed.
//
while (pExceptionTypeNode NEQ NULL)
{
pJmpBufNode->setExceptionTypeList(pExceptionTypeNode->getNextNode());
#ifdef EH_USE_GLOB_NEW
delete pExceptionTypeNode;
#else
free(pExceptionTypeNode);
#endif
pExceptionTypeNode = pJmpBufNode->getExceptionTypeList();
}
//
// no longer needs the jmpbuf for this try block.
//
#ifdef EH_USE_GLOB_NEW
delete pJmpBufNode;
#else
free(pJmpBufNode);
#endif
}
EHBoolean
EHExceptionHandler::catchException(EHExceptionTypeEnum exceptionType)
{
if (getExceptionType() EQU EH_NORMAL)
{
return FALSE;
}
if (isCaught_)
{
//
// A previous catch block (also associating with the current
// try block) has caught this exception. The current catch
// block should not catch the exception
//
return FALSE;
}
if (getExceptionType() EQU exceptionType OR
exceptionType EQU EH_ALL_EXCEPTIONS)
{
return (isCaught_ = TRUE);
}
return FALSE;
}
void
EHExceptionHandler::setExceptionType(Int32 exceptionType)
{
EH_ASSERT(exceptionType >= EH_NORMAL AND
exceptionType < EH_LAST_EXCEPTION_TYPE_ENUM);
exceptionType_ = (EHExceptionTypeEnum)exceptionType;
}
void
EHExceptionHandler::registerException(EHExceptionTypeEnum exceptionType)
{
#ifdef EH_USE_GLOB_NEW
EHExceptionTypeNode * pExceptionTypeNode =
new EHExceptionTypeNode(exceptionType);
if (pExceptionTypeNode EQU NULL)
{
EH_ABORT("operator new could not allocate the needed space");
}
#else
EHExceptionTypeNode * pExceptionTypeNode =
(EHExceptionTypeNode *)malloc(sizeof(EHExceptionTypeNode));
if (pExceptionTypeNode EQU NULL)
{
EH_ABORT("malloc() could not allocate the needed space");
}
//
// Note that the constructor of class EHExceptionTypeNode
// was not invoked.
//
pExceptionTypeNode->setExceptionType(exceptionType);
#endif
pExceptionTypeNode->setNextNode(pExceptionTypeList_);
pExceptionTypeList_ = pExceptionTypeNode;
}
// define try block
EHExceptionTypeEnum
EHExceptionHandler::defineTryBlock()
{
// this->setjmpStatus and this->environment
// were set by setjmp() (for more information
// refer to the definition of macro EH_TRY)
setExceptionType(setjmpStatus);
if (getExceptionType() EQU EH_NORMAL)
{
if (pExceptionTypeList_ EQU NULL)
{
EH_ABORT("You have not registered any exceptions");
}
#ifdef EH_USE_GLOB_NEW
EHExceptionJmpBufNode * pJmpBufNode = new EHExceptionJmpBufNode;
if (pJmpBufNode EQU NULL)
{
EH_ABORT("operator new could not allocate the needed space");
}
#else
EHExceptionJmpBufNode * pJmpBufNode =
(EHExceptionJmpBufNode *)malloc(sizeof(EHExceptionJmpBufNode));
if (pJmpBufNode EQU NULL)
{
EH_ABORT("malloc() could not allocate the needed space");
}
//
// Note that the constructor of class EHExceptionJmpBufNode
// was not invoked
//
pJmpBufNode->setLink(NULL);
#endif
pJmpBufNode->setEnv(environment);
pJmpBufNode->setExceptionTypeList(pExceptionTypeList_);
exceptionJmpBufStack_.push(pJmpBufNode);
pExceptionTypeList_ = NULL;
}
return getExceptionType();
}
// throw
void
EHExceptionHandler::throwException(EHExceptionTypeEnum exceptionType)
{
EHExceptionJmpBufNode::env envStruct;
EHBoolean foundException = FALSE;
EHExceptionTypeNode * pExceptionTypeNode = NULL;
EHExceptionJmpBufNode * pJmpBufNode = exceptionJmpBufStack_.pop();
//
// The following flag helps to make sure that no more than one catch
// block (of all catch blocks associating with a try block) catches
// an exception. This flag is cleared whenever an exception is thrown.
// It will be set by the first catch block that catches the exception.
//
isCaught_ = FALSE;
// Record the state at the time of exception; we do this at the time
// exception is thrown, so if an exception is thrown more than once
// we record this as many times. User errors (as indicated by value
// EH_PROCESSING_EXCEPTION) are not to be propagated.
// Genesis case: 10-010523-0766
if (( exceptionType != EH_PROCESSING_EXCEPTION ) && pEHCallBack_)
pEHCallBack_->doFFDC();
//
// Searches the nested try blocks, starting with the innermost try
// block, to find a catch block (associating with the current try
// block) that can catch the exception.
//
// pJmpBufNode points to the control block describing the (current)
// innermost try block.
//
while (pJmpBufNode NEQ NULL)
{
//
// pExceptionTypeNode points to a list of exceptions that can be
// caught by the catch block(s) associating with the innermost
// try block
//
pExceptionTypeNode = pJmpBufNode->getExceptionTypeList();
//
// Finds out if there exists a catch block associating with the
// the (current) innermost try block that can catch the exception.
// The list is deallocated after the search since it is no longer
// needed.
//
while (pExceptionTypeNode NEQ NULL)
{
if (pExceptionTypeNode->getExceptionType() EQU exceptionType OR
pExceptionTypeNode->getExceptionType() EQU EH_ALL_EXCEPTIONS)
{
foundException = TRUE;
}
pJmpBufNode->setExceptionTypeList(pExceptionTypeNode->getNextNode());
#if EH_USE_GLOB_NEW
delete pExceptionTypeNode;
#else
free(pExceptionTypeNode);
#endif
pExceptionTypeNode = pJmpBufNode->getExceptionTypeList();
}
//
// If the thrown exception is found,
// cut back the runtime stack now.
//
if (foundException)
{
memcpy ((void *)&envStruct,
(void *)&pJmpBufNode->environment,
sizeof(envStruct));
#if EH_USE_GLOB_NEW
delete pJmpBufNode;
#else
free(pJmpBufNode);
#endif
if(pEHCallBack_)
pEHCallBack_->dumpDiags();
longjmp(envStruct.jmpBuf, exceptionType);
}
//
// Has not found a catch block that can catch the exception yet.
// Tries the catch block(s) associating with the next outer try
// block. Deallocates the control block describing the current
// try block because the control block is no longer needed.
//
#if EH_USE_GLOB_NEW
delete pJmpBufNode;
#else
free(pJmpBufNode);
#endif
pJmpBufNode = exceptionJmpBufStack_.pop();
}
EH_ABORT("Could not find any matching exception handler");
}