cpu.c: X1000 using kernel,debug + MUNGE freezes

This forum is for general developer support questions.
Post Reply
User avatar
javierdlr
Beta Tester
Beta Tester
Posts: 389
Joined: Sun Jun 19, 2011 10:13 pm
Location: Donostia (GUIPUZCOA) - Spain
Contact:

cpu.c: X1000 using kernel,debug + MUNGE freezes

Post by javierdlr »

Hi, maybe you already read this thread here: http://forum.hyperion-entertainment.biz ... 522#p28484
(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;
}
What could be the problem (bad coding? race condition?) for such freeze/crash ONLY when using kernel.debug+MUNGE on X1000, on my SAM460ex I can't reproduce such crash/freeze.


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
c
Dump of context at 0xFFC08BA0
Trap type: DSI exception
User avatar
Thomas Frieden
AmigaOS Core Developer
AmigaOS Core Developer
Posts: 147
Joined: Fri Dec 10, 2010 3:21 pm

Re: cpu.c: X1000 using kernel,debug + MUNGE freezes

Post by Thomas Frieden »

One thing, probably not the cause, but please, PLEASE:

Code: Select all

         
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) );
PLEASE do not do that. NEVER allocate any system structure yourself if there is an appropriate possibility with AllocSysObject:

Code: Select all

pause_req = (struct TimeRequest *)IExec->AllocSysObjectTags(ASOT_IOREQUEST, 
                                 ASOIR_Duplicate, timer_req,
                         TAG_DONE);
As you see, no CopyMem needed, no transfer of any fields from the original.
User avatar
Thomas Frieden
AmigaOS Core Developer
AmigaOS Core Developer
Posts: 147
Joined: Fri Dec 10, 2010 3:21 pm

Re: cpu.c: X1000 using kernel,debug + MUNGE freezes

Post by Thomas Frieden »

I'm also not quite sure what the mutices around the setting of switch and launch points should accomplish ?

Regarding the idler task, make sure it won't persist after the main task exited. Usually, you would catch a sempahore or mutex at the start of the code and release it before exiting. The main task would then wait for that mutex before quitting.

If you don't, then there is a good chance that the main task quits and the program gets unloadseg'd while the idler task is still running (it's low priority anyway), which will crash.
User avatar
javierdlr
Beta Tester
Beta Tester
Posts: 389
Joined: Sun Jun 19, 2011 10:13 pm
Location: Donostia (GUIPUZCOA) - Spain
Contact:

Re: cpu.c: X1000 using kernel,debug + MUNGE freezes

Post by javierdlr »

Thomas Frieden wrote:I'm also not quite sure what the mutices around the setting of switch and launch points should accomplish ?

Regarding the idler task, make sure it won't persist after the main task exited. Usually, you would catch a sempahore or mutex at the start of the code and release it before exiting. The main task would then wait for that mutex before quitting.

If you don't, then there is a good chance that the main task quits and the program gets unloadseg'd while the idler task is still running (it's low priority anyway), which will crash.
I just changed from Forbid()/Permit() to use MutexObtain()/MutexRelease().
As you pointed, all test I did (on my SAM460ex) ilder() task finishes before main() task ends.
Ok thx for help, will try to make changes as you suggested ASAP.
User avatar
javierdlr
Beta Tester
Beta Tester
Posts: 389
Joined: Sun Jun 19, 2011 10:13 pm
Location: Donostia (GUIPUZCOA) - Spain
Contact:

Re: cpu.c: X1000 using kernel,debug + MUNGE freezes

Post by javierdlr »

Thomas Frieden wrote:One thing, probably not the cause, but please, PLEASE:
...
PLEASE do not do that. NEVER allocate any system structure yourself if there is an appropriate possibility with AllocSysObject:

Code: Select all

pause_req = (struct TimeRequest *)IExec->AllocSysObjectTags(ASOT_IOREQUEST, 
                                 ASOIR_Duplicate, timer_req,
                         TAG_DONE);
As you see, no CopyMem needed, no transfer of any fields from the original.
Ok, applied such change (and corto suggested another one) and here it's:
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

 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 );
    if(ITimer)
    {
     pause_req = IExec->AllocSysObjectTags(ASOT_IOREQUEST,
                                           ASOIOR_Duplicate, timer_req,
                                          TAG_END);

     // 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
      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 create idler task\n");

   }
  }

 }
 else
  IExec->DebugPrintF("Couldn't open timer.device\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->FreeSysObject(ASOT_IOREQUEST, 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;
}
EDIT1: seems it works now fine with such changes!!!! THX A LOT.
Post Reply