                 let now = DispatchTime.now()
 
                 // Make a copy of the tasks so we can execute these while not holding the lock anymore
-                while tasksCopy.count < tasksCopy.capacity, let task = scheduledTasks.peek(), task.readyIn(now) <= .nanoseconds(0) {
-                    tasksCopy.append(task.task)
-
-                    _ = scheduledTasks.pop()
+                while tasksCopy.count < tasksCopy.capacity, let task = scheduledTasks.peek() {
+                    if task.readyIn(now) <= .nanoseconds(0) {
+                        _ = scheduledTasks.pop()
+                        tasksCopy.append(task.task)
+                    } else {
+                        nextReadyTask = task
+                        break
+                    }
                 }
 
                 tasksLock.unlock()
 
                 // all pending tasks are set to occur in the future, so we can stop looping.
-                if tasksCopy.count == 0 {
+                if tasksCopy.isEmpty {
                     break
                 }
 

                // TODO: Better locking
                tasksLock.lock()
                if scheduledTasks.isEmpty {
                    tasksLock.unlock()
                    break
                }

                task.fail(error: EventLoopError.shutdown)
            }
        }
        var nextReadyTask: ScheduledTask? = nil
        while lifecycleState != .closed {
            // Block until there are events to handle or the selector was woken up
            /* for macOS: in case any calls we make to Foundation put objects into an autoreleasepool */
            try withAutoReleasePool {

                try selector.whenReady(strategy: currentSelectorStrategy(nextReadyTask: nextReadyTask)) { ev in
                    switch ev.registration {
                    case .serverSocketChannel(let chan, _):
                        self.handleEvent(ev.io, channel: chan)
