Code: Select all
// compile with: gcc handlertest.c -o handlertest -lauto
#include <proto/exec.h>
#include <proto/dos.h>
#include <signal.h>
#pragma pack(2)
struct MemData
{
char null_string[4];
struct Interrupt low_mem_handler;
short low_mem_signal;
short release_delay;
long call_count;
};
#pragma pack()
struct MemData *data = NULL;
int32 low_mem_handler(struct ExecBase *ExecBase,
struct MemHandlerData *memh,
struct MemData *data);
int main(int argc, char **argv)
{
uint32 signals = 0;
signal(SIGINT, SIG_IGN); // Tell C to ignore some signalss
if (!(data = IExec->AllocVecTags(sizeof(struct MemData),
AVT_Type, MEMF_SHARED,
AVT_ClearWithValue, 0,
TAG_END)))
{
return RETURN_ERROR;
}
data->low_mem_signal = 1;
data->call_count = 0;
// Initialise interrupt
data->low_mem_handler.is_Node.ln_Pri=50;
data->low_mem_handler.is_Node.ln_Type=NT_EXTINTERRUPT;
data->low_mem_handler.is_Node.ln_Name="dopus memhandler";
data->low_mem_handler.is_Data=data;
data->low_mem_handler.is_Code=(void (*)())low_mem_handler;
// Add the handler
IDOS->Printf("Adding Handler\n");
IExec->AddMemHandler(&data->low_mem_handler);
signals = IExec->Wait(SIGBREAKF_CTRL_C);
// Remove low-memory handler
if (data->low_mem_handler.is_Node.ln_Pri==50)
IExec->RemMemHandler(&data->low_mem_handler);
IDOS->Printf("Handler call count: %ld\n", data->call_count);
}
// Low memory handler
int32 low_mem_handler(struct ExecBase *ExecBase,
struct MemHandlerData *memh,
struct MemData *data)
{
// Is this the first time?
if (!(memh->memh_Flags&MEMHF_RECYCLE))
{
// Just doing something for test purposes
if (data->low_mem_signal>-1)
{
// Increment call count
data->call_count++;
// Tell it to try again
return MEM_TRY_AGAIN;
}
}
// We didn't actually do anything
return MEM_DID_NOTHING;
}
Compile the above program and execute it in a shell.
For an X1000 with 2GB memory enter allocmem 1300 MB. For other hardware you may need to try smaller numbers untill allocmem returns with "Error: Memory allocation failed!".
The system (tested on an X1000 only) will freeze and a hard reset is necessary.
The MEM_TRY_AGAIN return value for a low memory handler may not be as useful since exec is no longer setting the MEMHF_RECYCLE flag in MemHandlerData->memh_flags but OS3 programs, older OS4 programs and new programs that want to release memory incrementally could still use the MEM_TRY_AGAIN return value. It may seem unlikely that a low memory condition will occur on PPC hardware with a large amount of memory but some programs like OS3 Adpro intentionally attempt to allocate more memory than is available in order to trigger low memory handlers into freeing up as much memory as possible.
The takeaway from this is the following:
1. Programs (especially OS3 programs) that use low memory handlers which rely on the MEMHF_RECYCLE flag being properly set may fail or react unpredictably.
2. Programs that use low memory handlers which return MEM_TRY_AGAIN under low memory conditions will cause a complete system failure requiring a hard reset.
3. The exec AddMemHandler autodoc needs to be updated with a note that exec not longer sets the MEMHF_RECYCLE flag and that program low memory handlers should no longer rely on that flag being set. The tiny note to that effect in the exec includes is easily overlooked and may not get programmers attention.