<commit_before>//
//  Semaphore.swift
//  LightweightSemaphore
//
//  Created by <NAME> on 2015-04-03.
//  Copyright (c) 2015 <NAME>. All rights reserved.
//

import Darwin.Mach
import Dispatch.time

struct SemaphorePool
{
  static private let capacity = 256
  static private let buffer = UnsafeMutablePointer<ChannelSemaphore>.alloc(capacity)
  static private var cursor = 0

  static private var lock = OS_SPINLOCK_INIT

  static func Return(s: ChannelSemaphore)
  {
    OSSpinLockLock(&lock)
    if cursor < capacity
    {
      buffer.advancedBy(cursor).initialize(s)
      cursor += 1
    }
    OSSpinLockUnlock(&lock)
  }

  static func Obtain() -> ChannelSemaphore
  {
    OSSpinLockLock(&lock)
    if cursor > 0
    {
      cursor -= 1
      if isUniquelyReferencedNonObjC(&buffer[cursor])
      {
        let s = buffer.advancedBy(cursor).move()
        OSSpinLockUnlock(&lock)
        s.svalue = 0
        s.selected = 0
        s.currentState = .Ready
        return s
      }

      // for i in reverse(0..<cursor)
      for var i=cursor-1; i>=0; i--
      {
        if isUniquelyReferencedNonObjC(&buffer[i])
        {
          let s = buffer[i]
          buffer[i] = buffer.advancedBy(cursor).move()
          OSSpinLockUnlock(&lock)
          s.svalue = 0
          s.selected = 0
          s.currentState = .Ready
          return s
        }
      }
      cursor += 1
    }
    OSSpinLockUnlock(&lock)
    return ChannelSemaphore(value: 0)
  }
}

// MARK: ChannelSemaphoreState

enum ChannelSemaphoreState: Equatable
{
case Ready

// Unbuffered channel data
case Pointer(UnsafeMutablePointer<Void>)

// Select() case
case WaitSelect
case Select(Selection)
case Invalidated

// End state
case Done
}

func ==(ls: ChannelSemaphoreState, rs: ChannelSemaphoreState) -> Bool
{
  switch (ls, rs)
  {
  case (.Ready, .Ready): return true
  case (.Pointer(let p1), .Pointer(let p2)) where p1 == p2: return true
  case (.WaitSelect, .WaitSelect): return true
  case (.Select(let s1), .Select(let s2)) where s1.id === s2.id: return s1.semaphore === s2.semaphore
  case (.Invalidated, .Invalidated): return true
  case (.Done, .Done): return true
  default: return false
  }
}

final public class ChannelSemaphore
{
  private var svalue: Int32
  private let semp: semaphore_t

  private var currentState = ChannelSemaphoreState.Ready
  private var selected = 0

  private var statelock = OS_SPINLOCK_INIT

  private init(value: Int32)
  {
    svalue = (value > 0) ? value : 0
    semp = {
      var newport = semaphore_t()
      let kr = semaphore_create(mach_task_self_, &newport, SYNC_POLICY_FIFO, 0)
      assert(kr == KERN_SUCCESS, __FUNCTION__)
      return newport
    }()
  }

  private convenience init()
  {
    self.init(value: 0)
  }

  deinit
  {
    let kr = semaphore_destroy(mach_task_self_, semp)
    assert(kr == KERN_SUCCESS, __FUNCTION__)
  }

  final var isSelected: Bool { return selected != 0 }

  final var state: ChannelSemaphoreState {
    OSSpinLockLock(&statelock)
    let internalState = currentState
    OSSpinLockUnlock(&statelock)
    return internalState
  }

  func setState(newState: ChannelSemaphoreState) -> Bool
  {
    OSSpinLockLock(&statelock)
    let copy: Bool
    switch (currentState, newState)
    {
    case (.WaitSelect, .Select), (.WaitSelect, .Invalidated):
        copy = true
        selected = 1

    case (.Ready, .WaitSelect), (.Ready, .Pointer):
      copy = true

    case (_, .Done):
      copy = true

    default:
      copy = false
    }

    if copy { currentState = newState }
    OSSpinLockUnlock(&statelock)
    return copy
  }

