From d5b44db3d32a5aab2a556218720b0c8e5c956c86 Mon Sep 17 00:00:00 2001 From: Lorenzo Gabriele Date: Sat, 25 Jul 2020 11:58:28 +0200 Subject: [PATCH 1/6] Add travis CI script --- .travis.yml | 18 ++++++++++++++++++ build.sbt | 2 +- 2 files changed, 19 insertions(+), 1 deletion(-) create mode 100644 .travis.yml diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..3f7aaa5 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,18 @@ +os: linux +dist: xenial +language: scala +branches: + only: + - master +scala: + - 2.11.12 +jdk: + - openjdk8 +before_cache: + - find $HOME/.sbt -name "*.lock" -print -delete +compiler: clang +script: sbt test +cache: + directories: + - $HOME/.sbt + - $HOME/.cache/coursier diff --git a/build.sbt b/build.sbt index 0873dee..04bd884 100644 --- a/build.sbt +++ b/build.sbt @@ -44,7 +44,7 @@ lazy val commonSettings = Seq( "-Ywarn-unused-import" ), Compile / doc / scalacOptions -= "-Xfatal-warnings", - libraryDependencies += "com.lihaoyi" %%% "utest" % "0.7.5-SNAPSHOT" % Test, + libraryDependencies += "com.lihaoyi" %%% "utest" % "0.7.4" % Test, testFrameworks += new TestFramework("utest.runner.Framework"), Test / nativeLinkStubs := true, publish / skip := true, From 8b3767dec12f6e473768a3f18038bdb276de2520 Mon Sep 17 00:00:00 2001 From: Lorenzo Gabriele Date: Sat, 25 Jul 2020 12:53:37 +0200 Subject: [PATCH 2/6] Skip tests on example modules --- build.sbt | 30 +++++++++++++++++++++++++----- 1 file changed, 25 insertions(+), 5 deletions(-) diff --git a/build.sbt b/build.sbt index 04bd884..b2997e4 100644 --- a/build.sbt +++ b/build.sbt @@ -44,13 +44,17 @@ lazy val commonSettings = Seq( "-Ywarn-unused-import" ), Compile / doc / scalacOptions -= "-Xfatal-warnings", - libraryDependencies += "com.lihaoyi" %%% "utest" % "0.7.4" % Test, + libraryDependencies += "com.lihaoyi" %%% "utest" % "0.7.5-SNAPSHOT" % Test, testFrameworks += new TestFramework("utest.runner.Framework"), Test / nativeLinkStubs := true, publish / skip := true, publishLocal / skip := true ) +lazy val examplesSettings = Seq( + test := {} +) + lazy val core = project .in(file("core")) .settings(name := "native-loop-core") @@ -62,18 +66,21 @@ lazy val core = project lazy val pipe = project .in(file("pipe")) .settings(commonSettings) + .settings(test := {}) .enablePlugins(ScalaNativePlugin) .dependsOn(core) lazy val client = project .in(file("client")) .settings(commonSettings) + .settings(test := {}) .enablePlugins(ScalaNativePlugin) .dependsOn(core) lazy val server = project .in(file("server")) .settings(commonSettings) + .settings(test := {}) .enablePlugins(ScalaNativePlugin) .dependsOn(core) @@ -81,6 +88,7 @@ lazy val scalaJsCompat = project .in(file("scalajs-compat")) .settings(name := "native-loop-js-compat") .settings(commonSettings) + .settings(test := {}) .settings(publish / skip := false) .settings(publishLocal / skip := false) .enablePlugins(ScalaNativePlugin) @@ -88,24 +96,36 @@ lazy val scalaJsCompat = project lazy val serverExample = project .in(file("examples/server")) - .settings(commonSettings) + .settings( + commonSettings, + examplesSettings + ) .enablePlugins(ScalaNativePlugin) .dependsOn(core, server, client) lazy val pipeExample = project .in(file("examples/pipe")) - .settings(commonSettings) + .settings( + commonSettings, + examplesSettings + ) .enablePlugins(ScalaNativePlugin) .dependsOn(core, pipe, client) lazy val curlExample = project .in(file("examples/curl")) - .settings(commonSettings) + .settings( + commonSettings, + examplesSettings + ) .enablePlugins(ScalaNativePlugin) .dependsOn(core, client) lazy val timerExample = project .in(file("examples/timer")) - .settings(commonSettings) + .settings( + commonSettings, + examplesSettings + ) .enablePlugins(ScalaNativePlugin) .dependsOn(core) From c8832ef2fcc130ca20e51d0ed435c87a59ae91c0 Mon Sep 17 00:00:00 2001 From: Lorenzo Gabriele Date: Sat, 25 Jul 2020 12:55:08 +0200 Subject: [PATCH 3/6] 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. --- .../scala/scalanative/loop/Eventloop.scala | 60 +++++++++---------- 1 file changed, 30 insertions(+), 30 deletions(-) diff --git a/core/src/main/scala/scala/scalanative/loop/Eventloop.scala b/core/src/main/scala/scala/scalanative/loop/Eventloop.scala index 76a2509..1672210 100644 --- a/core/src/main/scala/scala/scalanative/loop/Eventloop.scala +++ b/core/src/main/scala/scala/scalanative/loop/Eventloop.scala @@ -10,38 +10,38 @@ object EventLoop { // Schedule loop execution after main ends scalanative.runtime.ExecutionContext.global.execute( new Runnable { - - /** - * This is the implementation of the event loop - * that integrates with libuv. The logic is the - * following: - * - First we run all Scala futures in the default - * execution context - * - Then in loop: - * - we check if they generated IO calls on - * the event loop - * - If it's the case we run libuv's event loop - * using UV_RUN_ONCE until there are callbacks - * to execute - * - We run the default execution context again - * in case the callbacks generated new Futures - */ - def run(): Unit = { - @tailrec - def runUv(): Unit = { - val res = uv_run(loop, UV_RUN_ONCE) - if (res != 0) runUv() - } - - scala.scalanative.runtime.loop() - while (uv_loop_alive(loop) != 0) { - runUv() - scala.scalanative.runtime.loop() - } - uv_loop_close(loop) - } + def run(): Unit = EventLoop.run() } ) + + /** + * This is the implementation of the event loop + * that integrates with libuv. The logic is the + * following: + * - First we run all Scala futures in the default + * execution context + * - Then in loop: + * - we check if they generated IO calls on + * the event loop + * - If it's the case we run libuv's event loop + * using UV_RUN_ONCE until there are callbacks + * to execute + * - We run the default execution context again + * in case the callbacks generated new Futures + */ + def run(): Unit = { + @tailrec + def runUv(): Unit = { + val res = uv_run(loop, UV_RUN_ONCE) + if (res != 0) runUv() + } + + scala.scalanative.runtime.loop() + while (uv_loop_alive(loop) != 0) { + runUv() + scala.scalanative.runtime.loop() + } + } } @link("uv") From 6c823eecafe10be47c674f902eca39723dd9a097 Mon Sep 17 00:00:00 2001 From: Lorenzo Gabriele Date: Sat, 25 Jul 2020 12:57:44 +0200 Subject: [PATCH 4/6] 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. --- build.sbt | 2 +- .../scala/scala/scalanative/loop/LoopTestSuite.scala | 9 +++++++++ .../test/scala/scala/scalanative/loop/TimerTests.scala | 2 +- 3 files changed, 11 insertions(+), 2 deletions(-) create mode 100644 core/src/test/scala/scala/scalanative/loop/LoopTestSuite.scala diff --git a/build.sbt b/build.sbt index b2997e4..0239016 100644 --- a/build.sbt +++ b/build.sbt @@ -44,7 +44,7 @@ lazy val commonSettings = Seq( "-Ywarn-unused-import" ), Compile / doc / scalacOptions -= "-Xfatal-warnings", - libraryDependencies += "com.lihaoyi" %%% "utest" % "0.7.5-SNAPSHOT" % Test, + libraryDependencies += "com.lihaoyi" %%% "utest" % "0.7.4" % Test, testFrameworks += new TestFramework("utest.runner.Framework"), Test / nativeLinkStubs := true, publish / skip := true, diff --git a/core/src/test/scala/scala/scalanative/loop/LoopTestSuite.scala b/core/src/test/scala/scala/scalanative/loop/LoopTestSuite.scala new file mode 100644 index 0000000..8a8da28 --- /dev/null +++ b/core/src/test/scala/scala/scalanative/loop/LoopTestSuite.scala @@ -0,0 +1,9 @@ +package scala.scalanative.loop + +import utest._ + +abstract class LoopTestSuite extends TestSuite { + override def utestAfterEach(path: Seq[String]): Unit = { + EventLoop.run() + } +} diff --git a/core/src/test/scala/scala/scalanative/loop/TimerTests.scala b/core/src/test/scala/scala/scalanative/loop/TimerTests.scala index 9ed7edd..3be3a24 100644 --- a/core/src/test/scala/scala/scalanative/loop/TimerTests.scala +++ b/core/src/test/scala/scala/scalanative/loop/TimerTests.scala @@ -5,7 +5,7 @@ import scala.concurrent.duration._ import scala.concurrent.ExecutionContext.Implicits.global import scala.concurrent.Promise -object TimerTests extends TestSuite { +object TimerTests extends LoopTestSuite { val tests = Tests { def now(): Duration = System.currentTimeMillis().millis val d = 200.millis From f5e818fdee0b3512192b0084835c1b26e17a72da Mon Sep 17 00:00:00 2001 From: Lorenzo Gabriele Date: Sat, 25 Jul 2020 13:01:21 +0200 Subject: [PATCH 5/6] Install libuv in travis --- .travis.yml | 10 +++++--- .../scala/scalanative/loop/Eventloop.scala | 2 -- .../loop/internals/HandleUtils.scala | 24 +++++++++++-------- project/build.properties | 2 +- 4 files changed, 22 insertions(+), 16 deletions(-) diff --git a/.travis.yml b/.travis.yml index 3f7aaa5..ffb514d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,5 +1,5 @@ os: linux -dist: xenial +dist: bionic language: scala branches: only: @@ -10,8 +10,12 @@ jdk: - openjdk8 before_cache: - find $HOME/.sbt -name "*.lock" -print -delete -compiler: clang -script: sbt test +before_install: + # Install libuv + - sudo apt-get update + - sudo apt-get install -y libuv1-dev +script: + - sbt test cache: directories: - $HOME/.sbt diff --git a/core/src/main/scala/scala/scalanative/loop/Eventloop.scala b/core/src/main/scala/scala/scalanative/loop/Eventloop.scala index 1672210..c0db995 100644 --- a/core/src/main/scala/scala/scalanative/loop/Eventloop.scala +++ b/core/src/main/scala/scala/scalanative/loop/Eventloop.scala @@ -78,8 +78,6 @@ object LibUV { def uv_loop_close(loop: Loop): CInt = extern def uv_is_active(handle: Ptr[Byte]): Int = extern def uv_handle_size(h_type: Int): CSize = extern - def uv_handle_get_data(handle: Ptr[Byte]): Long = extern - def uv_handle_set_data(handle: Ptr[Byte], data: Long): Unit = extern def uv_req_size(r_type: Int): CSize = extern def uv_prepare_init(loop: Loop, handle: PrepareHandle): Int = extern def uv_prepare_start(handle: PrepareHandle, cb: PrepareCB): Int = extern diff --git a/core/src/main/scala/scala/scalanative/loop/internals/HandleUtils.scala b/core/src/main/scala/scala/scalanative/loop/internals/HandleUtils.scala index a0c8a44..63a21ad 100644 --- a/core/src/main/scala/scala/scalanative/loop/internals/HandleUtils.scala +++ b/core/src/main/scala/scala/scalanative/loop/internals/HandleUtils.scala @@ -1,6 +1,7 @@ package scala.scalanative.loop package internals +import scala.scalanative.runtime._ import scala.scalanative.runtime.Intrinsics._ import scala.scalanative.unsafe.Ptr import scala.scalanative.libc.stdlib @@ -8,19 +9,22 @@ import scala.collection.mutable import LibUV._ private[loop] object HandleUtils { - private val references = mutable.Map.empty[Long, Int] + private val references = mutable.Map.empty[Object, Int] @inline def getData[T <: Object](handle: Ptr[Byte]): T = { - val data = LibUV.uv_handle_get_data(handle) - val rawptr = castLongToRawPtr(data) + // data is the first member of uv_loop_t + val ptrOfPtr = handle.asInstanceOf[Ptr[Ptr[Byte]]] + val rawptr = toRawPtr(!ptrOfPtr) castRawPtrToObject(rawptr).asInstanceOf[T] } - @inline def setData[T <: Object](handle: Ptr[Byte], function: T): Unit = { - val rawptr = castObjectToRawPtr(function) - val data = castRawPtrToLong(rawptr) - if (references.contains(data)) references(data) += 1 - else references(data) = 1 - LibUV.uv_handle_set_data(handle, data) + @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) } private val onCloseCB = new CloseCB { def apply(handle: UVHandle): Unit = { @@ -29,7 +33,7 @@ private[loop] object HandleUtils { } @inline def close(handle: Ptr[Byte]): Unit = { uv_close(handle, onCloseCB) - val data = LibUV.uv_handle_get_data(handle) + val data = getData[Object](handle) val current = references(data) if (current > 1) references(data) -= 1 else references.remove(data) diff --git a/project/build.properties b/project/build.properties index 797e7cc..0837f7a 100644 --- a/project/build.properties +++ b/project/build.properties @@ -1 +1 @@ -sbt.version=1.3.10 +sbt.version=1.3.13 From 11d154152a8d43e2b14002f06a8101a2a36a7c79 Mon Sep 17 00:00:00 2001 From: Lorenzo Gabriele Date: Sat, 25 Jul 2020 15:33:07 +0200 Subject: [PATCH 6/6] Remove comment in .travis.yml --- .travis.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index ffb514d..6c0d469 100644 --- a/.travis.yml +++ b/.travis.yml @@ -11,7 +11,6 @@ jdk: before_cache: - find $HOME/.sbt -name "*.lock" -print -delete before_install: - # Install libuv - sudo apt-get update - sudo apt-get install -y libuv1-dev script: