Shared memory in DLLs
Hi,
I'm at my first attempt at creating a DLL that utilizes memory area that is shared between all instances of the DLL. This is the shared section declaration:
#pragma data_seg(".ESC_SHARED")
unsigned char sg_pXMLBuffer[XMLBUFFER_SIZE];
volatile bool sg_bLocked;
Message sg_iMessage = MSG_NoMessage;
#pragma data_seg()
#pragma comment(linker,"/SECTION:.ESC_SHARED,RWS")
The idea is that an application should be able to post a message in the sg_iMessage, telling another instance to retrieve the data in sg_pXMLBuffer and process it. The problem is that the data in sg_pXMLBuffer never changes in the "remote" instance. The other variables (sg_bLocked and sg_iMessage) propagate nicely into all other instances, but when i change something in sg_PXMLBuffer, it still appears to be all 0's in the other instances. Why? XMLBUFFER_SIZE is 32k by the way.
EDIT: I should probably add that I'm using VS2005
[977 byte] By [
korona] at [2007-11-11 9:51:27]

# 1 Re: Shared memory in DLLs
Found it myself.
For anyone who interested:
It turns out I need to initialize the memory or it will be "optimized away"(?).
The following works fine:
#pragma data_seg(".ESC_SHARED")
unsigned char sg_pXMLBuffer[XMLBUFFER_SIZE] = { 0 };
volatile bool sg_bLocked = false;
MessengerMessage sg_iMessage = MSG_NoMessage;
HHOOK sg_hCallCBTHook = 0;
#pragma data_seg()
#pragma comment(linker,"/SECTION:.ESC_SHARED,RWS")
Feel free to lock the thread :)
korona at 2007-11-11 20:59:49 >

# 2 Re: Shared memory in DLLs
Is there a reason why sg_pXMLBuffer isn't volatile? It could also be the cause of that "optimization".
Danny at 2007-11-11 21:00:55 >

# 3 Re: Shared memory in DLLs
i didn't declare it volatile since i wont be looking for changes in it in a tight loop, as I do with sg_bLocked. As such:
while(sg_bLocked)
;
So i figured it wouldn't be subject to cache trouble. However, it should be pointed out that my understanding of when to declare stuff as volatile isn't as good as I'd like it to be. I rarely use it, and most often it's on data that might be changed by another thread, an interrupt etc.
korona at 2007-11-11 21:01:53 >

# 4 Re: Shared memory in DLLs
volatile has little to do with tight loops. You should declare any object that can be changed asynchronously as volatile. In this case, sg_pXMLBuffer might be modified by another thread or DLL asynchronously. If another thread has a cached copy of sg_pXMLBuffer, and the memory buffer has changed behind its back, the program's behavior is undefined.
Danny at 2007-11-11 21:02:54 >

# 5 Re: Shared memory in DLLs
Hi,
I'm at my first attempt at creating a DLL that utilizes memory area that is shared between all instances of the DLL. This is the shared section declaration:
#pragma data_seg(".ESC_SHARED")
unsigned char sg_pXMLBuffer[XMLBUFFER_SIZE];
volatile bool sg_bLocked;
Message sg_iMessage = MSG_NoMessage;
#pragma data_seg()
#pragma comment(linker,"/SECTION:.ESC_SHARED,RWS")
Unfortunately the pragma data_seg() won't work in c++ builder and it may not work in some other compilers (other than VC++). So here's another solution to creating a shared memory area.
HANDLE hsm = 0; //handle to a shared memory file
LPVOID lpshrmem = NULL; //pointer to shared memory area
int WINAPI DllEntryPoint(HINSTANCE hinst, unsigned long reason, void* lpReserved)
{
bool initproc=0;
switch (reason) {
case DLL_PROCESS_ATTACH:
hsm = CreateFileMapping((HANDLE)0xffffffff,NULL, PAGE_READWRITE,0,1024,"DLLSHAREDDATA");
if (!hsm)
return 0;
initproc = (GetLastError() != ERROR_ALREADY_EXISTS);
lpshrmem = MapViewOfFile(hsm, FILE_MAP_WRITE,0,0,0);
if (!lpshrmem)
return 0;
if (initproc)
memset(lpshrmem, '\0',1024);//zero initialize the memory
break;
case DLL_THREAD_ATTACH:
//DisableThreadLibraryCalls(hinst);
break;
// The thread of the attached process terminates.
case DLL_THREAD_DETACH:
break;
case DLL_PROCESS_DETACH:
// Unmap shared memory from the process's address space.
UnmapViewOfFile(lpshrmem);
// Close the process's handle to the file-mapping object.
CloseHandle(hsm);
break;
default:
break; }
return 1;
}
Ivan** at 2007-11-11 21:03:58 >

# 6 Re: Shared memory in DLLs
You're right, #prgamas by their nature aren't portable so it's best to avoid them when possible if the code is meant to be used by various compilers. Anyway, you should note that this code will only work on specific variants of Windows, certainly not POSIX.
Also, instead of using hard coded literals and magic numbers such as 1024 it's best to use a constant. Different OSs have different page sizes. Finally, I would check the initproc value right after assigning it.
Danny at 2007-11-11 21:04:58 >

# 7 Re: Shared memory in DLLs
Is there a reason why sg_pXMLBuffer isn't volatile? It could also be the cause of that "optimization".Is there a reason why sg_pXMLBuffer isn't volatile
geeta at 2007-11-11 21:05:56 >

# 8 Re: Shared memory in DLLs
Is there a reason why sg_pXMLBuffer isn't volatile
Is there a reason why sg_pXMLBuffer isn't volatile
geeta at 2007-11-11 21:07:00 >

# 9 Re: Shared memory in DLLs
Hi, Danny
initproc need not be checked first because the first dll to create a shared memory area will initialize the memory. The other dll instances will always have 0 for initproc and MapViewOfFile will simply return a pointer to the already allocated shared memory.
Ivan** at 2007-11-11 21:07:57 >

# 10 Re: Shared memory in DLLs
OK, another nit. Wouldn't it be better to declare it like this:
bool initproc = (GetLastError() != ERROR_ALREADY_EXISTS);
I would also prefer a Boolean value as the initializer, i.e., bool initproc=false. Anyway, thanks for the clarification.
Danny at 2007-11-11 21:09:04 >

# 11 Re: Shared memory in DLLs
As far as volatility goes, korona, you are confusing "volatile" with "register". Register is a suggestion to the compiler to place the variable in a register for faster access. Volatile on the other hand, means asynchronous access, as was mentioned above.
I would personally use GlobalAlloc with GMEM_MOVEABLE and GMEM_SHARED, but I supposed you can do it this way. Are there any advantages to one way or another?
val at 2007-11-11 21:10:03 >
