home *** CD-ROM | disk | FTP | other *** search
- /*
- File: ShellMem.cpp
-
- Contains: Memory management for the Shell
-
- Owned by: Nick Pilch
-
- Copyright: © 1995 - 1996 by Apple Computer, Inc., all rights reserved.
-
- Change History (most recent first):
-
- <8> 7/30/96 DH Changed unknown macro/function BREAK to
- WARN.
- <7> 7/30/96 eeh 1372943: add ODShellCorruptDocGoodbye and
- ODShellGenericGoodbye
- <6> 7/28/96 DH Bug#1372954: Changed LowMemoryAlert to call
- ExitToShell instead of ODCloseDocument.
- This was done because that utility routine
- can crash under low memory situations.
- <5> 6/21/96 jpa T10002: Lowered min app heap free space to
- 32k, 6k contig.
- <4> .04.1996 NP 1339832: Send exit event before closing
- documents/windows from LowMemoryAlert.
- <3> 4/4/96 NP 1338241: Unstaticize function.
- <2> 3/29/96 DM 1334273: show low mem quit alert and then
- exit to shell when unable to show another
- low mem alert due to out-of-mem err
- <1> 10/24/95 jpa first checked in
-
- In Progress:
-
- */
-
-
- #ifndef _RLSHELL_
- #include "RlShell.h"
- #endif
-
- #ifndef _SHELLDEF_
- #include "ShellDef.h"
- #endif
-
- #ifndef _DISPTCH_
- #include <Disptch.xh>
- #endif
-
- #ifndef _MEMMGR_
- #include <MemMgr.h>
- #endif
-
- #ifndef _DLOGUTIL_
- #include <DlogUtil.h>
- #endif
-
- #ifndef _DOCUTILS_
- #include <DocUtils.h>
- #endif
-
- #ifndef _USERSRCM_
- #include <UseRsrcM.h>
- #endif
-
- #ifndef _TEMPITER_
- #include <TempIter.h>
- #endif
-
- #ifndef _SHELLMEM_
- #include <ShellMem.h>
- #endif
-
- //==============================================================================
- // CONSTANTS
- //==============================================================================
-
- const size_t kSlushFundSize = 10 * 1024; // Size of memory slush-fund
- const size_t kSlushFundAllocLimit = 2 * 1024; // Max request that will free slush fund
-
- const ODSize kGoodAppFreeSpace = 32 * 1024; // Sizes below which we notify the user
- const ODSize kGoodAppContigSpace = 6 * 1024;
- const ODSize kGoodTempFreeSpace = 100 * 1024;
- const ODSize kGoodTempContigSpace = 32 * 1024;
-
- const ODSize kBailAppFreeSpace = 2 * 1024; // App-heap mem requirement of low-mem alert
-
-
- //==============================================================================
- // METHODS
- //==============================================================================
-
-
- //-------------------------------------------------------------------------------------
- // InitMemory
- //-------------------------------------------------------------------------------------
-
- void
- RealShell::InitMemory( )
- {
- // Preload low-mem alerts so we'll be able to use them when space is low:
- CUsingLibraryResources r;
- ::Get1Resource('ALRT',kSHLphSpaceIsLow);
- ::Get1Resource('DITL',kSHLphSpaceIsLow);
- ::Get1Resource('ALRT',kSHLphAppSpaceIsLow);
- ::Get1Resource('DITL',kSHLphAppSpaceIsLow);
-
- if( ! MMAllocateSlushFund(kDefaultHeapID, kSlushFundSize,kSlushFundAllocLimit) )
- WARN("Could not allocate slush fund");
- }
-
-
- //-------------------------------------------------------------------------------------
- // IsFreeMemoryLow
- //-------------------------------------------------------------------------------------
-
- inline ODSLong Max( ODSLong a, ODSLong b )
- {return a>b ?a :b;}
-
- ODSize RealShell::IsFreeMemoryLow( ODBoolean &appIsLow, ODBoolean &tempIsLow )
- {
- // First check/replenish the memory slush fund:
- ODBoolean slushy;
- if( MMSlushFundSize(kDefaultHeapID) > 0 )
- slushy = kODTrue;
- else
- slushy = MMAllocateSlushFund(kDefaultHeapID, kSlushFundSize,kSlushFundAllocLimit);
-
- size_t free,contig;
- ODSLong freeDelta, contigDelta;
- ODSLong purgeApp = 0, purgeTemp = 0;
-
- MMSystemFreeSpace(kMMAppMemory, &free,&contig);
- freeDelta = kGoodAppFreeSpace-free;
- contigDelta = kGoodAppContigSpace-contig;
- purgeApp = Max(freeDelta,contigDelta);
- appIsLow = (purgeApp>0);
-
- MMSystemFreeSpace(kMMTempMemory, &free,&contig);
- freeDelta = kGoodTempFreeSpace-free;
- contigDelta = kGoodTempContigSpace-contig;
- purgeTemp = Max(freeDelta,contigDelta);
- tempIsLow = (purgeTemp>0);
-
- if( !slushy )
- tempIsLow = kODTrue;
-
- purgeApp = Max(purgeApp,purgeTemp);
- return (purgeApp>0 ?purgeApp :0);
- }
-
-
- //-------------------------------------------------------------------------------------
- // CheckFreeMemory
- //-------------------------------------------------------------------------------------
-
- ODBoolean RealShell::CheckFreeMemory( )
- {
- // If space is low, purge. If space is still low, alert the user, provided this
- // process is active. After the user is alerted, set a flag so we don't put up
- // an endless stream of alerts. Note that we don't use the normal dialog filter,
- // since it calls the Dispatcher, which may cause trouble when space is low.
-
- ODBoolean appIsLow, tempIsLow;
- ODSize purge = this->IsFreeMemoryLow(appIsLow,tempIsLow);
-
- if( purge ) {
- // Low on free space, so purge:
- this->Purge( 2*purge );
-
- this->IsFreeMemoryLow(appIsLow,tempIsLow);
-
- if( (appIsLow || tempIsLow) ) {
- // Yow, still low on memory after purging.
- size_t freeApp,contig;
- MMSystemFreeSpace(kMMAppMemory, &freeApp,&contig);
- if( !fLowMemNotified && fProcessIsActive && freeApp > kBailAppFreeSpace ) {
- this->LowMemoryAlert( tempIsLow ); // Notify user 1st time if we can
- fLowMemNotified = kODTrue;
- }
- return kODFalse;
- }
- }
- fLowMemNotified = kODFalse; // We're okay now, clear notification state
- return kODTrue;
- }
-
-
- static ODBoolean
- DocNeedsSaving( Environment *ev, ODSession *session, ODDocument *document )
- {
- // Throws no exceptions.
- TRY{
- return ODDocumentHasChanges(ev,session,document);
- }CATCH_ALL{
- WARN("ODDocumentHasChanges failed, err %d",ErrorCode());
- }ENDTRY
- return kODFalse;
- }
-
- #if ODDebug
- void BREAK( const char[] );
- #endif
-
- static void GenericAlert( short alertID )
- {
- #if ODDebug
- WARN("about to show fatal low memory or related alert...");
- #endif
- {
- TRY{
- CUsingLibraryResources r;
- InitCursor();
- ::Alert( alertID, kODNULL );
- }CATCH_ALL{
- WARN("cannot show fatal low memory alert - quitting...");
- }ENDTRY
- }
- // make sure CUsingLibraryResources goes out of scope first...
- ::ExitToShell(); // bye bye process
- }
-
- void ODShellLowMemoryGoodbye()
- {
- GenericAlert( kODAlertShellLowMemoryError );
- }
-
- void ODShellGenericGoodbye( ODBoolean inform )
- {
- if ( inform )
- GenericAlert( kODAlertShellGenericError );
- else
- ::ExitToShell();
- }
-
- void ODShellCorruptDocGoodbye()
- {
- GenericAlert( kODAlertShellCorruptDocError );
- }
-
- //------------------------------------------------------------------------------
- // DispatchExitEvent
- //
- // Duplicated in ODSessnB.cpp
- //------------------------------------------------------------------------------
-
- static void DispatchExitEvent(Environment* ev, ODDispatcher* dispatcher)
- {
- // Copied from RealShell::FakePrintMenuEvent
- ODEventData event;
- event.message = 0L;
- event.what = kODEvtExit;
- // zero the rest of the fields
- WASSERT( sizeof(Point) == sizeof(long) );
- *(long*)&event.where = 0L;
- event.when = 0L;
- event.modifiers = 0;
- dispatcher->Dispatch(ev, &event);
- }
-
- //------------------------------------------------------------------------------
- // RealShell::LowMemoryAlert
- //------------------------------------------------------------------------------
-
- void RealShell::LowMemoryAlert( ODBoolean tempMem )
- {
- /* Do not use the regular ODDialogFilter for this alert, as it calls back to the
- Dispatcher, which calls other OpenDoc routines. This could be dangerous/fatal
- in precisely this kind of low memory situation. */
-
- // First, do any open documents need to be saved?
- ODBoolean needSave = kODFalse;
- TRY{
- for( TempODWindowIterator wi(fEV,fSession->GetWindowState(fEV)); wi; ++wi )
- if( DocNeedsSaving(fEV,fSession, ODGetDraftOfWindow(fEV,wi)->GetDocument(fEV)) ) {
- needSave = kODTrue;
- break;
- }
- }CATCH_ALL{
- if ( ErrorCode() == kODErrOutOfMemory )
- {
- ODShellLowMemoryGoodbye(); // goodbye cruel world
- }
- else
- {
- WARN("Error %d checking docs",ErrorCode());
- // don't reraise
- }
- }ENDTRY
-
- ODSShort result; ODVolatile(result);
- TRY{
- // Shazam! Show the alert:
- ODSShort id = needSave ?kSHLphSpaceIsLow :kSHLphSpaceIsLowNoSave;
- if( tempMem ) id++;
- {
- CUsingLibraryResources r;
- result = ShowAlert(fEV, id, kODNULL, fSession);
- }
- }CATCH_ALL{
- if ( ErrorCode() == kODErrOutOfMemory )
- {
- ODShellLowMemoryGoodbye(); // goodbye cruel world
- }
- else
- {
- WARN("Error %d showing low mem alert",ErrorCode());
- // don't reraise
- }
- }ENDTRY
-
- if( result == kStdCancelItemIndex )
- return;
-
- needSave = needSave && (result==kStdOkItemIndex); // Don't save if user said not to
-
- // CYBERDOG NEEDS THIS EXIT EVENT FIRST IF WE'RE GOING TO SHUT DOWN
- // EVERYTHING.
- TRY
- DispatchExitEvent(fEV, fSession->GetDispatcher(fEV));
- CATCH_ALL
- WARN("Caught error trying to dispatch exit event in "
- "RealShell::LowMemoryAlert");
- if ( ErrorCode() == kODErrOutOfMemory )
- ODShellLowMemoryGoodbye(); // quit immediately
- ENDTRY
-
- // First close documents. (If we're told to save, close only the unmodified docs.)
- // Note that this may free up memory before the save step below.
- for( TempODWindowIterator wi(fEV,fSession->GetWindowState(fEV)); wi; ++wi ) {
- TRY{
- ODDocument *document = ODGetDraftOfWindow(fEV,wi)->GetDocument(fEV);
- if( !needSave || !DocNeedsSaving(fEV,fSession, document) )
- // ODCloseDocument(fEV, fSession, document);
- // $$$$$ - dh
- /* This is a VERY TEMPORARY fix for the crashes on closing
- partially constructed documents. If you see this code,
- IMMEDIATELY file a bug and get this removed!!!
- */
- ::ExitToShell(); // Will quit immediately.
- }CATCH_ALL{
- WARN("Error %d closing doc",ErrorCode());
- // don't reraise
- }ENDTRY
- }
-
- if( needSave ) {
- // Now save&close the rest of the documents.
- for( TempODWindowIterator wi(fEV,fSession->GetWindowState(fEV)); wi; ++wi ) {
- TRY{
- ODDocument *document = ODGetDraftOfWindow(fEV,wi)->GetDocument(fEV);
- if( DocNeedsSaving(fEV,fSession, document) ) {
- /* Do not call RealShell::Save, as this will put up a standard-file dialog
- for an unsaved new document. Not the safest thing to do right now! */
- ODSaveDocument(fEV,fSession, document);
- }
- }CATCH_ALL{
- WARN("Error %d saving/closing doc",ErrorCode());
- // don't reraise
- }ENDTRY
- }
- }
-
- fSession->GetDispatcher(fEV)->Exit(fEV); // Quit at next event loop
- }
-
-
- //-------------------------------------------------------------------------------------
- // Purge
- //-------------------------------------------------------------------------------------
-
- ODSize RealShell::Purge(ODSize size)
- {
- ODSize result;
- TRY{
- result= fSession->Purge(fEV,size);
- }CATCH_ALL{
- result = 0;
- // do not reraise, ignore exception
- }ENDTRY
- return result;
- }
-