/* Copyright (C) 2003 MySQL AB This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. 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. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include <ndb_global.h> #include "Emulator.hpp" #include <FastScheduler.hpp> #include <SignalLoggerManager.hpp> #include <TransporterRegistry.hpp> #include <TimeQueue.hpp> #include "Configuration.hpp" #include "WatchDog.hpp" #include "ThreadConfig.hpp" #include "SimBlockList.hpp" #include <NodeState.hpp> #include <NdbMem.h> #include <NdbOut.hpp> #include <NdbMutex.h> #include <NdbSleep.h> extern "C" { extern void (* ndb_new_handler)(); } /** * Declare the global variables */ #ifndef NO_EMULATED_JAM Uint8 theEmulatedJam[EMULATED_JAM_SIZE * 4]; Uint32 theEmulatedJamIndex = 0; Uint32 theEmulatedJamBlockNumber = 0; #endif GlobalData globalData; TimeQueue globalTimeQueue; FastScheduler globalScheduler; TransporterRegistry globalTransporterRegistry; #ifdef VM_TRACE SignalLoggerManager globalSignalLoggers; #endif EmulatorData globalEmulatorData; NdbMutex * theShutdownMutex = 0; int simulate_error_during_shutdown= 0; EmulatorData::EmulatorData(){ theConfiguration = 0; theWatchDog = 0; theThreadConfig = 0; theSimBlockList = 0; theShutdownMutex = 0; m_socket_server = 0; } void ndb_new_handler_impl(){ ERROR_SET(fatal, ERR_MEMALLOC, "New handler", ""); } void EmulatorData::create(){ NdbMem_Create(); theConfiguration = new Configuration(); theWatchDog = new WatchDog(); theThreadConfig = new ThreadConfig(); theSimBlockList = new SimBlockList(); m_socket_server = new SocketServer(); theShutdownMutex = NdbMutex_Create(); ndb_new_handler = ndb_new_handler_impl; } void EmulatorData::destroy(){ if(theConfiguration) delete theConfiguration; theConfiguration = 0; if(theWatchDog) delete theWatchDog; theWatchDog = 0; if(theThreadConfig) delete theThreadConfig; theThreadConfig = 0; if(theSimBlockList) delete theSimBlockList; theSimBlockList = 0; if(m_socket_server) delete m_socket_server; m_socket_server = 0; NdbMem_Destroy(); } void NdbShutdown(NdbShutdownType type, NdbRestartType restartType){ if(type == NST_ErrorInsert){ type = NST_Restart; restartType = (NdbRestartType) globalEmulatorData.theConfiguration->getRestartOnErrorInsert(); if(restartType == NRT_Default){ type = NST_ErrorHandler; globalEmulatorData.theConfiguration->stopOnError(true); } } if((type == NST_ErrorHandlerSignal) || // Signal handler has already locked mutex (NdbMutex_Trylock(theShutdownMutex) == 0)){ globalData.theRestartFlag = perform_stop; bool restart = false; #if ! ( defined NDB_OSE || defined NDB_SOFTOSE) if((type != NST_Normal && globalEmulatorData.theConfiguration->stopOnError() == false) || type == NST_Restart) { restart = true; } #endif const char * shutting = "shutting down"; if(restart){ shutting = "restarting"; } switch(type){ case NST_Normal: ndbout << "Shutdown initiated" << endl; break; case NST_Watchdog: ndbout << "Watchdog " << shutting << " system" << endl; break; case NST_ErrorHandler: ndbout << "Error handler " << shutting << " system" << endl; break; case NST_ErrorHandlerSignal: ndbout << "Error handler signal " << shutting << " system" << endl; break; case NST_Restart: ndbout << "Restarting system" << endl; break; default: ndbout << "Error handler " << shutting << " system" << " (unknown type: " << (unsigned)type << ")" << endl; type = NST_ErrorHandler; break; } const char * exitAbort = 0; #if defined VM_TRACE && ( ! ( defined NDB_OSE || defined NDB_SOFTOSE) ) exitAbort = "aborting"; #else exitAbort = "exiting"; #endif if(type == NST_Watchdog){ /** * Very serious, don't attempt to free, just die!! */ ndbout << "Watchdog shutdown completed - " << exitAbort << endl; #if defined VM_TRACE && ( ! ( defined NDB_OSE || defined NDB_SOFTOSE) ) signal(6, SIG_DFL); abort(); #else exit(-1); #endif } #ifndef NDB_WIN32 if (simulate_error_during_shutdown) { kill(getpid(), simulate_error_during_shutdown); while(true) NdbSleep_MilliSleep(10); } #endif globalEmulatorData.theWatchDog->doStop(); #ifdef VM_TRACE FILE * outputStream = globalSignalLoggers.setOutputStream(0); if(outputStream != 0) fclose(outputStream); #endif /** * Stop all transporter connection attempts and accepts */ globalEmulatorData.m_socket_server->stopServer(); globalEmulatorData.m_socket_server->stopSessions(); globalTransporterRegistry.stop_clients(); /** * Stop transporter communication with other nodes */ globalTransporterRegistry.stopSending(); globalTransporterRegistry.stopReceiving(); /** * Remove all transporters */ globalTransporterRegistry.removeAll(); #ifdef VM_TRACE #define UNLOAD (type != NST_ErrorHandler && type != NST_Watchdog) #else #define UNLOAD true #endif if(UNLOAD){ globalEmulatorData.theSimBlockList->unload(); globalEmulatorData.destroy(); } if(type != NST_Normal && type != NST_Restart){ ndbout << "Error handler shutdown completed - " << exitAbort << endl; #if ( defined VM_TRACE || defined ERROR_INSERT ) && ( ! ( defined NDB_OSE || defined NDB_SOFTOSE) ) signal(6, SIG_DFL); abort(); #else exit(-1); #endif } /** * This is a normal restart, depend on angel */ if(type == NST_Restart){ exit(restartType); } ndbout << "Shutdown completed - exiting" << endl; } else { /** * Shutdown is already in progress */ /** * If this is the watchdog, kill system the hard way */ if (type== NST_Watchdog){ ndbout << "Watchdog is killing system the hard way" << endl; #if defined VM_TRACE && ( ! ( defined NDB_OSE || defined NDB_SOFTOSE) ) signal(6, SIG_DFL); abort(); #else exit(-1); #endif } while(true) NdbSleep_MilliSleep(10); } }