[interprocess] linux porting problems

Hi - I am having problems porting some boost::interprocess code from Win32 to Linux (rhel4). I am using boost-1.55. Here's the setup: I need to find if there is an existing instance of the process already running. When the process starts up, it checks the shared memory for a bIsProcessingRunning flag. If it is true, the process dumps some data into the shared memory and then exits. If not true, then the process starts up normally and then checks the shared memory for any updates. The class I use to wrap the boost::interprocess is below. Note: I needed the shared memory location to only be initialized the first time it was created so the only way I saw how to do it was through the src code was to use the initialization_func_t(). This approach works fine on Win32 but on Linux, it doesn't work. Thanks in advance for any suggestions or hints. ------------------------------------------------------------- #pragma once #include <boost/interprocess/shared_memory_object.hpp> #include <boost/interprocess/detail/managed_open_or_create_impl.hpp> #include <boost/interprocess/mapped_region.hpp> #include <boost/interprocess/sync/scoped_lock.hpp> #include <boost/interprocess/sync/interprocess_mutex.hpp> //---------------------------------------------------------------- // SSharedData // Structure of shared memory data contents //---------------------------------------------------------------- struct SSharedData { SSharedData() : bIsProcessRunning( false ), bIsData( false ), argc( 0 ) { } //Mutex to protect access to the queue boost::interprocess::interprocess_mutex mutex; bool bIsProcessRunning; bool bIsData; int argc; char argv[100][100]; }; //---------------------------------------------------------------- // CSharedMemory // Wrapper class to boost::interprocess for shared memory //---------------------------------------------------------------- class CSharedMemory { public: //---------------------------------------------------------------- // initialization_func_t // helper class to initialize shared memory to SSharedData //---------------------------------------------------------------- class initialization_func_t { public: initialization_func_t() {} bool operator()( void *pAddress, std::size_t nSize, bool bCreated ) { char *mptr; if( bCreated ) { mptr = reinterpret_cast<char*>(pAddress); // construct shared data structure BOOST_TRY { new (mptr) SSharedData(); } BOOST_CATCH( ... ) { return false; } BOOST_CATCH_END } return true; } }; public: CSharedMemory( std::string sName ) : m_pData( NULL ) { try { // erase previous shared memory boost::interprocess::shared_memory_object::remove( sName.c_str() ); // open a tempory shared memory object m_pShmem = new boost::interprocess::detail::managed_open_or_create_impl<boost::interprocess::s hared_memory_object>( boost::interprocess::open_or_create, sName.c_str() , sizeof( SSharedData ), boost::interprocess::read_write, (void*)0, //Prepare initialization functor initialization_func_t() ); // get the address of the mapped region void *pAddr = m_pShmem->get_address(); // construct the shared structure in memory m_pData = static_cast<SSharedData*>(pAddr); } catch( boost::interprocess::interprocess_exception &ex ) { std::cout << ex.what() << std::endl; } } ~CSharedMemory() { delete m_pShmem; } SSharedData *GetData() { return m_pData; } protected: SSharedData *m_pData; boost::interprocess::detail::managed_open_or_create_impl< boost::interprocess::shared_memory_object > *m_pShmem; };

Daren Lee wrote:
Hi -
I am having problems porting some boost::interprocess code from Win32 to Linux (rhel4). I am using boost-1.55.
Here's the setup: I need to find if there is an existing instance of the process already running. When the process starts up, it checks the shared memory for a bIsProcessingRunning flag. If it is true, the process dumps some data into the shared memory and then exits. If not true, then the process starts up normally and then checks the shared memory for any updates. The class I use to wrap the boost::interprocess is below.
Note: I needed the shared memory location to only be initialized the first time it was created so the only way I saw how to do it was through the src code was to use the initialization_func_t().
This approach works fine on Win32 but on Linux, it doesn't work.
Thanks in advance for any suggestions or hints.
Which version of Interprocess are you using, CVS version? And I suppose you meant Boost-1.35? Regards, Ion

