<Swing Dev> [9] Review Request for 8130735: javax.swing.TimerQueue: timer fires late when another timer starts
Semyon Sadetsky
semyon.sadetsky at oracle.com
Wed Jul 22 08:02:39 UTC 2015
Alexander,
Thank you for the contribution. The final update:
http://cr.openjdk.java.net/~ssadetsky/8130735/webrev.02/
--Semyon
On 7/21/2015 2:31 PM, Alexander Scherbatiy wrote:
> On 7/21/2015 1:40 PM, Semyon Sadetsky wrote:
>> In the run() the delayed timer is obtained from timer, so it is
>> always the resulting delayed timer.
> Just to use the delayed timer from the queue and not from the timer?
>
> TimerQueue.run(){
> DelayedTimer delayedTimer = queue.take(); // note that this
> delayed timer is not the same as timer.delayedTimer
> delayedTimer.getTimer().lock();
> if(delayedTimer.removed){
> // skip it
> }
> // ...
> delayedTimer.getTimer().unlock();
> }
>
> Thanks,
> Alexandr.
>
>
>> How do you propose to detect that timer was renewed exactly during
>> the time interval between the timer is taken from the queue and the
>> lock is captured in the run() thread?
>>
>> On 7/21/2015 12:53 PM, Alexander Scherbatiy wrote:
>>> On 7/21/2015 11:36 AM, Semyon Sadetsky wrote:
>>>> Hi Alexander,
>>>>
>>>> The remove() method set delayedTimer field to null, and it is
>>>> checked in run() to be not null. So it acts in the same way as flag
>>>> you've proposed.
>>>>
>>>> The issue is about how to detect consequent remove() ans add() in
>>>> run(). If you use some flag in remove() then you need to clear it
>>>> in add()
>>> I suppose that you are talking about some flags in Timer. The
>>> proposed change suggests to add the flag to the DelayedTimer. So
>>> after stopping a timer (timer.delayedTimer = null) the delayedTimer
>>> taken from the queue contains information that it has been removed.
>>>
>>> Thanks,
>>> Alexandr.
>>>
>>>> because after the add() the timer should run normally with the new
>>>> period. And you cannot clear such flag in the first consequent
>>>> run() after add() because you cannot determine the moment the add()
>>>> was called. So it is just the same problem.
>>>>
>>>> --Semyon
>>>>
>>>> On 7/21/2015 10:35 AM, Alexander Scherbatiy wrote:
>>>>>
>>>>> What about to add removed flat to DelayedTimer? Something like:
>>>>> TimerQueue.removeTimer(Timer timer){
>>>>> timer.lock();
>>>>> // ...
>>>>> timer.delayedTimer.removed = true;
>>>>> queue.remove(timer.delayedTimer);
>>>>> timer.delayedTimer = null;
>>>>> timer.unlock();
>>>>> }
>>>>>
>>>>> TimerQueue.run(){
>>>>> DelayedTimer delayedTimer = queue.take();
>>>>> delayedTimer.getTimer().lock();
>>>>> if(delayedTimer.removed){
>>>>> // skip it
>>>>> }
>>>>> // ...
>>>>> delayedTimer.getTimer().unlock();
>>>>> }
>>>>>
>>>>> Thanks,
>>>>> Alexandr.
>>>>>
>>>>>
>>>>> On 7/17/2015 12:28 AM, Sergey Bylokhov wrote:
>>>>>> Hi, Semyon.
>>>>>> I see that the chance to reproduce the problem is very very
>>>>>> small, because we should call addTimer, when we are at lines
>>>>>> 171/172. So the bug is about really small timings. So the related
>>>>>> question: Is it possible in the fixed version to call addTimer
>>>>>> when we remove DelayedTimer from the queue via queue.take(), but
>>>>>> before we assign its value to the runningTimer?
>>>>>>
>>>>>> On 14.07.15 12:51, Alexander Zvegintsev wrote:
>>>>>>> still looks good to me.
>>>>>>>
>>>>>>> Thanks,
>>>>>>>
>>>>>>> Alexander.
>>>>>>>
>>>>>>> On 07/14/2015 12:41 PM, Semyon Sadetsky wrote:
>>>>>>>> Hi Alexander,
>>>>>>>>
>>>>>>>> I added the double check
>>>>>>>> :http://cr.openjdk.java.net/~ssadetsky/8130735/webrev.01/
>>>>>>>>
>>>>>>>> --Semyon
>>>>>>>>
>>>>>>>> On 7/13/2015 1:24 PM, Alexander Zvegintsev wrote:
>>>>>>>>> Hello Semyon,
>>>>>>>>>
>>>>>>>>> the fix looks good to me.
>>>>>>>>>
>>>>>>>>> P.S. Just a side note, as I can see we could possibly start
>>>>>>>>> two threads instead of one in startIfNeeded():
>>>>>>>>>
>>>>>>>>> 96 void startIfNeeded() {
>>>>>>>>> 97 if (! running) {
>>>>>>>>> 98 runningLock.lock();
>>>>>>>>> 99 try {
>>>>>>>>> 100 final ThreadGroup threadGroup =
>>>>>>>>> AppContext.getAppContext().getThreadGroup();
>>>>>>>>> 101 AccessController.doPrivileged((PrivilegedAction<Object>)
>>>>>>>>> () -> {
>>>>>>>>> 102 String name = "TimerQueue";
>>>>>>>>> 103 Thread timerThread = new
>>>>>>>>> ManagedLocalsThread(threadGroup,
>>>>>>>>> 104 this, name);
>>>>>>>>>
>>>>>>>>> !running check is missing after try. It is not the case with
>>>>>>>>> current code base, but it may be changed in future.
>>>>>>>>>
>>>>>>>>> Thanks,
>>>>>>>>>
>>>>>>>>> Alexander.
>>>>>>>>>
>>>>>>>>> On 07/09/2015 08:08 PM, Semyon Sadetsky wrote:
>>>>>>>>>> Hello,
>>>>>>>>>>
>>>>>>>>>> Please review fix for JDK9:
>>>>>>>>>>
>>>>>>>>>> bug: https://bugs.openjdk.java.net/browse/JDK-8130735
>>>>>>>>>> webrev: http://cr.openjdk.java.net/~ssadetsky/8130735/webrev.00/
>>>>>>>>>>
>>>>>>>>>> The root cause is the setting larger expiration time for the
>>>>>>>>>> timer which is already inserted into the delay queue. So all
>>>>>>>>>> timers behind the timer cannot be executed earlier than its
>>>>>>>>>> expiration time. This happens very rare only for repeated
>>>>>>>>>> timers and only if user uses the Swing timer API inaccurately
>>>>>>>>>> (call start() without stop()).
>>>>>>>>>> The fix eliminates this possibility by introducing a check if
>>>>>>>>>> the timer was already restarted concurrently.
>>>>>>>>>> It is difficult to write test because I could not reliably
>>>>>>>>>> reproduce the issue for a reasonable time.
>>>>>>>>>>
>>>>>>>>>> --Semyon
>>>>>>>>>
>>>>>>>>
>>>>>>>
>>>>>>
>>>>>>
>>>>>> --
>>>>>> Best regards, Sergey.
>>>>>
>>>>
>>>
>>
>
More information about the swing-dev
mailing list