Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

TrampolineScheduler NullPointerException #1702

Closed
DylanSale opened this issue Sep 26, 2014 · 3 comments
Closed

TrampolineScheduler NullPointerException #1702

DylanSale opened this issue Sep 26, 2014 · 3 comments
Labels
Milestone

Comments

@DylanSale
Copy link

There is an issue in TrampolineScheduler on 0.20.4 where it can throw a NullPointerException in InnerCurrentThreadScheduler enqueue(Action0 action, long execTime)

        private Subscription enqueue(Action0 action, long execTime) {
            if (innerSubscription.isUnsubscribed()) {
                return Subscriptions.empty();
            }
            PriorityQueue<TimedAction> queue = QUEUE.get();
            final TimedAction timedAction = new TimedAction(action, execTime, COUNTER_UPDATER.incrementAndGet(TrampolineScheduler.this));
            queue.add(timedAction);

            if (wip.getAndIncrement() == 0) {
                do {
                    queue.poll().action.call();
                } while (wip.decrementAndGet() > 0);
                return Subscriptions.empty();
            } else {
                // queue wasn't empty, a parent is already processing so we just add to the end of the queue
                return Subscriptions.create(new Action0() {

                    @Override
                    public void call() {
                        PriorityQueue<TimedAction> _q = QUEUE.get();
                        if (_q != null) {
                            _q.remove(timedAction);
                        }
                    }

                });
            }
        }

The Exception happens on queue.poll().action.call();.
From what I can tell, the queue is empty, and poll is returning null.

This is happening inside a nested observable.redo().timeout().redo() chain (the redo().timeout() happens earlier in the application, it isn't just one after the other like that), if that helps. I'm not in a position to create a simple replication example however.

My current theory is: One of the redos could be unsubscribing, calling _q.remove, while the wip loop is running (perhaps unsubscribe is happening on another thread?), causing the queue to become empty, and the next loop of the wip loop returns null. I think the queue.poll() call should check for null.

@benjchristensen
Copy link
Member

Thanks for the report. I'll take a look.

@benjchristensen benjchristensen added this to the 1.0 milestone Oct 7, 2014
benjchristensen added a commit to benjchristensen/RxJava that referenced this issue Oct 9, 2014
I tried for about 30 minutes to replicate the NPE reported in ReactiveX#1702 but couldn't.
It makes sense reading the code that an unsubscribe could trigger an NPE though so I'm fixing it as per recommendation of @DylanSale even though I can't replicate.
I confirmed that the items are being put in the queue BEFORE the wip variable is incremented, so that concurrency seems okay.
@benjchristensen
Copy link
Member

Fixed (I hope) in #1736

akarnokd added a commit that referenced this issue Jan 23, 2015
Fixes NPEs reported in #1702 by synchronizing queue.
@akarnokd
Copy link
Member

Hi. Fixed in 1.x branch via #2471. Can you verify the fix works for your case?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

3 participants