packages feed

zeolite-lang-0.24.0.0: tests/leak-check/leak-check.0rx

/* -----------------------------------------------------------------------------
Copyright 2021-2022 Kevin P. Barry

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
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
----------------------------------------------------------------------------- */

// Author: Kevin P. Barry [ta0kira@gmail.com]

concrete LeakCheck {
  @type run () -> ()
}

define LeakCheck {
  @value Vector<Int> memory

  run () {
    if (Argv.global().size() != 2) {
      \ message()
    } elif (Argv.global().readAt(1) == "race") {
      \ runWith(1000, 0)
      \ BasicOutput.stderr().writeNow("no race conditions this time\n")
    } elif (Argv.global().readAt(1) == "leak") {
      \ runWith(100, 0)
    } elif (Argv.global().readAt(1) == "forever") {
      \ runWith(10000000, 1024*1024)
    } else {
      \ message()
    }
  }

  @type message () -> ()
  message () {
    fail(Argv.global().readAt(0) + " [race | leak | forever]")
  }

  @type runWith (Int, Int) -> ()
  runWith (iterations, size) {
    Int threads <- Ranges:max(3, $ExprLookup[CPU_CORE_COUNT]$-1)
    ReadAt<BarrierWait> barriers <- EnumeratedBarrier.new(threads+1)
    traverse (Counter.zeroIndexed(iterations) -> Int i) {
      \ doIteration<LastReference>(i, size, barriers)
      \ doIteration<Chaos>(i, size, barriers)
    }
  }

  @type doIteration<#f>
    #f defines ThreadFactory
  (Int, Int, ReadAt<BarrierWait>) -> ()
  doIteration (i, size, barriers) {
    \ BasicOutput.stderr()
        .write(typename<#f>())
        .write(": iteration ")
        .write(i)
        .write("\n")
        .flush()

    optional LeakCheck original <- LeakCheck{ Vector:createSize<Int>(size) }
    weak LeakCheck checkedValue <- original
    $ReadOnly[checkedValue]$

    scoped {
      Vector<Thread> threads <- Vector<Thread>.new()
    } in {
      traverse (Counter.zeroIndexed(barriers.size()-1) -> Int j) {
        \ threads.push(ProcessThread.from(#f.create(original, barriers.readAt(j+1))).start())
      }

      \ barriers.readAt(0).wait()
      original <- empty

      traverse (threads.defaultOrder() -> Thread thread) {
        \ thread.join()
      }
    }

    // Make sure that threads are out of scope before validating.
    $ValidateRefs[checkedValue]$
  }
}

@type interface ThreadFactory {
  create (optional LeakCheck, BarrierWait) -> (Routine)
}

concrete LastReference {
  defines ThreadFactory
}

define LastReference {
  $ReadOnlyExcept[]$

  refines Routine

  @value weak LeakCheck copy
  @value BarrierWait barrier

  create (copy, barrier) {
    return LastReference{ copy, barrier }
  }

  run ()  {
    \ barrier.wait()
    \ strong(copy)
  }
}

concrete Chaos {
  defines ThreadFactory
}

define Chaos {
  $ReadOnly[barrier]$

  refines Routine

  @value weak LeakCheck copy
  @value BarrierWait barrier

  create (copy, barrier) {
    return Chaos{ copy, barrier }
  }

  run ()  {
    weak LeakCheck copy1 <- empty
    weak LeakCheck copy2 <- empty
    weak LeakCheck copy3 <- empty
    weak LeakCheck copy4 <- empty
    weak LeakCheck copy5 <- empty
    \ barrier.wait()
    copy1 <- copy
    copy2 <- copy1
    copy3 <- copy1
    copy3 <-> copy1
    copy1 <-> copy1
    copy2 <-> copy1
    copy <- empty
    copy4 <- strong(copy2)
    copy1 <- strong(copy3)
    copy2 <- empty
    copy3 <- empty
  }
}