Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 15 additions & 6 deletions core/src/main/scala/scala/scalanative/loop/Timer.scala
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import LibUV._, LibUVConstants._
import scala.scalanative.unsafe.Ptr
import internals.HandleUtils

@inline class Timer private (private val ptr: Ptr[Byte]) extends AnyVal {
@inline final class Timer private (private val ptr: Ptr[Byte]) extends AnyVal {
def clear(): Unit = {
uv_timer_stop(ptr)
HandleUtils.close(ptr)
Expand Down Expand Up @@ -37,21 +37,30 @@ object Timer {
val timerHandle = stdlib.malloc(uv_handle_size(UV_TIMER_T))
uv_timer_init(EventLoop.loop, timerHandle)
HandleUtils.setData(timerHandle, callback)
val timer = new Timer(timerHandle)
val withClearIfTimeout: () => Unit =
if (repeat == 0L) { () =>
{
callback()
timer.clear()
}
} else callback
uv_timer_start(timerHandle, timeoutCB, timeout, repeat)
new Timer(timerHandle)
timer
}

def delay(duration: FiniteDuration): Future[Unit] = {
val promise = Promise[Unit]()
timeout(duration.toMillis)(() => promise.success(()))
timeout(duration)(() => promise.success(()))
promise.future
}

def timeout(millis: Long)(callback: () => Unit): Timer = {
startTimer(millis, 0L, callback)
def timeout(duration: FiniteDuration)(callback: () => Unit): Timer = {
startTimer(duration.toMillis, 0L, callback)
}

def repeat(millis: Long)(callback: () => Unit): Timer = {
def repeat(duration: FiniteDuration)(callback: () => Unit): Timer = {
val millis = duration.toMillis
startTimer(millis, millis, callback)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,28 +14,38 @@ private[loop] object HandleUtils {
@inline def getData[T <: Object](handle: Ptr[Byte]): T = {
// data is the first member of uv_loop_t
val ptrOfPtr = handle.asInstanceOf[Ptr[Ptr[Byte]]]
val rawptr = toRawPtr(!ptrOfPtr)
castRawPtrToObject(rawptr).asInstanceOf[T]
val dataPtr = !ptrOfPtr
if (dataPtr == null) null.asInstanceOf[T]
else {
val rawptr = toRawPtr(dataPtr)
castRawPtrToObject(rawptr).asInstanceOf[T]
}
}
@inline def setData(handle: Ptr[Byte], obj: Object): Unit = {
if (references.contains(obj)) references(obj) += 1
else references(obj) = 1

// data is the first member of uv_loop_t
val ptrOfPtr = handle.asInstanceOf[Ptr[Ptr[Byte]]]
val rawptr = castObjectToRawPtr(obj)
!ptrOfPtr = fromRawPtr[Byte](rawptr)
if(obj != null) {
if (references.contains(obj)) references(obj) += 1
else references(obj) = 1
val rawptr = castObjectToRawPtr(obj)
!ptrOfPtr = fromRawPtr[Byte](rawptr)
} else {
!ptrOfPtr = null
}
}
private val onCloseCB = new CloseCB {
def apply(handle: UVHandle): Unit = {
stdlib.free(handle)
}
}
@inline def close(handle: Ptr[Byte]): Unit = {
uv_close(handle, onCloseCB)
val data = getData[Object](handle)
val current = references(data)
if (current > 1) references(data) -= 1
else references.remove(data)
if(getData(handle) != null) {
uv_close(handle, onCloseCB)
val data = getData[Object](handle)
val current = references(data)
if (current > 1) references(data) -= 1
else references.remove(data)
setData(handle, null)
}
}
}
14 changes: 12 additions & 2 deletions core/src/test/scala/scala/scalanative/loop/TimerTests.scala
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ object TimerTests extends LoopTestSuite {
val times = 3
val p = Promise[Unit]()
var timer: Timer = null.asInstanceOf[Timer]
timer = Timer.repeat(d.toMillis) { () =>
timer = Timer.repeat(d) { () =>
if (i == times) {
p.success(())
timer.clear()
Expand All @@ -43,13 +43,23 @@ object TimerTests extends LoopTestSuite {
}
}
test("clear timeout") {
val handle = Timer.timeout(d.toMillis) { () =>
val handle = Timer.timeout(d) { () =>
throw new Exception("This timeout should have not triggered")
}
handle.clear()
for {
() <- Timer.delay(d * 2)
} yield ()
}
test("close multiple times") {
val timer = Timer.timeout(10.millis)(() => {})
timer.clear()
timer.clear()
global.execute(new Runnable { def run(): Unit = timer.clear() })
Timer.timeout(50.millis) { () =>
timer.clear()
timer.clear()
}
}
}
}