Skip to content

Instantly share code, notes, and snippets.

View djspiewak's full-sized avatar

Daniel Spiewak djspiewak

View GitHub Profile
@djspiewak
djspiewak / Main.java
Created November 10, 2020 22:00 — forked from RaasAhsan/Main.java
minimized ARM memory barrier violation
import java.util.concurrent.atomic.*;
import java.util.concurrent.*;
public class Main {
private static ExecutorService executor = Executors.newFixedThreadPool(2);
private static int iterations = 10000000;
public static class Runner {
// writes to canceled happen before a CAS on suspended
// reads on canceled happen after a CAS on suspended
def racePair[F[_]: Concurrent, A, B](fa: F[A], fb: F[B]): F[Either[(Outcome[F, E, A], Fiber[F, E, B]), (Fiber[F, E, A], Outcome[F, E, B])]] =
MonadCancel[F] uncancelable { poll =>
for {
fibADef <- Concurrent[F].deferred[Fiber[F, E, A]]
fibBDef <- Concurrent[F].deferred[Fiber[F, E, B]]
result <- Concurrent[F].deferred[Either[(Outcome[F, E, A], Fiber[F, E, B]), (Fiber[F, E, A], Outcome[F, E, B])]]
fibA <- fa guarantee { oc =>
fibBDef.get flatMap { fibB =>
def racePair[F[_]: Concurrent, A, B](fa: F[A], fb: F[B]): F[Either[(Outcome[F, E, A], Fiber[F, E, B]), (Fiber[F, E, A], Outcome[F, E, B])]] =
for {
fibADef <- Concurrent[F].deferred[Fiber[F, E, A]]
fibBDef <- Concurrent[F].deferred[Fiber[F, E, B]]
result <- Concurrent[F].deferred[Either[(Outcome[F, E, A], Fiber[F, E, B]), (Fiber[F, E, A], Outcome[F, E, B])]]
fibA <- fa guarantee { oc =>
fibBDef.get flatMap { fibB =>
result.complete(Left((oc, fibB))).void

Proposed Cross-Publication Guidelines

What follows is my opinion on how we should tame all of this complexity. Specifically, how can we make it as easy as possible to keep everyone's builds and releases in-sync with the latest Dotty as we approach Scala 3. This is a very complex undertaking with a lot of moving parts. I'm attempting to draw on our experience doing this for prior Scala 2 versions, as well as personal scars from previous upgrade efforts across various Scala versions. In other words, this is a bit of a "lessons learned" phrased as "please everyone do this".

Any projects I have any control over will be following these steps to the best of our ability.

1. Cross-Publish Your Latest for Two Scala 3 Milestones

Breaking upgrades are always much easier when you can break them apart into the smallest possible steps. Publishing for the previous Scala 3 release in addition to the latest one is a very easy thing to do (since your library was already building on that version!) and it eases the

Fibers

Fibers are an abstraction over sequential computation, similar to threads but at a higher level. There are two ways to think about this model: by example, and abstractly from first principles. We'll start with the example.

(credit here is very much due to Fabio Labella, who's incredible Scala World talk describes these ideas far better than I can)

Callback Sequentialization

Consider the following three functions

var flag: Boolean = false
val ref: AtomicBoolean = new AtomicBoolean()
def thread1() = {
flag = true
ref.compareAndSet(false, true)
// checkpoint A
}
[info] DeferredJVMParallelism1Tests
[info] + Deferred — issue #380: with cooperative light async boundaries
[error] x Deferred — issue #380: with cooperative full async boundaries
[error] the value is false (DeferredJVMSpec.scala:175)
[info] + issue #380: complete doesn't block, test #2
[info] Total for specification DeferredJVMParallelism1Tests
[info] Finished in 10 seconds, 133 ms
[info] 3 examples, 1 failure, 0 error
[info] DeferredJVMParallelism2Tests
[info] + Deferred — issue #380: with cooperative light async boundaries
/*
* Copyright 2020 Typelevel
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
trait Exists[F[_]] {
type E
def apply(): F[E]
}
object Exists {
def apply[F[_], A](fa: F[A]): Exists[F] = new Exists[F] {
type E = A
def apply() = fa
}
object Soviet {
def repeated[F[_]: Async, A, B, R](runner: (A => B) => F[R])(body: A => F[B]): F[R] =
for {
ref <- Sync[F].delay(new AtomicReference[A => B])
result <- Sync[F].delay(new AtomicReference[B])
latch <- Sync[F].delay(new Semaphore(1))
_ <- Sync[F].delay(latch.acquire())
r <- {