Skip to content

TrampolineScheduler NullPointerException #1702

Closed
@DylanSale

Description

@DylanSale

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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions