Skip to content

Commit 3afc321

Browse files
Replace manual handle memory management with GC allocated space (#2)
1 parent 526cb61 commit 3afc321

File tree

4 files changed

+34
-36
lines changed

4 files changed

+34
-36
lines changed

build.sbt

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,6 @@ lazy val commonSettings = Seq(
4040
),
4141
libraryDependencies += "com.lihaoyi" %%% "utest" % "0.8.3" % Test,
4242
testFrameworks += new TestFramework("utest.runner.Framework"),
43-
nativeConfig ~= {_.withMultithreading(false)},
4443
)
4544

4645
lazy val core = project

core/src/main/scala/scala/scalanative/loop/Poll.scala

Lines changed: 20 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,38 +1,40 @@
11
package scala.scalanative.loop
22

3-
import scala.scalanative.libc.stdlib
43
import LibUV._, LibUVConstants._
5-
import scala.scalanative.unsafe.Ptr
4+
import scala.scalanative.unsafe.{Ptr, sizeOf}
5+
import scala.scalanative.runtime.BlobArray
66
import internals.HandleUtils
77

88
class RWResult(val result: Int, val readable: Boolean, val writable: Boolean)
9-
@inline class Poll(val ptr: Ptr[Byte]) extends AnyVal {
9+
@inline class Poll(private val data: BlobArray) extends AnyVal {
10+
private def handle: Ptr[Byte] = data.atUnsafe(0)
11+
1012
def start(in: Boolean, out: Boolean)(callback: RWResult => Unit): Unit = {
11-
HandleUtils.setData(ptr, callback)
13+
HandleUtils.setData(handle, callback)
1214
var events = 0
1315
if (out) events |= UV_WRITABLE
1416
if (in) events |= UV_READABLE
15-
uv_poll_start(ptr, events, Poll.pollReadWriteCB)
17+
uv_poll_start(handle, events, Poll.pollReadWriteCB)
1618
}
1719

1820
def startReadWrite(callback: RWResult => Unit): Unit = {
19-
HandleUtils.setData(ptr, callback)
20-
uv_poll_start(ptr, UV_READABLE | UV_WRITABLE, Poll.pollReadWriteCB)
21+
HandleUtils.setData(handle, callback)
22+
uv_poll_start(handle, UV_READABLE | UV_WRITABLE, Poll.pollReadWriteCB)
2123
}
2224

2325
def startRead(callback: Int => Unit): Unit = {
24-
HandleUtils.setData(ptr, callback)
25-
uv_poll_start(ptr, UV_READABLE, Poll.pollReadCB)
26+
HandleUtils.setData(handle, callback)
27+
uv_poll_start(handle, UV_READABLE, Poll.pollReadCB)
2628
}
2729

2830
def startWrite(callback: Int => Unit): Unit = {
29-
HandleUtils.setData(ptr, callback)
30-
uv_poll_start(ptr, UV_WRITABLE, Poll.pollWriteCB)
31+
HandleUtils.setData(handle, callback)
32+
uv_poll_start(handle, UV_WRITABLE, Poll.pollWriteCB)
3133
}
3234

3335
def stop(): Unit = {
34-
uv_poll_stop(ptr)
35-
HandleUtils.close(ptr)
36+
uv_poll_stop(handle)
37+
HandleUtils.close(handle)
3638
}
3739
}
3840

@@ -72,8 +74,10 @@ object Poll {
7274
private lazy val size = uv_handle_size(UV_POLL_T)
7375

7476
def apply(fd: Int): Poll = {
75-
val pollHandle = stdlib.malloc(size)
76-
uv_poll_init(EventLoop.loop, pollHandle, fd)
77-
new Poll(pollHandle)
77+
// GC managed memory, but scans only user data
78+
val data = BlobArray.alloc(size.toInt)
79+
data.setScannableLimitUnsafe(sizeOf[Ptr[_]])
80+
uv_poll_init(EventLoop.loop, data.atUnsafe(0), fd)
81+
new Poll(data)
7882
}
7983
}

core/src/main/scala/scala/scalanative/loop/Timer.scala

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
11
package scala.scalanative.loop
22

3-
import scala.scalanative.libc.stdlib
43
import scala.concurrent.{Future, Promise}
54
import scala.concurrent.duration._
65
import LibUV._, LibUVConstants._
7-
import scala.scalanative.unsafe.Ptr
6+
import scala.scalanative.unsafe.{Ptr, sizeOf}
7+
import scala.scalanative.runtime.BlobArray
88
import internals.HandleUtils
99

10-
@inline final class Timer private (private val ptr: Ptr[Byte]) extends AnyVal {
10+
@inline final class Timer private (private val data: BlobArray) extends AnyVal {
11+
private def ptr = data.atUnsafe(0)
1112
def clear(): Unit = {
1213
uv_timer_stop(ptr)
1314
HandleUtils.close(ptr)
@@ -29,17 +30,21 @@ object Timer {
2930
repeat: Long,
3031
callback: () => Unit
3132
): Timer = {
32-
val timerHandle = stdlib.malloc(uv_handle_size(UV_TIMER_T))
33+
// GC managed memory, but scans only user data
34+
val data = BlobArray.alloc(uv_handle_size(UV_TIMER_T).toInt)
35+
data.setScannableLimitUnsafe(sizeOf[Ptr[_]])
36+
37+
val timerHandle = data.atUnsafe(0)
3338
uv_timer_init(EventLoop.loop, timerHandle)
34-
HandleUtils.setData(timerHandle, callback)
35-
val timer = new Timer(timerHandle)
39+
val timer = new Timer(data)
3640
val withClearIfTimeout: () => Unit =
3741
if (repeat == 0L) { () =>
3842
{
3943
callback()
4044
timer.clear()
4145
}
4246
} else callback
47+
HandleUtils.setData(timerHandle, withClearIfTimeout)
4348
uv_timer_start(timerHandle, timeoutCB, timeout, repeat)
4449
timer
4550
}

core/src/main/scala/scala/scalanative/loop/internals/HandleUtils.scala

Lines changed: 3 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,9 @@ package internals
44
import scala.scalanative.runtime._
55
import scala.scalanative.runtime.Intrinsics._
66
import scala.scalanative.unsafe.Ptr
7-
import scala.scalanative.libc.stdlib
87
import LibUV._
98

109
private[loop] object HandleUtils {
11-
private val references = new java.util.IdentityHashMap[Object, Int]()
12-
1310
@inline def getData[T <: Object](handle: Ptr[Byte]): T = {
1411
// data is the first member of uv_loop_t
1512
val ptrOfPtr = handle.asInstanceOf[Ptr[Ptr[Byte]]]
@@ -24,23 +21,16 @@ private[loop] object HandleUtils {
2421
// data is the first member of uv_loop_t
2522
val ptrOfPtr = handle.asInstanceOf[Ptr[Ptr[Byte]]]
2623
if (obj != null) {
27-
references.put(obj, references.get(obj) + 1)
2824
val rawptr = castObjectToRawPtr(obj)
2925
!ptrOfPtr = fromRawPtr[Byte](rawptr)
3026
} else {
3127
!ptrOfPtr = null
3228
}
3329
}
34-
private val onCloseCB: CloseCB = (handle: UVHandle) => {
35-
stdlib.free(handle)
36-
}
3730
@inline def close(handle: Ptr[Byte]): Unit = {
38-
if (getData(handle) != null) {
39-
uv_close(handle, onCloseCB)
40-
val data = getData[Object](handle)
41-
val current = references.get(data)
42-
if (current > 1) references.put(data, current - 1)
43-
else references.remove(data)
31+
val data = getData[Object](handle)
32+
if (data != null) {
33+
uv_close(handle, null)
4434
setData(handle, null)
4535
}
4636
}

0 commit comments

Comments
 (0)