Getting Shared Memory Attach failure on windows ?
Anubhuti Kaushik 060000XD9S Visits (2114)
The other day I was suddenly unable to start the region which was coming up fine from past 3 months.
The error in console looked like this:
ERZ074081I/7442 10/03/13 06:27:11.089546900 testan 2608/0001 : Starting region with attribute override 'StartType=cold'.
I could make out that CICS was unable to attach to the Region Pool which is one of the RD Stanza attributes.
Symrecs showed like this.
SYMPTOMS = TIME/"10/03/13 06:27:11.098336000" REGION/testan PROD/5724NT710 LVLS/810 MOD/"@(#)stoma, 22:04:15, Sep 7 2013" FUNC/StoMA_Init LINE/392 MS/060008 MSN/14 SRC/0 PRCS/487 ABCODE/ SRVID/1880320373 PID/2608 TID/1 PROC/
PRCS is the error that is returned by Operating System when a OS call fails. In this case I took CICS TRACE and found out that PRCS is returned by Windows function MapViewOfFileEx. This function is called whenever a process tried to attach to a shared memory segment.
I searched MSDN to find out in what scenarios error no 487 is returned by MapViewOfFileEx.
MSDN enlightened me a bit though not much! So what MSDN did tell me was that if the address at which the process is trying to attach is not available MapViewOfFileEx fails with error 487.
Now why is this address occupied, I dint do anything. I barely started my region!
Answer to this question comes from the way Windows loads the libraries in a executable. Most of the operating systems have different segments dedicated to process data, heap, code , stack, shared libraries, and shared segment. We call these segments as data segment, heap segment, shared memory segment, code segment etc. Any call to malloc() or other such memory allocation routine will always return you an address from heap segment. Similarly, a call to shared memory creation will be catered by shared memory segment only.
But in Windows, it is different. In Windows, 2 GB of process image is undivided. There is no demarcation between data segment, heap segment, code segment, shared memory segment etc. So when a process starts it has to load lot of dependent libraries. Windows loads all these libraries anywhere within 2GB of Process Address space. Some times it loads some module at the address which you might have specified in RD stanza for RegionPoolBase.
In such a scenario, you need to know the memory map of the failing process. With the help of memory map you can identify a free address which is large enough to accomodate RegionPool.
Various tools like ProcDump.exe or other debugging tools can be used to get a memory map. I trust my old WinDbg
This is what I tried to get the memory map. Click on WinDbg from Program Files.
Once WinDbg executable opens, from Main Menu click File -> Open Executable
Browse to 'CICS Install Directory'/bin/
Supply Arguments -> -r <region name>
Tick Debug Child Processes option also
Finally Click Open
You will see something like below in your WinDbg Window. This is the list of all the modules that are loaded by this executable. Second column shows Starting Load address of the module. Third Column shows end address till where the module is loaded.
The default value of RegionPoolBase is0x70000000. You also need to see the value of MaxRegionPool. Memory of size MaxRegionPool starting from RegionPoolBase must be free for MapViewOfFileEx call to succeed. If you observe here , libEncServer.dll is loaded at 71460000 which means that enough memory is not free to cater the request.
Now you need to find out an address which has contigous memory of MaxRegionPool size free. I can see 4th Segment free here. So I change my RegionPoolBase to 4th segment. I also need to change the TasksharedPoolBase depending upon MaxTSHPool Size. I set these values, and restart the region with StartType=cold.
Phew! the region started!
You can use the similar logic to debug shared memory attach problem in any other process like sfs server, or cicsgc. These processes try to attach to CIPC shared memory default base address for which is 5th segment.
Hope this helps.