swiftlang / swiftlang/swift-corelibs-libdispatch

[SR-11647] Swift 5.1 on Linux: Regression in OperationQueue concurrency

Open
#614 2 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

5.1Regression bug Foundation libdispatch
Dominant language
C
Stars
2.6k
Forks
496
Avg merge
2d 6h
Merged PRs (30d)
3

Description

Previous ID SR-11647
Radar None
Original Reporter freak4pc (JIRA User)
Type Bug
Environment

Swift 5.1.1 latest Docker image

Additional Detail from JIRA
Votes 0
Component/s Foundation, libdispatch
Labels Bug, 5.1Regression
Assignee None
Priority Medium

md5: 4aa6a76a0b5ee28f3059851ef77c1f74

relates to:

  • SR-11864 Availability warnings in dead code paths

Issue Description:

We've bumped into an interesting regression in RxSwift's OperationQueueScheduler that wraps OperationQueue, specifically under Linux. It seems concurrency is broken or hangs.

The full issue is here:
https://github.com/ReactiveX/RxSwift/pull/2077#issuecomment-544166860

I was able to reduce the issue using only OperationQueue, without Rx:

import Foundation

let condition = NSCondition()
let sema = DispatchSemaphore(value: 0)
var writtenStarted = 0
var writtenEnded = 0
var events = [String]()
var lock = NSLock()

func performLocked(_ action: () -> Void) {
    lock.lock()
    action()
    lock.unlock()
}

let concurrent = {
    performLocked {
        print("Started")
        events.append("Started")
    }

    condition.lock()
    writtenStarted += 1
    condition.signal()
    while writtenStarted < 2 {
        condition.wait()
    }
    condition.unlock()

    performLocked {
        print("Ended")
        events.append("Ended")
    }

    condition.lock()
    writtenEnded += 1
    condition.signal()
    while writtenEnded < 2 {
        condition.wait()
    }
    condition.unlock()
    sema.signal()
}

let op1 = BlockOperation(block: concurrent)
let op2 = BlockOperation(block: concurrent)

let operationQueue = OperationQueue()
operationQueue.maxConcurrentOperationCount = 8

operationQueue.addOperation(op1)
operationQueue.addOperation(op2)
sema.wait()

Running the following code on macOS (in Swift 5.1 as well) or Linux with Swift 5.0 yields:

$ swift regression.swift
Started
Started
Ended
Ended

Running it under Linux with Swift 5.1:

$ swift -v
Swift version 5.1.1 (swift-5.1.1-RELEASE)

$ swift regression.swift
Started
-> At this point the process hangs and never completes

This seems to be an open regression in Swift 5.1 under Linux, but happy for any feedback or to provide any additional information.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start by running the embedded regression with Swift 5.1.1 on Linux and compare it with Swift 5.0 or macOS. Investigate the OperationQueue and BlockOperation interaction through Foundation and libdispatch; done means the two operations complete and print both Started and Ended lines without hanging.

Written by the indexing model from the issue text.

Assessment

Tech stack
linux, swift
Domain
operating-systems
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.