  func signal() -> Bool
  {
    if OSAtomicIncrement32Barrier(&svalue) <= 0
    {
      let kr = semaphore_signal(semp)
      assert(kr == KERN_SUCCESS, __FUNCTION__)
      return kr == KERN_SUCCESS
    }
    return false
  }

  func wait() -> Bool
  {
    return wait(DISPATCH_TIME_FOREVER)
  }

  func wait(timeout: dispatch_time_t) -> Bool
  {
    if OSAtomicDecrement32Barrier(&svalue) >= 0
    {
      return true
    }

    var kr: kern_return_t
    switch timeout
    {
    case DISPATCH_TIME_NOW: // will not wait
      kr = semaphore_timedwait(semp, mach_timespec_t())
      assert(kr == KERN_SUCCESS || kr == KERN_OPERATION_TIMED_OUT, __FUNCTION__)

    case DISPATCH_TIME_FOREVER: // will wait forever
      do {
        kr = semaphore_wait(semp)
      } while kr == KERN_ABORTED
      assert(kr == KERN_SUCCESS, __FUNCTION__)<commit_msg>Lazy initialization of mach ports in ChannelSemaphore<commit_after>//
//  Semaphore.swift
//  LightweightSemaphore
//
//  Created by <NAME> on 2015-04-03.
//  Copyright (c) 2015 <NAME>. All rights reserved.
//

import Darwin.Mach
import Dispatch.time
import Foundation.NSThread

struct SemaphorePool
{
  static private let capacity = 256
  static private let buffer = UnsafeMutablePointer<ChannelSemaphore>.alloc(capacity)
  static private var cursor = 0

  static private var lock = OS_SPINLOCK_INIT

  static func Return(s: ChannelSemaphore)
  {
    OSSpinLockLock(&lock)
    if cursor < capacity
    {
      buffer.advancedBy(cursor).initialize(s)
      cursor += 1
    }
    OSSpinLockUnlock(&lock)
  }

  static func Obtain() -> ChannelSemaphore
  {
    OSSpinLockLock(&lock)
    if cursor > 0
    {
      cursor -= 1
      if isUniquelyReferencedNonObjC(&buffer[cursor])
      {
        let s = buffer.advancedBy(cursor).move()
        OSSpinLockUnlock(&lock)
        s.svalue = 0
        s.selected = 0
        s.currentState = .Ready
        return s
      }

      // for i in reverse(0..<cursor)
      for var i=cursor-1; i>=0; i--
      {
        if isUniquelyReferencedNonObjC(&buffer[i])
        {
          let s = buffer[i]
          buffer[i] = buffer.advancedBy(cursor).move()
          OSSpinLockUnlock(&lock)
          s.svalue = 0
          s.selected = 0
          s.currentState = .Ready
          return s
        }
      }
      cursor += 1
    }
    OSSpinLockUnlock(&lock)
    return ChannelSemaphore(value: 0)
  }
}

// MARK: ChannelSemaphoreState

enum ChannelSemaphoreState: Equatable
{
case Ready

// Unbuffered channel data
case Pointer(UnsafeMutablePointer<Void>)

// Select() case
case WaitSelect
case Select(Selection)
case Invalidated

// End state
case Done
}

func ==(ls: ChannelSemaphoreState, rs: ChannelSemaphoreState) -> Bool
{
  switch (ls, rs)
  {
  case (.Ready, .Ready): return true
  case (.Pointer(let p1), .Pointer(let p2)) where p1 == p2: return true
  case (.WaitSelect, .WaitSelect): return true
  case (.Select(let s1), .Select(let s2)) where s1.id === s2.id: return s1.semaphore === s2.semaphore
  case (.Invalidated, .Invalidated): return true
  case (.Done, .Done): return true
  default: return false
  }
}

final public class ChannelSemaphore
{
  private var svalue: Int32
  private var semp = semaphore_t()

  private var currentState = ChannelSemaphoreState.Ready
  private var selected = 0

  private var statelock = OS_SPINLOCK_INIT

  private init(value: Int32)
  {
    svalue = (value > 0) ? value : 0
//    semp = {
//      var newport = semaphore_t()
//      let kr = semaphore_create(mach_task_self_, &newport, SYNC_POLICY_FIFO, 0)
//      assert(kr == KERN_SUCCESS, __FUNCTION__)
//      return newport
//    }()
  }

  private convenience init()
  {
    self.init(value: 0)
  }

  deinit
  {
    let kr = semaphore_destroy(mach_task_self_, semp)
    assert(kr == KERN_SUCCESS, __FUNCTION__)
  }

  final private func initSemaphorePort()
  {
    var semaphore = semaphore_t()
    let kr = semaphore_create(mach_task_self_, &semaphore, SYNC_POLICY_FIFO, 0)
    assert(kr == KERN_SUCCESS, __FUNCTION__)

    func atomicAssignPort(port: semaphore_t, assignee: UnsafeMutablePointer<Void>) -> Bool
    { // succeed only if 'semp' is still zero
      return OSAtomicCompareAndSwap32Barrier(0, unsafeBitCast(port, Int32.self),
                                             UnsafeMutablePointer<Int32>(assignee))
    }

    if !atomicAssignPort(semaphore, &semp)
    { // another initialization attempt succeeded concurrently. Don't leak the port; return it.
      let kr = semaphore_destroy(mach_task_self_, semaphore)
      assert(kr == KERN_SUCCESS, __FUNCTION__)
    }
  }

  final var isSelected: Bool { return selected != 0 }

  final var state: ChannelSemaphoreState {
    OSSpinLockLock(&statelock)
    let internalState = currentState
    OSSpinLockUnlock(&statelock)
    return internalState
  }

  func setState(newState: ChannelSemaphoreState) -> Bool
  {
    OSSpinLockLock(&statelock)
    let copy: Bool
    switch (currentState, newState)
    {
    case (.WaitSelect, .Select), (.WaitSelect, .Invalidated):
        copy = true
        selected = 1

    case (.Ready, .WaitSelect), (.Ready, .Pointer):
      copy = true

    case (_, .Done):
      copy = true

    default:
      copy = false
    }

    if copy { currentState = newState }
    OSSpinLockUnlock(&statelock)
    return copy
  }

  func signal() -> Bool
  {
    if OSAtomicIncrement32Barrier(&svalue) <= 0
    {
      while semp == 0
      { // if svalue was previously less than zero, there must be a wait() call
        // currently in the process of initializing semp.
        NSThread.sleepForTimeInterval(1e-10)
      }

      let kr = semaphore_signal(semp)
      assert(kr == KERN_SUCCESS, __FUNCTION__)
      return kr == KERN_SUCCESS
    }
    return false
  }

  func wait() -> Bool
  {
    return wait(DISPATCH_TIME_FOREVER)
  }

  func wait(timeout: dispatch_time_t) -> Bool
  {
    if OSAtomicDecrement32Barrier(&svalue) >= 0
    {
      return true
    }

    if semp == 0 { initSemaphorePort() }

    var kr: kern_return_t
    switch timeout
    {
    case DISPATCH_TIME_NOW: // will not wait
      kr = semaphore_timedwait(semp, mach_timespec_t())
      assert(kr == KERN_SUCCESS || kr == KERN_OPERATION_TIMED_OUT, __FUNCTION__)

    case DISPATCH_TIME_FOREVER: // will wait forever
      do {
        kr = semaphore_wait(semp)
      } while kr == KERN_ABORTED
      assert(kr == KERN_SUCCESS, __FUNCTION__)
{'fraction_non_alphanumeric': 0.1018185451638689, 'fraction_numerical': 0.012290167865707434, 'mean_word_length': 2.6515870120394016, 'pattern_counts': {'":': 0, '<': 19, '<?xml version=': 0, '>': 34, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 2, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2008970', 'n_tokens_mistral': 3457, 'n_tokens_neox': 3241, 'n_words': 824}