JensRavens/Interstellar

Possible data race in function `subscribe`

couchdeveloper opened this issue · 0 comments

In function subscribe

    public func subscribe(f: Result<T> -> Void) -> Signal<T> {
        if let value = value {
            f(value)
        }
        mutex.lock {
            callbacks.append(f)
        }
        return self
    }

https://github.com/JensRavens/Interstellar/blob/master/Sources/Signal.swift#L145-L153

it seems to me, there's a potential data race: access to value should be protected by the mutex.

Proposed solution:

    public func subscribe(f: Result<T> -> Void) -> Signal<T> {
        var v: Result<T>?
        mutex.lock {
            v = self.value
            callbacks.append(f)
        }
        if let value = v {
            f(value)
        }
        return self
    }

Still, this is not a reliable solution: it's not guaranteed, that function f will be invoked before any other mapping function which is invoked due to an update. These kind of issues can be solved only with introducing an "execution context" (for example a dispatch queue) which defines where the mapping function will be executed:

    public func subscribe(ec: ExecutionContext = <default>, f: Result<T> -> Void) -> Signal<T> {
        mutex.lock {
            if let value = self.value {
                ec.execAsync { f(value) }
            }
            callbacks.append(f)
        }
        return self
    }