Repository: Kotlin/kotlinx.coroutines
File: kotlinx-coroutines-core/common/src/internal/LimitedDispatcher.kt (Kotlin)

Code before:
            dispatcher.dispatchYield(this, worker)
        }
    }

    /**
     * Tries to dispatch the given [block].
     * If there are not enough workers, it starts a new one via [startWorker].
     */
    private inline fun dispatchInternal(block: Runnable, startWorker: (Worker) -> Unit) {
        // Add task to queue so running workers will be able to see that
        queue.addLast(block)
        if (runningWorkers.value >= parallelism) return
        // allocation may fail if some workers were launched in parallel or a worker temporarily decreased
        // `runningWorkers` when they observed an empty queue.
        if (!tryAllocateWorker()) return
        val task = obtainTaskOrDeallocateWorker() ?: return
        startWorker(Worker(task))
    }

    /**
     * Tries to obtain the permit to start a new worker.
     */
    private fun tryAllocateWorker(): Boolean {
        synchronized(workerAllocationLock) {
            if (runningWorkers.value >= parallelism) return false
            runningWorkers.incrementAndGet()
            return true
        }
    }

    /**
     * Obtains the next task from the queue, or logically deallocates the worker if the queue is empty.
     */
    private fun obtainTaskOrDeallocateWorker(): Runnable? {
        while (true) {
            when (val nextTask = queue.removeFirstOrNull()) {
                null -> synchronized(workerAllocationLock) {
                    runningWorkers.decrementAndGet()
                    if (queue.size == 0) return null
                    runningWorkers.incrementAndGet()
                }
                else -> return nextTask
            }
        }
    }

    override fun toString() = name ?: "$dispatcher.limitedParallelism($parallelism)"

    /**
     * A worker that polls the queue and runs tasks until there are no more of them.
     *

Review comment (suggestion):
This seems to basically be a `finally` block. Any reason not to use that, instead of `catch`+re`throw`? Same holds true below.

Code after:
            dispatcher.dispatchYield(this, worker)
        }
    }

    /**
     * Tries to dispatch the given [block].
     * If there are not enough workers, it starts a new one via [startWorker].
     */
    private inline fun dispatchInternal(block: Runnable, startWorker: (Worker) -> Unit) {
        // Add task to queue so running workers will be able to see that
        queue.addLast(block)
        if (runningWorkers.value >= parallelism) return
        // allocation may fail if some workers were launched in parallel or a worker temporarily decreased
        // `runningWorkers` when they observed an empty queue.
        if (!tryAllocateWorker()) return
        val task = obtainTaskOrDeallocateWorker() ?: return
        try {
            startWorker(Worker(task))
        } catch (e: Throwable) {
            /* If we failed to start a worker, we should decrement the counter.
            The queue is in an inconsistent state--it's non-empty despite the target parallelism not having been
            reached--but at least a properly functioning worker will have a chance to correct this if some future
            dispatch does succeed.
            If we don't decrement the counter, it will be impossible to ever reach the target parallelism again. */
            runningWorkers.decrementAndGet()
            throw e
        }
    }

    /**
     * Tries to obtain the permit to start a new worker.
     */
    private fun tryAllocateWorker(): Boolean {
        synchronized(workerAllocationLock) {
            if (runningWorkers.value >= parallelism) return false
            runningWorkers.incrementAndGet()
            return true
        }
    }

    /**
     * Obtains the next task from the queue, or logically deallocates the worker if the queue is empty.
     */
    private fun obtainTaskOrDeallocateWorker(): Runnable? {
        while (true) {
            when (val nextTask = queue.removeFirstOrNull()) {
                null -> synchronized(workerAllocationLock) {
                    runningWorkers.decrementAndGet()
                    if (queue.size == 0) return null
                    runningWorkers.incrementAndGet()
                }