(cpu.c source code/example is on above thread)
I changed a bit cpu.c (IIRC RemTask(0L) instead Wait(0L)) (or adding mutex'es before/after FindTask(NULL), but still crashes for Guillaume):
Hidden Text - Click to Show :
Code: Select all
;/* CPU functions
gcc -Wall -N -gstabs -O2 -o cpu cpu.c
quit
*/
#define DEBUG
#include <proto/exec.h>
#include <proto/dos.h>
#include <proto/timer.h>
static __attribute__((used)) char *version_string = "$VER: CPU 0.2beta (17.06.2014)";
struct ExecIFace *IExec;
struct DOSIFace *IDOS;
struct Device *TimerBase = NULL;
struct TimerIFace *ITimer = NULL;
// Using mutex instead of Forbid/Permit
APTR idlerMx;
// Signals for inter-process synchronization
static ULONG idle_sig = -1, main_sig = -1;
// Main task's address
static struct Task *main_task = NULL;
// "Volatile" to avoid clever optimizer walking over me. Program runs as long as flag is set.
static volatile BOOL running = TRUE;
// Simple mode switches to non-busy looping option when measuring the CPU usage.
static volatile BOOL simple_mode = TRUE;
// How many times idle task was ran during 1 second. Run count 0 means 100% cpu usage, 100 means 0 % CPU usage
static uint32 run_count = 0;
// Used by idle task for 1/100 second pauses when running in non-busy looping mode
static struct TimeRequest *pause_req = NULL;
// For keeping book of time
static struct TimeVal idle_start, idle_finish, idle_time;
// Set if idler task runs into trouble
static BOOL error = FALSE;
// Idle task gives up CPU
static void my_switch(void)
{
ITimer->GetSysTime(&idle_finish);
ITimer->SubTime(&idle_finish, &idle_start);
idle_time.Seconds += idle_finish.Seconds;
idle_time.Microseconds += idle_finish.Microseconds;
}
// Idle task gets CPU
static void my_launch(void)
{
ITimer->GetSysTime(&idle_start);
}
/* Idler process. Soon after creation its priority is dropped to minimal
so that it can't disturb the system */
static void idler(void)
{
struct Task *me = NULL;
struct MsgPort *idle_port = NULL; // Message port for our timerequest
#ifdef DEBUG
IExec->DebugPrintF(" idler() START\n");
#endif
idle_port = IExec->AllocSysObject(ASOT_PORT, NULL);
if(!idle_port)
{
error = TRUE;
goto die;
}
#ifdef DEBUG
IExec->DebugPrintF(" idle_port=0x%08lx\n",idle_port);
#endif
idle_sig = IExec->AllocSignal(-1);
if(idle_sig == -1)
{
error = TRUE;
goto die;
}
#ifdef DEBUG
IExec->DebugPrintF(" idle_sig=0x%08lx\n",idle_sig);
#endif
IDOS->Delay(1); // or X1000 freezes with kernel.debug+MUNGE ¿:-/
me = IExec->FindTask(NULL);
#ifdef DEBUG
IExec->DebugPrintF(" idler() task=0x%08lx (=idle_task)\n...\n",me);
#endif
// And god kills another kitten...
//IExec->Forbid();
IExec->MutexObtain(idlerMx);
me->tc_Switch = my_switch;
me->tc_Launch = my_launch;
me->tc_Flags |= TF_SWITCH | TF_LAUNCH;
//IExec->Permit();
IExec->MutexRelease(idlerMx);
// Signal main task that we are ready
IExec->Signal(main_task, 1L<<main_sig);
// Wait for main task to obtain ITimer
IExec->Wait(1L<<idle_sig);
pause_req->Request.io_Message.mn_ReplyPort = idle_port;
// Let's be reasonable...
IExec->SetTaskPri(me/*IExec->FindTask(NULL)*/, -127);
// If running wasn't volatile, optimizer would disable test!
while(running)
{
// When in "Simple" mode, pause for 1/100th of second
if(simple_mode) // Toggle TRUE/FALSE not yet implemented (default is TRUE)
{
struct TimeVal tv;
run_count++;
ITimer->GetSysTime(&tv);
tv.Microseconds += 10000; // 100Hz = 1/100th of second
pause_req->Request.io_Command = TR_ADDREQUEST;
pause_req->Time.Seconds = tv.Seconds;
pause_req->Time.Microseconds = tv.Microseconds;
// Set the timer running
IExec->DoIO( (struct IORequest *)pause_req );
}
}
//IExec->Forbid();
IExec->MutexObtain(idlerMx);
me->tc_Switch = NULL;
me->tc_Launch = NULL;
me->tc_Flags ^= TF_SWITCH | TF_LAUNCH;
//IExec->Permit();
IExec->MutexRelease(idlerMx);
if(idle_sig != -1)
{
IExec->FreeSignal(idle_sig);
#ifdef DEBUG
IExec->DebugPrintF(" FREE idle_sig=0x%08lx\n",idle_sig);
#endif
}
die:
if(idle_port)
{
IExec->FreeSysObject(ASOT_PORT, idle_port);
#ifdef DEBUG
IExec->DebugPrintF(" FREE idle port=0x%08lx\n",idle_port);
#endif
}
// Tell the main task that we can leave now (error flag may be set!)
IExec->Signal(main_task, 1L<<main_sig);
#ifdef DEBUG
IExec->DebugPrintF(" idler() END\n");
#endif
// Waiting for termination, Valhalla awaits!
//IExec->Wait(0L);
IExec->RemTask(0L);
}
/********/
/* MAIN */
/********/
int main(void)
{
struct MsgPort *timer_port = NULL;
struct TimeRequest *timer_req = NULL;
struct Task *idle_task = NULL;
BYTE timer_device = -1;
#ifdef DEBUG
IExec->DebugPrintF("\n[cpu.c]\n");
IExec->DebugPrintF("main() START\n");
#endif
idlerMx = IExec->AllocSysObjectTags(ASOT_MUTEX, /*ASOMUTEX_Recursive,FALSE,*/ TAG_END);
if(!idlerMx) goto clean;
main_sig = IExec->AllocSignal(-1);
if(main_sig == -1)
{
IDOS->Printf("Couldn't allocate main signal\n");
goto clean;
}
#ifdef DEBUG
IExec->DebugPrintF("main_sig=0x%08lx\n",main_sig);
#endif
// Who was I again? Hmm...
main_task = IExec->FindTask(NULL);
#ifdef DEBUG
IExec->DebugPrintF("main() task=0x%08lx\n",main_task);
#endif
// Spawn a little nasty minion
idle_task = IExec->CreateTaskTags("CPU_idleTask", 0, idler, 16384,
CT_LockStack,TRUE, TAG_DONE);
if(idle_task)
{
#ifdef DEBUG
IExec->DebugPrintF("idle_task=0x%08lx\n",idle_task);
#endif
timer_port = IExec->AllocSysObject(ASOT_PORT, NULL);
if(timer_port)
{
timer_req = IExec->AllocSysObjectTags(ASOT_IOREQUEST,
ASOIOR_Size, sizeof(struct TimeRequest),
ASOIOR_ReplyPort, timer_port,
TAG_END);
if(timer_req)
{
if( !(timer_device=IExec->OpenDevice("timer.device", UNIT_WAITUNTIL, (struct IORequest *)timer_req, 0)) )
{
TimerBase = (struct Device *)timer_req->Request.io_Device;
ITimer = (struct TimerIFace *)IExec->GetInterface( (struct Library *)TimerBase, "main", 1, NULL );
pause_req = IExec->AllocVecTags(sizeof(struct TimeRequest), AVT_ClearWithValue,0, TAG_DONE);
if(!pause_req)
goto clean;
IExec->CopyMem( timer_req, pause_req, sizeof(struct TimeRequest) );
if(ITimer)
{
struct TimeVal tv;
// Let's sync to idler task now
IExec->Wait(1L<<main_sig);
if(error)
goto clean;
// Send message, "We've got ITimer now", back
IExec->Signal(idle_task, 1L<<idle_sig);
ITimer->GetSysTime(&tv);
tv.Seconds++;
//IExec->DebugPrintF("1)tv.Seconds=%ld\n",tv.Seconds);
timer_req->Request.io_Command = TR_ADDREQUEST;
timer_req->Time.Seconds = tv.Seconds;
timer_req->Time.Microseconds = tv.Microseconds;
// Set the timer running
IExec->SendIO( (struct IORequest *)timer_req );
// Reset idle time
idle_time.Seconds = 0;
idle_time.Microseconds = 0;
// The Main Loop
while(running)
{
ULONG sigs = IExec->Wait(SIGBREAKF_CTRL_C | 1L<<timer_port->mp_SigBit);
// Handle timer events
if( sigs&(1L<<timer_port->mp_SigBit) )
{
IExec->GetMsg(timer_port);
tv.Seconds++;
//IExec->DebugPrintF("2)tv.Seconds=%ld\n",tv.Seconds);
timer_req->Request.io_Command = TR_ADDREQUEST;
timer_req->Time.Seconds = tv.Seconds;
timer_req->Time.Microseconds = tv.Microseconds;
IExec->SendIO( (struct IORequest *)timer_req );
// Timer signal, update visuals once per second
//if( (++count % FREQ) == 0 ) // FREQ?
{
uint16 value = 100;
if(simple_mode) // Toggle TRUE/FALSE not yet implemented (default is TRUE)
{
value -= run_count;
IDOS->Printf("CPU:%ld%% (%ld) S ",value,run_count);
}
else
{
value -= 100 * (idle_time.Seconds * 1000000 + idle_time.Microseconds) / 1000000.0;
IDOS->Printf("CPU:%ld%% (%ld) B ",value,run_count);
}
// Reset idle time
idle_time.Seconds = 0;
idle_time.Microseconds = 0;
run_count = 0;
if(value > 100)
value = 100;
IDOS->FFlush( IDOS->Output() );
IDOS->Printf("\r\033[K");
}
}
// Handle Control-C too
if(sigs&SIGBREAKF_CTRL_C)
running = FALSE;
}
}
if( !IExec->CheckIO((struct IORequest *)timer_req) )
{
IExec->AbortIO( (struct IORequest *)timer_req );
while( IExec->GetMsg(timer_port) );
}
}
else
IExec->DebugPrintF("Couldn't open timer.device\n");
}
}
}
else
IExec->DebugPrintF("Couldn't create idler task\n");
clean:
// if idler task had problems, don't wait for it
if(idle_task && !error)
{
// Give it some more cpu
IExec->SetTaskPri(idle_task, 0);
// Wait idler task to finish possible timer actions before closing timing services
IExec->Wait(1L<<main_sig | SIGBREAKF_CTRL_C);
}
if(ITimer)
IExec->DropInterface( (struct Interface *)ITimer );
if(timer_device==0 && timer_req)
IExec->CloseDevice( (struct IORequest *)timer_req );
if(timer_req)
IExec->FreeSysObject(ASOT_IOREQUEST, timer_req);
if(pause_req)
IExec->FreeVec(pause_req);
if(timer_port)
IExec->FreeSysObject(ASOT_PORT, timer_port);
if(idle_task)
{
// IExec->DeleteTask(idle_task); // Farewell, idler!
#ifdef DEBUG
IExec->DebugPrintF("FREE idle_task=0x%08lx\n",idle_task);
#endif
idle_task = NULL;
}
if(main_sig != -1)
{
IExec->FreeSignal(main_sig);
#ifdef DEBUG
IExec->DebugPrintF("FREE main_sig=0x%08lx\n",main_sig);
#endif
}
IExec->FreeSysObject(ASOT_MUTEX, idlerMx);
#ifdef DEBUG
IExec->DebugPrintF("main() END\n");
IExec->DebugPrintF("[cpu.c]\n\n");
#endif
return 0;
}
Philippe Ferrucci already worte:
Hello,
french developer Guillaume BOESEL gave me your cpu.c source code.
It crashes here when using the normal kernel (non debug) when I add 2 debug lines like this:
main_task = IExec->FindTask(NULL);
(IExec->DebugPrintF)( "found\n");
...
// Spawn a little nasty minion
idle_task = IExec->CreateTaskTags("CPU_idleTask", 0, idler, 16384, CT_LockStack,TRUE, TAG_DONE);
(IExec->DebugPrintF)( "created\n");
I have this debug text:
found
cDump of context at 0xFFC08BA0
Trap type: DSI exception