/* * Copyright 1999-2004 The Apache Software Foundation. * * Licensed 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. */ /* * $Id: SolarisPlatformUtils.cpp 180016 2005-06-04 19:49:30Z jberry $ */ // --------------------------------------------------------------------------- // Includes // --------------------------------------------------------------------------- #if !defined (APP_NO_THREADS) # if defined (XML_USE_DCE) # include # else # include # endif #endif // APP_NO_THREADS #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #if defined (XML_USE_ICU_TRANSCODER) #include #else // use native transcoder #include #endif #if defined (XML_USE_ICU_MESSAGELOADER) #include #elif defined (XML_USE_ICONV_MESSAGELOADER) #include #else // use In-memory message loader #include #endif #if defined (XML_USE_NETACCESSOR_LIBWWW) #include #elif defined (XML_USE_NETACCESSOR_SOCKET) #include #endif #if defined (SOLARIS) extern "C" int ftime(struct timeb *); // Solaris headers missing this decl #endif XERCES_CPP_NAMESPACE_BEGIN // --------------------------------------------------------------------------- // XMLPlatformUtils: Private Static Methods // --------------------------------------------------------------------------- XMLNetAccessor* XMLPlatformUtils::makeNetAccessor() { #if defined (XML_USE_NETACCESSOR_LIBWWW) return new (fgMemoryManager) LibWWWNetAccessor(); #elif defined (XML_USE_NETACCESSOR_SOCKET) return new (fgMemoryManager) SocketNetAccessor(); #else return 0; #endif } // // This method is called by the platform independent part of this class // when client code asks to have one of the supported message sets loaded. // In our case, we use the ICU based message loader mechanism. // XMLMsgLoader* XMLPlatformUtils::loadAMsgSet(const XMLCh* const msgDomain) { XMLMsgLoader* retVal; try { #if defined (XML_USE_ICU_MESSAGELOADER) retVal = new (fgMemoryManager) ICUMsgLoader(msgDomain); #elif defined (XML_USE_ICONV_MESSAGELOADER) retVal = new (fgMemoryManager) MsgCatalogLoader(msgDomain); #else retVal = new (fgMemoryManager) InMemMsgLoader(msgDomain); #endif } catch(const OutOfMemoryException&) { throw; } catch(...) { panic(PanicHandler::Panic_CantLoadMsgDomain); } return retVal; } // // This method is called very early in the bootstrapping process. This guy // must create a transcoding service and return it. It cannot use any string // methods, any transcoding services, throw any exceptions, etc... It just // makes a transcoding service and returns it, or returns zero on failure. // XMLTransService* XMLPlatformUtils::makeTransService() #if defined (XML_USE_ICU_TRANSCODER) { return new (fgMemoryManager) ICUTransService; } #elif defined (XML_USE_ICONV_TRANSCODER) { return new (fgMemoryManager) IconvTransService; } #else // Use Native transcoding service { return new (fgMemoryManager) IconvTransService; } #endif // --------------------------------------------------------------------------- // XMLPlatformUtils: The panic method // --------------------------------------------------------------------------- void XMLPlatformUtils::panic(const PanicHandler::PanicReasons reason) { fgUserPanicHandler? fgUserPanicHandler->panic(reason) : fgDefaultPanicHandler->panic(reason); } // --------------------------------------------------------------------------- // XMLPlatformUtils: File Methods // --------------------------------------------------------------------------- unsigned int XMLPlatformUtils::curFilePos(FileHandle theFile , MemoryManager* const manager) { // Get the current position int curPos = tell( (int)theFile); if (curPos == -1) ThrowXMLwithMemMgr(XMLPlatformUtilsException, XMLExcepts::File_CouldNotGetSize, manager); return (unsigned int)curPos; } void XMLPlatformUtils::closeFile(FileHandle theFile , MemoryManager* const manager) { if (close((int) theFile)) ThrowXMLwithMemMgr(XMLPlatformUtilsException, XMLExcepts::File_CouldNotCloseFile, manager); } unsigned int XMLPlatformUtils::fileSize(FileHandle theFile , MemoryManager* const manager) { // Get the current position long int curPos = tell((int) theFile); if (curPos == -1) ThrowXMLwithMemMgr(XMLPlatformUtilsException, XMLExcepts::File_CouldNotGetCurPos, manager); // Seek to the end and save that value for return if (lseek( (int) theFile, 0, SEEK_END) == (off_t)-1) ThrowXMLwithMemMgr(XMLPlatformUtilsException, XMLExcepts::File_CouldNotSeekToEnd, manager); long int retVal = tell((int) theFile); if (retVal == -1) ThrowXMLwithMemMgr(XMLPlatformUtilsException, XMLExcepts::File_CouldNotSeekToEnd, manager); // And put the pointer back if (lseek((int) theFile, curPos, SEEK_SET) == (off_t)-1) ThrowXMLwithMemMgr(XMLPlatformUtilsException, XMLExcepts::File_CouldNotSeekToPos, manager); return (unsigned int)retVal; } FileHandle XMLPlatformUtils::openFile(const char* const fileName , MemoryManager* const manager) { return (FileHandle) open( fileName , O_RDONLY | O_LARGEFILE); } FileHandle XMLPlatformUtils::openFile(const XMLCh* const fileName , MemoryManager* const manager) { const char* tmpFileName = XMLString::transcode(fileName, manager); ArrayJanitor janText((char*)tmpFileName, manager); return (FileHandle) open( tmpFileName , O_RDONLY | O_LARGEFILE); } FileHandle XMLPlatformUtils::openFileToWrite(const XMLCh* const fileName , MemoryManager* const manager) { const char* tmpFileName = XMLString::transcode(fileName, manager); ArrayJanitor janText((char*)tmpFileName, manager); return (FileHandle)open( tmpFileName , O_WRONLY | O_CREAT | O_TRUNC | O_LARGEFILE, 0666); } FileHandle XMLPlatformUtils::openFileToWrite(const char* const fileName , MemoryManager* const manager) { return (FileHandle)open( fileName , O_WRONLY | O_CREAT | O_TRUNC | O_LARGEFILE, 0666); } unsigned int XMLPlatformUtils::readFileBuffer(FileHandle theFile , const unsigned int toRead , XMLByte* const toFill , MemoryManager* const manager) { ssize_t noOfItemsRead = read((int) theFile, (void*) toFill, toRead); if(noOfItemsRead == -1) { ThrowXMLwithMemMgr(XMLPlatformUtilsException, XMLExcepts::File_CouldNotReadFromFile, manager); } return (unsigned int) noOfItemsRead; } void XMLPlatformUtils::writeBufferToFile( FileHandle const theFile , long toWrite , const XMLByte* const toFlush , MemoryManager* const manager) { if (!theFile || (toWrite <= 0 ) || !toFlush ) return; const XMLByte* tmpFlush = (const XMLByte*) toFlush; ssize_t bytesWritten = 0; while (true) { bytesWritten=write((int)theFile, (const void *)tmpFlush, toWrite); if(bytesWritten == -1) { ThrowXMLwithMemMgr(XMLPlatformUtilsException, XMLExcepts::File_CouldNotWriteToFile, manager); } if (bytesWritten < toWrite) //incomplete write { tmpFlush+=bytesWritten; toWrite-=bytesWritten; bytesWritten=0; } else return; } return; } void XMLPlatformUtils::resetFile(FileHandle theFile , MemoryManager* const manager) { // Seek to the start of the file if (lseek((int) theFile, 0, SEEK_SET) == -1) ThrowXMLwithMemMgr(XMLPlatformUtilsException, XMLExcepts::File_CouldNotResetFile, manager); } // --------------------------------------------------------------------------- // XMLPlatformUtils: File system methods // --------------------------------------------------------------------------- XMLCh* XMLPlatformUtils::getFullPath(const XMLCh* const srcPath, MemoryManager* const manager) { // // NOTE: THe path provided has always already been opened successfully, // so we know that its not some pathological freaky path. It comes in // in native format, and goes out as Unicode always // char* newSrc = XMLString::transcode(srcPath, manager); ArrayJanitor janText(newSrc, manager); // Use a local buffer that is big enough for the largest legal path char absPath[PATH_MAX + 1]; //get the absolute path char* retPath = realpath(newSrc, &absPath[0]); if (!retPath) { ThrowXMLwithMemMgr(XMLPlatformUtilsException, XMLExcepts::File_CouldNotGetBasePathName, manager); } return XMLString::transcode(absPath, manager); } bool XMLPlatformUtils::isRelative(const XMLCh* const toCheck , MemoryManager* const manager) { // Check for pathological case of empty path if (!toCheck[0]) return false; // // If it starts with a slash, then it cannot be relative. This covers // both something like "\Test\File.xml" and an NT Lan type remote path // that starts with a node like "\\MyNode\Test\File.xml". // if (toCheck[0] == XMLCh('/')) return false; // Else assume its a relative path return true; } XMLCh* XMLPlatformUtils::getCurrentDirectory(MemoryManager* const manager) { char dirBuf[PATH_MAX + 2]; char *curDir = getcwd(&dirBuf[0], PATH_MAX + 1); if (!curDir) { ThrowXMLwithMemMgr(XMLPlatformUtilsException, XMLExcepts::File_CouldNotGetBasePathName, manager); } return XMLString::transcode(curDir, manager); } inline bool XMLPlatformUtils::isAnySlash(XMLCh c) { return ( chBackSlash == c || chForwardSlash == c); } // --------------------------------------------------------------------------- // XMLPlatformUtils: Timing Methods // --------------------------------------------------------------------------- unsigned long XMLPlatformUtils::getCurrentMillis() { timeb aTime; ftime(&aTime); return (unsigned long)(aTime.time*1000 + aTime.millitm); } // ----------------------------------------------------------------------- // Mutex methods // ----------------------------------------------------------------------- #if !defined (APP_NO_THREADS) // --------------------------------------------------------------------------- // XMLPlatformUtils: Platform init method // --------------------------------------------------------------------------- typedef XMLHolder MutexHolderType; static MutexHolderType* gAtomicOpMutex = 0; void XMLPlatformUtils::platformInit() { // // The gAtomicOpMutex mutex needs to be created // because compareAndSwap and incrementlocation and decrementlocation // does not have the atomic system calls for usage // Normally, mutexes are created on first use, but there is a // circular dependency between compareAndExchange() and // mutex creation that must be broken. gAtomicOpMutex = new (fgMemoryManager) MutexHolderType; #if defined(XML_USE_DCE) if (pthread_mutex_init(&gAtomicOpMutex->fInstance, pthread_mutexattr_default)) { #else // XML_USE_DCE if (pthread_mutex_init(&gAtomicOpMutex->fInstance, NULL)) { #endif // XML_USE_DCE delete gAtomicOpMutex; gAtomicOpMutex = 0; panic( PanicHandler::Panic_SystemInit ); } } #ifndef XML_USE_DCE // inlining the class with dce threading causes segmentation fault class RecursiveMutex : public XMemory { public: pthread_mutex_t mutex; int recursionCount; pthread_t tid; MemoryManager* const fMemoryManager; RecursiveMutex(MemoryManager* manager) : mutex(), recursionCount(0), tid(0), fMemoryManager(manager) { if (pthread_mutex_init(&mutex, NULL)) XMLPlatformUtils::panic(PanicHandler::Panic_MutexErr); } ~RecursiveMutex() { if (pthread_mutex_destroy(&mutex)) ThrowXMLwithMemMgr(XMLPlatformUtilsException, XMLExcepts::Mutex_CouldNotDestroy, fMemoryManager); } void lock() { if (pthread_equal(tid, pthread_self())) { recursionCount++; return; } if (pthread_mutex_lock(&mutex) != 0) XMLPlatformUtils::panic(PanicHandler::Panic_MutexErr); tid = pthread_self(); recursionCount = 1; } void unlock() { if (--recursionCount > 0) return; if (pthread_mutex_unlock(&mutex) != 0) XMLPlatformUtils::panic(PanicHandler::Panic_MutexErr); tid = 0; } }; #endif // ifndef XML_USE_DCE void* XMLPlatformUtils::makeMutex(MemoryManager* manager) { #if defined(XML_USE_DCE) MutexHolderType* const holder = new (manager) MutexHolderType; if (holder == NULL) { panic(PanicHandler::Panic_MutexErr); } pthread_mutexattr_t attr; pthread_mutexattr_create(&attr); pthread_mutexattr_setkind_np(&attr, MUTEX_RECURSIVE_NP); if (pthread_mutex_init(&holder->fInstance, attr)) { panic(PanicHandler::Panic_MutexErr); } pthread_mutexattr_delete(&attr); return holder; #else return new (manager) RecursiveMutex(manager); #endif } void XMLPlatformUtils::closeMutex(void* const mtxHandle) { if (mtxHandle == NULL) return; #if defined(XML_USE_DCE) MutexHolderType *rm = MutexHolderType::castTo(mtxHandle); pthread_mutex_destroy(&rm->fInstance); #else RecursiveMutex *rm = (RecursiveMutex *)mtxHandle; #endif delete rm; } void XMLPlatformUtils::lockMutex(void* const mtxHandle) { if (mtxHandle == NULL) return; #if defined(XML_USE_DCE) MutexHolderType *rm = MutexHolderType::castTo(mtxHandle); pthread_mutex_lock(&rm->fInstance); #else RecursiveMutex *rm = (RecursiveMutex *)mtxHandle; rm->lock(); #endif } void XMLPlatformUtils::unlockMutex(void* const mtxHandle) { if (mtxHandle == NULL) return; #if defined(XML_USE_DCE) MutexHolderType *rm = MutexHolderType::castTo(mtxHandle); pthread_mutex_unlock(&rm->fInstance); #else RecursiveMutex *rm = (RecursiveMutex *)mtxHandle; rm->unlock(); #endif } // ----------------------------------------------------------------------- // Miscellaneous synchronization methods // ----------------------------------------------------------------------- //atomic system calls in Solaris is only restricted to kernel libraries //So, to make operations thread safe we implement static mutex and lock //the atomic operations. It makes the process slow but what's the alternative! void* XMLPlatformUtils::compareAndSwap ( void** toFill , const void* const newValue , const void* const toCompare) { //return ((void*)cas32( (uint32_t*)toFill, (uint32_t)toCompare, (uint32_t)newValue) ); // the below calls are temporarily made till the above functions are part of user library // Currently its supported only in the kernel mode if (pthread_mutex_lock(&gAtomicOpMutex->fInstance)) panic(PanicHandler::Panic_SynchronizationErr); void *retVal = *toFill; if (*toFill == toCompare) *toFill = (void *)newValue; if (pthread_mutex_unlock(&gAtomicOpMutex->fInstance)) panic(PanicHandler::Panic_SynchronizationErr); return retVal; } int XMLPlatformUtils::atomicIncrement(int &location) { //return (int)atomic_add_32_nv( (uint32_t*)&location, 1); if (pthread_mutex_lock(&gAtomicOpMutex->fInstance)) panic(PanicHandler::Panic_SynchronizationErr); int tmp = ++location; if (pthread_mutex_unlock(&gAtomicOpMutex->fInstance)) panic(PanicHandler::Panic_SynchronizationErr); return tmp; } int XMLPlatformUtils::atomicDecrement(int &location) { //return (int)atomic_add_32_nv( (uint32_t*)&location, -1); if (pthread_mutex_lock(&gAtomicOpMutex->fInstance)) panic(PanicHandler::Panic_SynchronizationErr); int tmp = --location; if (pthread_mutex_unlock(&gAtomicOpMutex->fInstance)) panic(PanicHandler::Panic_SynchronizationErr); return tmp; } #else // #if !defined (APP_NO_THREADS) void XMLPlatformUtils::platformInit() { } void XMLPlatformUtils::closeMutex(void* const) { } void XMLPlatformUtils::lockMutex(void* const) { } void* XMLPlatformUtils::makeMutex(MemoryManager*) { return 0; } void XMLPlatformUtils::unlockMutex(void* const) { } void* XMLPlatformUtils::compareAndSwap ( void** toFill, const void* const newValue, const void* const toCompare) { void *retVal = *toFill; if (*toFill == toCompare) *toFill = (void *)newValue; return retVal; } int XMLPlatformUtils::atomicIncrement(int &location) { return ++location; } int XMLPlatformUtils::atomicDecrement(int &location) { return --location; } #endif // APP_NO_THREADS FileHandle XMLPlatformUtils::openStdInHandle(MemoryManager* const manager) { return (FileHandle)dup(0); } void XMLPlatformUtils::platformTerm() { #if !defined(APP_NO_THREADS) pthread_mutex_destroy(&gAtomicOpMutex->fInstance); delete gAtomicOpMutex; gAtomicOpMutex = 0; #endif } #include XERCES_CPP_NAMESPACE_END