Merge branch '138-toggle-free-look-with-hotkey' into 'main/atys-live'
[ryzomcore.git] / nel / src / misc / shared_memory.cpp
blobc6eea8e9f6844d8f9d4ee8d55a83e07e2b19681c
1 // NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
2 // Copyright (C) 2010 Winch Gate Property Limited
3 //
4 // This source file has been modified by the following contributors:
5 // Copyright (C) 2015 Jan BOON (Kaetemi) <jan.boon@kaetemi.be>
6 //
7 // This program is free software: you can redistribute it and/or modify
8 // it under the terms of the GNU Affero General Public License as
9 // published by the Free Software Foundation, either version 3 of the
10 // License, or (at your option) any later version.
12 // This program is distributed in the hope that it will be useful,
13 // but WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 // GNU Affero General Public License for more details.
17 // You should have received a copy of the GNU Affero General Public License
18 // along with this program. If not, see <http://www.gnu.org/licenses/>.
20 #include "stdmisc.h"
22 #include "nel/misc/shared_memory.h"
23 #include "nel/misc/debug.h"
25 #ifndef NL_OS_WINDOWS
26 # include <sys/types.h>
27 # include <sys/ipc.h>
28 # include <sys/shm.h>
29 #endif
31 using namespace std;
33 #ifdef DEBUG_NEW
34 #define new DEBUG_NEW
35 #endif
37 namespace NLMISC {
40 #ifdef NL_OS_WINDOWS
41 // Storage for file handles, necessary to close the handles
42 map<void*,HANDLE> AccessAddressesToHandles;
43 #else
44 // Storage for shmid, necessary to destroy the segments
45 map<TSharedMemId, sint> SharedMemIdsToShmids;
46 #endif
50 * Create a shared memory segment
52 void *CSharedMemory::createSharedMemory( TSharedMemId sharedMemId, uint32 size )
54 #ifdef NL_OS_WINDOWS
56 // Create a file mapping backed by the virtual memory swap file (not a data file)
57 HANDLE hMapFile = CreateFileMappingA( INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, size, sharedMemId );
58 if ( (hMapFile == NULL) || (GetLastError() == ERROR_ALREADY_EXISTS) )
60 nlwarning( "SHDMEM: Cannot create file mapping for smid %s: error %u%s, mapFile %p", sharedMemId, GetLastError(), (GetLastError()==ERROR_ALREADY_EXISTS) ? " (already exists) ": "", hMapFile );
61 return NULL;
63 //else
64 // nldebug( "SHDMEM: Creating smid %s --> mapFile %p", sharedMemId, hMapFile );
67 // Map the file into memory address space
68 void *accessAddress = MapViewOfFile( hMapFile, FILE_MAP_ALL_ACCESS, 0, 0, 0 );
69 AccessAddressesToHandles.insert( make_pair( accessAddress, hMapFile ) );
70 /*if ( accessAddress == NULL )
72 nlwarning( "SHDMEM: Cannot map view of file: error %u", GetLastError() );
73 }*/
74 return accessAddress;
76 #else
78 // Create a shared memory segment
79 sint shmid = shmget( sharedMemId, size, IPC_CREAT | IPC_EXCL | 0666 );
80 if ( shmid == -1 )
81 return NULL;
82 SharedMemIdsToShmids.insert( make_pair( sharedMemId, shmid ) );
84 // Map the segment into memory address space
85 void *accessAddress = (void*)shmat( shmid, 0, 0 );
86 if ( accessAddress == (void*)-1 )
87 return NULL;
88 else
89 return accessAddress;
91 #endif
96 * Get access to an existing shared memory segment
98 void *CSharedMemory::accessSharedMemory( TSharedMemId sharedMemId )
100 #ifdef NL_OS_WINDOWS
102 // Open the existing file mapping by name
103 HANDLE hMapFile = OpenFileMappingA( FILE_MAP_ALL_ACCESS, false, sharedMemId );
104 if ( hMapFile == NULL )
105 return NULL;
106 //nldebug( "SHDMEM: Opening smid %s --> mapFile %p", sharedMemId, hMapFile );
108 // Map the file into memory address space
109 void *accessAddress = MapViewOfFile( hMapFile, FILE_MAP_ALL_ACCESS, 0, 0, 0 );
110 AccessAddressesToHandles.insert( make_pair( accessAddress, hMapFile ) );
111 return accessAddress;
113 #else
115 // Open an existing shared memory segment
116 int shmid = shmget( sharedMemId, 0, 0666 );
117 if ( shmid == -1 )
118 return NULL;
120 // Map the segment into memory address space
121 void *accessAddress = (void*)shmat( shmid, 0, 0 );
122 if ( accessAddress == (void*)-1 )
123 return NULL;
124 else
125 return accessAddress;
127 #endif
132 * Close (detach) a shared memory segment
134 bool CSharedMemory::closeSharedMemory( void *accessAddress )
136 #ifdef NL_OS_WINDOWS
138 bool result = true;
140 // Unmap the file from memory address space
141 if ( UnmapViewOfFile( accessAddress ) == 0 )
143 nlwarning( "SHDMEM: UnmapViewOfFile failed: error %u", GetLastError() );
144 result = false;
147 // Close the corresponding handle
148 map<void*,HANDLE>::iterator im = AccessAddressesToHandles.find( accessAddress );
149 if ( im != AccessAddressesToHandles.end() )
151 //nldebug( "SHDMEM: CloseHandle mapFile %u", (*im).second );
152 if ( ! CloseHandle( (*im).second ) )
153 nlwarning( "SHDMEM: CloseHandle failed: error %u, mapFile %u", GetLastError(), (*im).second );
154 AccessAddressesToHandles.erase( im );
155 return result;
157 else
159 return false;
162 #else
164 // Detach the shared memory segment
165 return ( shmdt( accessAddress ) != -1 );
167 #endif
172 * Destroy a shared memory segment (to call only by the process that created the segment)
173 * Note: does nothing under Windows, it is automatic.
174 * "Rescue feature": set "force" to true if a segment was created and left out of
175 * control (meaning a new createSharedMemory() with the same sharedMemId fails), but
176 * before, make sure the segment really belongs to you!
178 * Note: this method does nothing under Windows, destroying is automatic.
179 * Under Unix, the segment will actually be destroyed after the last detach
180 * (quoting shmctl man page). It means after calling destroySharedMemory(), the
181 * segment is still accessible by another process until it calls closeSharedMemory().
183 void CSharedMemory::destroySharedMemory( TSharedMemId sharedMemId, bool force )
185 #ifndef NL_OS_WINDOWS
186 // Set the segment to auto-destroying (when the last process detaches)
187 map<TSharedMemId,int>::iterator im = SharedMemIdsToShmids.find( sharedMemId );
188 if ( im != SharedMemIdsToShmids.end() )
190 // Destroy the segment created before
191 shmctl( (*im).second, IPC_RMID, 0 );
192 SharedMemIdsToShmids.erase( im );
194 else if ( force )
196 // Open and destroy the segment
197 int shmid = shmget( sharedMemId, 0, 0666 );
198 if ( shmid != -1 )
200 // Destroy the segment
201 shmctl( shmid, IPC_RMID, 0 );
204 #endif
208 } // NLMISC