Skip to content

Commit 386823a

Browse files
authored
Add travis CI script (#28)
* Add travis CI script * Skip tests on example modules * Make EventLoop runnable multiple times - Skip uv_loop_close since it doesn't allow to run the event loop multiple times - Extract run() function of the bootstrap runnable to a separate public function. * Support utest 0.7.4 - Now to run asynchronous tests it's not needed the patched utest from the master branch. - Using utest 0.7.4 and having the EventLoop runnable multiple times, it is run after every test. * Install libuv in travis - Since the installed library doesn't contain the exposed symbols for `uv_handle_get_data` and `uv_handle_set_data` now the data is got directly from the pointer since it's the first field of the uv_loop_t struct.
1 parent a0873e5 commit 386823a

File tree

7 files changed

+101
-49
lines changed

7 files changed

+101
-49
lines changed

.travis.yml

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
os: linux
2+
dist: bionic
3+
language: scala
4+
branches:
5+
only:
6+
- master
7+
scala:
8+
- 2.11.12
9+
jdk:
10+
- openjdk8
11+
before_cache:
12+
- find $HOME/.sbt -name "*.lock" -print -delete
13+
before_install:
14+
- sudo apt-get update
15+
- sudo apt-get install -y libuv1-dev
16+
script:
17+
- sbt test
18+
cache:
19+
directories:
20+
- $HOME/.sbt
21+
- $HOME/.cache/coursier

build.sbt

Lines changed: 25 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -44,13 +44,17 @@ lazy val commonSettings = Seq(
4444
"-Ywarn-unused-import"
4545
),
4646
Compile / doc / scalacOptions -= "-Xfatal-warnings",
47-
libraryDependencies += "com.lihaoyi" %%% "utest" % "0.7.5-SNAPSHOT" % Test,
47+
libraryDependencies += "com.lihaoyi" %%% "utest" % "0.7.4" % Test,
4848
testFrameworks += new TestFramework("utest.runner.Framework"),
4949
Test / nativeLinkStubs := true,
5050
publish / skip := true,
5151
publishLocal / skip := true
5252
)
5353

54+
lazy val examplesSettings = Seq(
55+
test := {}
56+
)
57+
5458
lazy val core = project
5559
.in(file("core"))
5660
.settings(name := "native-loop-core")
@@ -62,50 +66,66 @@ lazy val core = project
6266
lazy val pipe = project
6367
.in(file("pipe"))
6468
.settings(commonSettings)
69+
.settings(test := {})
6570
.enablePlugins(ScalaNativePlugin)
6671
.dependsOn(core)
6772

6873
lazy val client = project
6974
.in(file("client"))
7075
.settings(commonSettings)
76+
.settings(test := {})
7177
.enablePlugins(ScalaNativePlugin)
7278
.dependsOn(core)
7379

7480
lazy val server = project
7581
.in(file("server"))
7682
.settings(commonSettings)
83+
.settings(test := {})
7784
.enablePlugins(ScalaNativePlugin)
7885
.dependsOn(core)
7986

8087
lazy val scalaJsCompat = project
8188
.in(file("scalajs-compat"))
8289
.settings(name := "native-loop-js-compat")
8390
.settings(commonSettings)
91+
.settings(test := {})
8492
.settings(publish / skip := false)
8593
.settings(publishLocal / skip := false)
8694
.enablePlugins(ScalaNativePlugin)
8795
.dependsOn(core)
8896

8997
lazy val serverExample = project
9098
.in(file("examples/server"))
91-
.settings(commonSettings)
99+
.settings(
100+
commonSettings,
101+
examplesSettings
102+
)
92103
.enablePlugins(ScalaNativePlugin)
93104
.dependsOn(core, server, client)
94105

95106
lazy val pipeExample = project
96107
.in(file("examples/pipe"))
97-
.settings(commonSettings)
108+
.settings(
109+
commonSettings,
110+
examplesSettings
111+
)
98112
.enablePlugins(ScalaNativePlugin)
99113
.dependsOn(core, pipe, client)
100114

101115
lazy val curlExample = project
102116
.in(file("examples/curl"))
103-
.settings(commonSettings)
117+
.settings(
118+
commonSettings,
119+
examplesSettings
120+
)
104121
.enablePlugins(ScalaNativePlugin)
105122
.dependsOn(core, client)
106123

107124
lazy val timerExample = project
108125
.in(file("examples/timer"))
109-
.settings(commonSettings)
126+
.settings(
127+
commonSettings,
128+
examplesSettings
129+
)
110130
.enablePlugins(ScalaNativePlugin)
111131
.dependsOn(core)

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

