GameMonkey Script

GameMonkey Script Forums
It is currently Mon Nov 20, 2017 3:38 pm

All times are UTC




Post new topic Reply to topic  [ 5 posts ] 
Author Message
PostPosted: Mon Apr 07, 2014 1:30 pm 
Offline

Joined: Mon Apr 07, 2014 1:15 pm
Posts: 2
Hi,
First i want to say thanks to gm developpers for this huge work, i'm using it for weeks and it's really perfect. :)

I think i may have found a little bug with the endon feature, (I'm using gm 1.29.0):

The main idea is when a endon block is reached, it creates a new "fake" block to kill the thread on a specific signal.
But I think that if this thread reaches after the endon, a real block (block, not endon), then it cancels the previous endon(s).

I wasn't able to recreate this with a small script (maybe because endon doesn't always return GM_SYS_BLOCK), but with my main script, i got this bug.
So i checked the gmMachineLib.cpp file, and i saw that a "block" return GM_SYS_BLOCK
such a return causes a machine->Sys_SwitchState(this,BLOCKED) (in gmThread.cpp/gmThread::PushStackFrame) -> http://prntscr.com/37t3qz
then in Sys_SwitchState, for the case BLOCKED, it does Sys_RemoveBlocks(a_thread) -> http://prntscr.com/37t4db

Therefore a block will remove a previous endon.

A fix, would be to not remove endon "blocks" in Sys_RemoveBlocks.

Am I right here ?

Thanks

Edit:
- Also I had a little question about "Sys_Signal", can I use GM_INVALID_THREAD for dest_thread and src_thread (as I want to send a signal from C++ code directly)
In the doc, it says that we can use GM_INVALID_THREAD for the dest_thread (this way all threads are signalled, but it says nothing about src_thread)
- In that case, if I create a signal from C++ code (not from a binding), can the object in the signal be collected by the GC ? because it's not really handled by the script, or is any object in a signal and a block not collected until the signal/block is "Sys_remove"?


Top
 Profile  
Reply with quote  
PostPosted: Tue Apr 08, 2014 9:46 am 
Offline

Joined: Mon Dec 15, 2003 1:38 pm
Posts: 698
Hi Korrion, welcome to the forum. Glad you're getting some use from GM.

You are most likely correct with the endon behavior and solution. I have to plead stupidity at the moment as I haven't looked through the code for a long time and can't give you an intelligent answer on the spot. It would be most helpful to make a small repro case so we can verify the issue and fix. I'll try to have a proper look at the code later this week and see if I can help. Briefly looking at the code and your description, the behavior does look as you describe.

In the meantime, feel free to experiment with a fix and play with / trace the VM implementation.

About your GC question... Any gmObject owned by C++ (not connected to other machine roots) must be added to the 'cpp owned' list otherwise it will be collected. For safety sake, newly created objects that are not yet connected, should have GC disabled around their initialization and connection. Looking at the gmSignal, a gmObject, which may be referenced there as gmVariable, IS a GC root once set on the thread. It should be safe.


Top
 Profile  
Reply with quote  
PostPosted: Tue Apr 08, 2014 6:40 pm 
Offline

Joined: Thu Jan 01, 2004 4:31 pm
Posts: 307
Hi,

I originally added the "endon" extension, it's been a while since I looked over it so will take a look to see if I can repro the issue you're seeing. I'll see what I can do :)


Top
 Profile  
Reply with quote  
PostPosted: Sun May 11, 2014 11:55 pm 
Offline

Joined: Mon Apr 07, 2014 1:15 pm
Posts: 2
Hi,

Sorry for the long time between answers.
So I got some vacations to work on this, here what I did to fix it:

in gmMachine.cpp, i added removeBlocks, that will remove a block from a block linkedlist, which is a endon block or not depending on "bool endOn"
and I added a parameter bool ignoreEndonBlocks to Sys_RemoveBlocks;
Code:
gmBlock* gmMachine::removeBlocks(gmBlock* block, bool endOn)
{

   if (block == NULL)
      return NULL;
   
   if (block->m_endOn == endOn)
   {
   
      gmBlock* next = block->m_nextBlock;
      
      gmBlockList * list = block->m_list;
      block->Remove();
      if(list->m_blocks.IsEmpty())
      {
         list = (gmBlockList *) m_blocks.Remove(list);
         Sys_Free(list);
      }
      Sys_Free(block);
      next = removeBlocks(next,endOn);
      return next;
   }
   else
   {
      block->m_nextBlock = removeBlocks(block->m_nextBlock,endOn);
      return block;
   }
}
void gmMachine::Sys_RemoveBlocks(gmThread * a_thread, bool ignoreEndonBlocks)
{
   
   gmBlock * block = a_thread->Sys_GetBlocks();

   //delete all the non endon blocks
   gmBlock * newBlock = removeBlocks(block,false);
   
   //delete also endon blocks if !ignoreEndonBlocks
   if (!ignoreEndonBlocks)
      newBlock = removeBlocks(newBlock,true);
      
   a_thread->Sys_SetBlocks(newBlock);
}


in gmMachine.h, the new function removeBlocks and the edited Sys_RemoveBlocks
Code:
  void Sys_RemoveBlocks(gmThread * a_thread, bool ignoreEndonBlocks = false);
  gmBlock* removeBlocks(gmBlock* block, bool endOn);


in gmMachine.cpp, adding a true as ignoreEndonBlock parameter for
Code:
    case gmThread::SYS_PENDING :
    {
      // remove and clean up the blocks.
      Sys_RemoveSignals(a_thread); // Prevent signals from accumulating
      Sys_RemoveBlocks(a_thread,true); //ADDED true for ignore endon blocks  <<here
      m_blockedThreads.Remove(a_thread);
      break;
    }


I'm not 100% sure that I am freeing correctely a gmBlock elem in the llist, but otherwise, it fixed my issue in my code.


Top
 Profile  
Reply with quote  
PostPosted: Mon May 19, 2014 10:00 am 
Offline

Joined: Mon Dec 15, 2003 1:38 pm
Posts: 698
Thanks for sharing your fix.

The removeBlocks recursive method looks a little complex. I'm wondering if you could have inserted a test inside Sys_RemoveBlocks, preserving the iterative method? Something like this perhaps?
Code:
void gmMachine::Sys_RemoveBlocks(gmThread * a_thread, bool a_includeEndOnBlocks) // Added param, pass false to ignore endOns
{
  gmBlock * block = a_thread->Sys_GetBlocks(), * next;
  while(block)
  {
    next = block->m_nextBlock;
    if( !block->m_endOn || a_includeEndOnBlocks ) // Added line
    {
      gmBlockList * list = block->m_list;
      block->Remove();
      if(list->m_blocks.IsEmpty())
      {
        list = (gmBlockList *) m_blocks.Remove(list);
        Sys_Free(list);
      }
      Sys_Free(block);
    }
    block = next;
  }
  a_thread->Sys_SetBlocks(NULL);
}


Top
 Profile  
Reply with quote  
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 5 posts ] 

All times are UTC


Who is online

Users browsing this forum: No registered users and 1 guest


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to:  
cron
Powered by phpBB® Forum Software © phpBB Group