- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Hi,
Recently we've upgraded toVisual Studio 2005 and since then we've had problems unloading and reloading DLL's containing Fortran code on some, but not all, of our workstations. The workstations that fail invariably have non-hyper-threaded single-core processors. The program cores in for_thread_clean because the object code is no longer present!
The main program is C++ Windows MFC application, that includes some Fortran code. It includes the following to initialize and clean up Fortran RTL support. All libraries (Fortran, MFC, ...) are statically linked to this program to avoidrun-time issues (this software is shipped all over the world and statically linking really cuts down on support issues).
BOOL CMyApp::InitInstance()
{
for_rtl_init_(0,0);
CConsoleApp* pConsoleApp = new CConsoleApp();
...
}
void CMyApp::ExitInstance()
{
delete pConsoleApp;
pConsoleApp = NULL;
for_rtl_finish_();
CWinApp::ExitInstance();
}
The main program loads a DLL that started off life many years ago as a Fortran console application. As with the main program, this DLL is statically linked with Fortran, MFC and other libraries.
CConsoleApp::CConsoleApp()
{
hDll=LoadLibrary("ConsoleApp.dll");
...
}
CConsoleApp::~CConsoleApp()
{
FreeLibrary(hDll);
hDll = NULL;
}
The Fortran RTL support for the DLL is managed as follows:
BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fwdReason,
LPVOID lpvReserved)
{
switch(fwdReason)
case DLL_PROCESS_ATTACH:
for_rtl_init_(0,0);
break;
case DLL_PROCESS_DETACH:
for_rtl_finish_();
break;
}
return TRUE;
}
Now to the problem... On debug builds, the program will occasionally core between the call to for_rtl_finish in DllMain and the "hDll = NULL" instruction in the CConsoleApp destructor. On release builds, substitute "occasionally" by "always". Thank goodness though that it does sometimes fail in the debug build, because that is how we found that the memory address it failed on was code belonging to the for_thread_clean function, which had already been unloaded before the call took place.
A workaround to this problem is to Sleep(1000) just after the call to for_rtl_finish win DllMain, butI really don't want to include this type of workaround in a production build.
By the way, we can't avoid the call to FreeLibrary (which would solve the problem), since we give the user the ability to rewind and restart the Console application, which we do by deleti ng the CConsoleApp instance and creating a new one. We unload and reload the DLL to ensure that all Fortran static variables get properly initialized.
And now to the questions...
-
Has anyone else out thererun into the same type of problem and did you come up with a solution?
-
Does for_rtl_finish spawn threads to do its work? We've thought about testing for this via the same methodology as Spy++ but it is likely easier to write this small novel than it would be to figure out the details.
-
Any suggestions?
Thanks,
Brian.
Link Copied
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Hi Steve,
We are running Fortran 10.1.4156.2005 with Microsoft Visual Studio 2005 Version 8.0.50727.762 (SP.050727-7600).
Thanks,
Brian.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Hi Steve,
Sorry 'bout that;it's Intel Visual Fortran Compiler for applications running on IA-32, Version 10.1Build 20080312 Package ID: w_fc_o_10.1.021.
And yes, we most likely do internal Fortran internal I/O. Right after the call to for_rtl_init(0,0) in the C++ main, there is a call to a Fortran subroutine that should have taken care of this old Compaq bug.
INITFORTRANWRITEBUG();
The Fortran code is as follows:(I'm not sure why we declare i, but this is really old code and if it ain't broke, well you know how that goes...)
subroutine InitFortranWriteBug
character*4 t
integer i
write (t,'(a)') 'TEST'
return
end
I'm going to go add a call to this same function in DllMain and get back to you on the results!
Thanks,
Brian.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
USE IFCORE
...
INTEGER(4) MODE
Now, where you have your internal write, do this:
MODE = FOR_SET_REENTRANCY(FOR_K_REENTRANCY_ASYNCH)
write(t,'(a)') 'TEST'
MODE = FOR_SET_REENTRANCY(MODE)
You're bracketing the write with the calls to FOR_SET_REENTRANCY. If you have multiple such writes you can surround all of them with one set of calls.
I am told that this is fixed in 10.1.025, but my tests so far are inconclusive.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
bfrancis:
I'm going to go add a call to this same function in DllMain and get back to you on the results!
Well, that didn't make things any better, and perhaps made them a little worse since I think its dying a little earlier and on a different routine (msportlib_d_writechar).
At the point of failure there is a thread as follows (I've got no cut and paste from thedevelopment side of the business to my email, so there may be typo's in the following):
NTDLL.DLL!77f88f13()
[Frames below may be incorrect and/or missing...]
KERNEL32.DLL!7c59a0a2()
KERNEL32.DLL!7c57b40f()
pos180gw.exe!_for__thread_clean() + 0x1b bytes
pos180gw.exe!_callthreadstart() Line 293 + 0xf bytes
pos180gw.exe!_threadstart(void* ptd=0x017b40e0) Line 277
KERNEL32.DLL!7c57b3bc()
Looking in _for__thread_clean() at this point we see:
call dword ptr [__imp__WaitForSingleObject@8 (96C96Ch)]
test eax,eax
This is what causes the failure in the release build that I first mentioned. The call to FreeLibrary() has removed the code from memory while we are still waiting on an event in the Fortran RTL thread cleanup. When this event finally does fire, the code has been removed. When I add the 1 second delay after the call to for_rtl_finish, the problem goes away, but this is not a solution, its a bandaid (and a pretty thin one at that).
What I'm looking for is some way to wait after the call to for_rtl_finish, to ensure that all Fortran RTL processing has completed.
Thanks,
Brian.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
MADsblionel:
Try this. In the Fortran routine with the internal write, add:
USE IFCORE
...
INTEGER(4) MODE
Now, where you have your internal write, do this:
MODE = FOR_SET_REENTRANCY(FOR_K_REENTRANCY_ASYNCH)
write(t,'(a)') 'TEST'
MODE = FOR_SET_REENTRANCY(MODE)
You're bracketing the write with the calls to FOR_SET_REENTRANCY. If you have multiple such writes you can surround all of them with one set of calls.
I am told that this is fixed in 10.1.025, but my tests so far are inconclusive.
Hi Steve,
I tried your suggestion in our INITFORTRANWRITEBUG subroutine but it made no difference in the results. Wrapping every internal Fortran I/O with the reentrancy settings is impractical since thereare many, manythousands of subprograms in the complete package (this package was started in the early 80's and has been growing ever since). Waiting for a new compiler release sounds much easier.
In the meantime, I added a Sleep(0) following the for_rtl_finish in both the main C++ program and the DllMain. This appears to havesolved the problem. I'm guessing that forcing a context switch allows the for_thread_clean thread to be activated before its code gets unmapped.
Thanks so much for your suggestions.
Best regards,
Brian.

- Subscribe to RSS Feed
- Mark Topic as New
- Mark Topic as Read
- Float this Topic for Current User
- Bookmark
- Subscribe
- Printer Friendly Page