Lines changed: 30 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -10,38 +10,38 @@ object EventLoop {
1010
// Schedule loop execution after main ends
1111
scalanative.runtime.ExecutionContext.global.execute(
1212
new Runnable {
13-
14-
/**
15-
* This is the implementation of the event loop
16-
* that integrates with libuv. The logic is the
17-
* following:
18-
* - First we run all Scala futures in the default
19-
* execution context
20-
* - Then in loop:
21-
* - we check if they generated IO calls on
22-
* the event loop
23-
* - If it's the case we run libuv's event loop
24-
* using UV_RUN_ONCE until there are callbacks
25-
* to execute
26-
* - We run the default execution context again
27-
* in case the callbacks generated new Futures
28-
*/
29-
def run(): Unit = {
30-
@tailrec
31-
def runUv(): Unit = {
32-
val res = uv_run(loop, UV_RUN_ONCE)
33-
if (res != 0) runUv()
34-
}
35-
36-
scala.scalanative.runtime.loop()
37-
while (uv_loop_alive(loop) != 0) {
38-
runUv()
39-
scala.scalanative.runtime.loop()
40-
}
41-
uv_loop_close(loop)
42-
}
13+
def run(): Unit = EventLoop.run()
4314
}
4415
)
16+
17+
/**
18+
* This is the implementation of the event loop
19+
* that integrates with libuv. The logic is the
20+
* following:
21+
* - First we run all Scala futures in the default
22+
* execution context
23+
* - Then in loop:
24+
* - we check if they generated IO calls on
25+
* the event loop
26+
* - If it's the case we run libuv's event loop
27+
* using UV_RUN_ONCE until there are callbacks
28+
* to execute
29+
* - We run the default execution context again
30+
* in case the callbacks generated new Futures
31+
*/
32+
def run(): Unit = {
33+
@tailrec
34+
def runUv(): Unit = {
35+
val res = uv_run(loop, UV_RUN_ONCE)
36+
if (res != 0) runUv()
37+
}
38+
39+
scala.scalanative.runtime.loop()
40+
while (uv_loop_alive(loop) != 0) {
41+
runUv()
42+
scala.scalanative.runtime.loop()
43+
}
44+
}
4545
}
4646

4747
@link("uv")
@@ -78,8 +78,6 @@ object LibUV {
7878
def uv_loop_close(loop: Loop): CInt = extern
7979
def uv_is_active(handle: Ptr[Byte]): Int = extern
8080
def uv_handle_size(h_type: Int): CSize = extern
81-
def uv_handle_get_data(handle: Ptr[Byte]): Long = extern
82-
def uv_handle_set_data(handle: Ptr[Byte], data: Long): Unit = extern
8381
def uv_req_size(r_type: Int): CSize = extern
8482
def uv_prepare_init(loop: Loop, handle: PrepareHandle): Int = extern
8583
def uv_prepare_start(handle: PrepareHandle, cb: PrepareCB): Int = extern

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

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,30 @@
11
package scala.scalanative.loop
22
package internals
33

4+
import scala.scalanative.runtime._
45
import scala.scalanative.runtime.Intrinsics._
56
import scala.scalanative.unsafe.Ptr
67
import scala.scalanative.libc.stdlib
78
import scala.collection.mutable
89
import LibUV._
910

1011
private[loop] object HandleUtils {
11-
private val references = mutable.Map.empty[Long, Int]
12+
private val references = mutable.Map.empty[Object, Int]
1213

1314
@inline def getData[T <: Object](handle: Ptr[Byte]): T = {
14-
val data = LibUV.uv_handle_get_data(handle)
15-
val rawptr = castLongToRawPtr(data)
15+
// data is the first member of uv_loop_t
16+
val ptrOfPtr = handle.asInstanceOf[Ptr[Ptr[Byte]]]
17+
val rawptr = toRawPtr(!ptrOfPtr)
1618
castRawPtrToObject(rawptr).asInstanceOf[T]
1719
}
18-
@inline def setData[T <: Object](handle: Ptr[Byte], function: T): Unit = {
19-
val rawptr = castObjectToRawPtr(function)
20-
val data = castRawPtrToLong(rawptr)
21-
if (references.contains(data)) references(data) += 1
22-
else references(data) = 1
23-
LibUV.uv_handle_set_data(handle, data)
20+
@inline def setData(handle: Ptr[Byte], obj: Object): Unit = {
21+
if (references.contains(obj)) references(obj) += 1
22+
else references(obj) = 1
23+
24+
// data is the first member of uv_loop_t
25+
val ptrOfPtr = handle.asInstanceOf[Ptr[Ptr[Byte]]]
26+
val rawptr = castObjectToRawPtr(obj)
27+
!ptrOfPtr = fromRawPtr[Byte](rawptr)
2428
}
2529
private val onCloseCB = new CloseCB {
2630
def apply(handle: UVHandle): Unit = {
@@ -29,7 +33,7 @@ private[loop] object HandleUtils {
2933
}
3034
@inline def close(handle: Ptr[Byte]): Unit = {
3135
uv_close(handle, onCloseCB)
32-
val data = LibUV.uv_handle_get_data(handle)
36+
val data = getData[Object](handle)
3337
val current = references(data)
3438
if (current > 1) references(data) -= 1
3539
else references.remove(data)
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
package scala.scalanative.loop
2+
3+
import utest._
4+
5+
abstract class LoopTestSuite extends TestSuite {
6+
override def utestAfterEach(path: Seq[String]): Unit = {
7+
EventLoop.run()
8+
}
9+
}

core/src/test/scala/scala/scalanative/loop/TimerTests.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import scala.concurrent.duration._
55
import scala.concurrent.ExecutionContext.Implicits.global
66
import scala.concurrent.Promise
77

8-
object TimerTests extends TestSuite {
8+
object TimerTests extends LoopTestSuite {
99
val tests = Tests {
1010
def now(): Duration = System.currentTimeMillis().millis
1111
val d = 200.millis

project/build.properties

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
sbt.version=1.3.10
1+
sbt.version=1.3.13

0 commit comments

Comments
 (0)