The online racing simulator
#1 - PoVo
prism_timers.php bug.
Hi,

Today while testing my PRISM plugin, I noticed that sometimes 1 of my 2 timers stops randomly.

After investigating the issue I came to a conclusion. When the timer is created it adds it to an array of timestamps sorted by timestamps themselves. If a timestamp is being added, and another times with the same timestamp exists in the timers array, it is replaced and stops running.

Solution (can be probably neatened up but I suck at PHP):

<?php 
// Registers a callback method.
    
protected function createTimer($callback$interval 1.0$flags Timer::CLOSE$args = array())
    {
        
# This will be the time when this timer is to trigger
        
$mtime microtime(TRUE);
        
$timestamp $mtime $interval;
        
        
# Check to make sure that another timer with same timestamp doesn't exist
        
if (isset($this->timers["$timestamp"]))
        {
            
$timestamp $mtime $interval 0.01;
        }
        
        
# Adds our timer to the array.
        
$this->timers["$timestamp"] = new Timer($this$callback$interval$flags$args);
    }
?>

Basically if the timestamp already exists, it adds a further "wait" of 0.01 seconds to make sure it doesn't replace the other timer.

After using this createTimer function, the problem goes away!

I was thinking of posting this to GitHub, but since my fix isn't so neat I am posting it here.
Quote from PoVo :

<?php 
        
# Check to make sure that another timer with same timestamp doesn't exist
        
if (isset($this->timers["$timestamp"]))
        {
            
$timestamp $mtime $interval 0.01;
        }
?>


Just to be sure, we should really make that recursive, but really good catch. I was pretty sure that I used microsecends, so even if you added two timers, it should of given you a unique value for each of them.

Anyway, the fix should look something like this, just added a recursive call to create timer, and the simple recursive call should offset it enough not to bounce into another timer.


<?php 
    
// Registers a callback method.
    
protected function createTimer($callback$interval 1.0$flags Timer::CLOSE$args = array())
    {
        
# This will be the time when this timer is to trigger
        
$mtime microtime(TRUE);
        
$timestamp $mtime $interval;
        
        
# Check to make sure that another timer with same timestamp doesn't exist
        
if (isset($this->timers["$timestamp"]))
        {
            
$this->createTimer($callback$interval$flags$args)
        }
        
        
# Adds our timer to the array.
        
$this->timers["$timestamp"] = new Timer($this$callback$interval$flags$args);
    }
?>

However, this is not a real fix.

Like you have shown, there is a time where two or more timers want to execute at the same time, and for that we need a real solution. I think having the current timestamp keyed array is a good solution, but also it's value should be allowed to be an array as well. So if there is a collision with time stamps, then the other timer is simply added to it's array. Something like this is the real solution.


<?php 
    
// Registers a callback method.
    
protected function createTimer($callback$interval 1.0$flags Timer::CLOSE$args = array())
    {
        
# This will be the time when this timer is to trigger
        
$timestamp microtime(TRUE) + $interval;

        
# Adds our timer to the array.
        
$this->timers["$timestamp"][] = new Timer($this$callback$interval$flags$args);
    }
?>

But that means I'm going to have to change something else, so this is gonna take a bit more time to ensure it's correct.
#3 - PoVo
Quote from Dygear :

<?php 
    
// Registers a callback method.
    
protected function createTimer($callback$interval 1.0$flags Timer::CLOSE$args = array())
    {
        
# This will be the time when this timer is to trigger
        
$mtime microtime(TRUE);
        
$timestamp $mtime $interval;
        
        
# Check to make sure that another timer with same timestamp doesn't exist
        
if (isset($this->timers["$timestamp"]))
        {
            
$this->createTimer($callback$interval$flags$args)
        }
        
        
# Adds our timer to the array.
        
$this->timers["$timestamp"] = new Timer($this$callback$interval$flags$args);
    }
?>


The idea of using a recursive fix is much better than what I did! But your fix still has a mistake. Even if you call createTimer again, you still create the timer.

Here's it fixed up:

<?php 
// Registers a callback method.
    
protected function createTimer($callback$interval 1.0$flags Timer::CLOSE$args = array())
    {
        
# This will be the time when this timer is to trigger
        
$timestamp microtime(TRUE) + $interval;
        
        
# Check to make sure that another timer with same timestamp doesn't exist
        
if (isset($this->timers["$timestamp"]))
        {
            
$this->createTimer($callback$interval$flags$args);
        }
        else 
        {
            
# Adds our timer to the array.
            
$this->timers["$timestamp"] = new Timer($this$callback$interval$flags$args);
        }
    }  
?>

I pulled your change, and merged it on github. Congrats, on your first bug fix, I hope to see many more .
ha, I thought it was an error in my coding causing the timers to do that.

I wrote something into my plugin to check last time each timer ran, and reinit any that have not run recent enough, ha!
Quote from Krammeh :ha, I thought it was an error in my coding causing the timers to do that.

I wrote something into my plugin to check last time each timer ran, and reinit any that have not run recent enough, ha!

Nah, it was my mistake . Some times it really is the fault of the upstream library.
#7 - PoVo
Okay this is totally weird.

Even with this fix, sometimes a random timer stops working. I have 4 timers and I've noticed during development time that some stop.

Now I'm guaranteed there's nothing wrong with the code in them, because I print a text line saying "XYZ Timer elapsed" before any other code is executed.

Right now I've decided to set my timer repeat to 0 and recreate the timer after it has elapsed with repeat as 0 and just repeat it every time.

I will continue to test this and try to figure it out...

EDIT: After testing for 40 mins, it seems setting repeat to 0 and just recreating the timer after it elapses seems to work, so it's most likely another problem within prism_timers.php.

EDIT2: *facepalm*. For some reason I had the prism_timers.php file from 0.4.2. LOL.
Quote from PoVo :EDIT2: *facepalm*. For some reason I had the prism_timers.php file from 0.4.2. LOL.

Haha, OK. Now it is working without a problem?
#9 - PoVo
Yep it's perfect again...

FGED GREDG RDFGDR GSFDG