Hi Daren,
Hi -
I am having problems porting some boost::interprocess code from Win32 to Linux (rhel4). I am using boost-1.55.
Here's the setup: I need to find if there is an existing instance of the process already running. When the process starts up, it checks the shared memory for a bIsProcessingRunning flag. If it is true, the process dumps some data into the shared memory and then exits. If not true, then the process starts up normally and then checks the shared memory for any updates. The class I use to wrap the boost::interprocess is below.
Note: I needed the shared memory location to only be initialized the first time it was created so the only way I saw how to do it was through the src code was to use the initialization_func_t().
This approach works fine on Win32 but on Linux, it doesn't work.
Thanks in advance for any suggestions or hints.
In the code you've attached I see that you are using managed_open_or_create_impl which is a implementation detail class. You shouldn't use it, because this might change. I understand that you wanted to execute an atomic functor when creating the shared memory and that possibility is not in the public interface, so I think this is an option I should add ASAP. Now, looking the code I see that you try to erase the shared memory every time in the CSharedMemory class: // erase previous shared memory boost::interprocess::shared_memory_object::remove( sName.c_str() ); This function works just like "std::remove" works with files and in UNIX systems we can remove a file while it's been used. In UNIX we can remove a shared memory segment while it's in use (well, actually, the file/shared memory becomes "unaccessible", and although it's not physically erased until processes attached to that removed segment end, the name can be reused for new processes creating new segments. This means that in Windows, if there is another process using the shared memory, the remove call will not success and you will find that the shared memory is initialized with data. In Unix, the shared memory will be removed from the filesystem (that is, won't be found using open/create) and although you try to create a shared memory with the same name you will crate a new, fresh, uninitialized segment. You can find more about UNIX behavior here: http://www.opengroup.org/onlinepubs/009695399/functions/shm_unlink.html This is really the same portability problem we have with files between Windows and Unix and something I haven't solved yet. And it seems that it's not an easy task, because we are talking about a resource that it's shared between processes. I'm afraid you will need to find a better way to know if a process is already active... Maybe if you comment "remove" from the code you might get what you want, but then you have a problem to know when to remove the shared memory segment. Regards, Ion

Hi Ion, Thanks for the great info about the differences between boost::interprocess on Windows and Unix. That explains a lot. Maybe I'll try opening the shared memory with the "open_only" flag first and then checking for any exceptions. Btw, I am using the CVS version of interprocess. Thanks for your great work on this nice library. -Daren

Hi Ion, I mananged to get something working on Linux by doing a try-catch block on an "open_only" shmem object. It works fine on normal program exit. However, as you probably know, if the program is killed or crashed there is a dangling reference since remove/shm_unlink is never called. So I'm wondering: 1) is there any way around this behavior on a kill/crash? 2) is there a way to manually remove the shared memory besides rebooting? (i tried using ipcrm but it looks like it still thinks there are processes attached). Thanks, Daren

Hi Daren,
Hi Ion,
I mananged to get something working on Linux by doing a try-catch block on an "open_only" shmem object. It works fine on normal program exit. However, as you probably know, if the program is killed or crashed there is a dangling reference since remove/shm_unlink is never called.
So I'm wondering: 1) is there any way around this behavior on a kill/crash?
I haven't found a solution. Interprocess' ancestor, Shmem, emulated reference counted semantics in Linux trying to be similar to Windows, but I couldn't manage crashes. So Interprocess took a different approach: Linux persistence for Windows shared memory. Current Interprocess persistence semantics are explained in the documentation here: http://ice.prohosting.com/newfunk/boost/libs/interprocess/ doc/html/interprocess/some_basic_explanations.html #interprocess.some_basic_explanations.persistence
2) is there a way to manually remove the shared memory besides rebooting? (i tried using ipcrm but it looks like it still thinks there are processes attached).
Memory is created using POSIX shm_open() so it's platform defined if the shared memory is visible in the filesystem. In Linux, I think that shared memory is created in /dev/shm. You can use shell's "rm /dev/shm/file" to get the same behavior as shm_unlink(). If you find a way to manage crashes, I would be really, really happy. I revised several portable run-time implementations (apache, cygwin, etc...) but no-one, as far as I know has solved this. Regards, Ion
participants (2)
-
Daren Lee
-
Ion Gaztañaga