{"action":"closed","issue":{"url":"https://api.github.com/repos/scalaz/scalaz-zio/issues/68","repository_url":"https://api.github.com/repos/scalaz/scalaz-zio","labels_url":"https://api.github.com/repos/scalaz/scalaz-zio/issues/68/labels{/name}","comments_url":"https://api.github.com/repos/scalaz/scalaz-zio/issues/68/comments","events_url":"https://api.github.com/repos/scalaz/scalaz-zio/issues/68/events","html_url":"https://github.com/scalaz/scalaz-zio/issues/68","id":335225621,"node_id":"MDU6SXNzdWUzMzUyMjU2MjE=","number":68,"title":"Fix issues with non-interruption after failure state","user":{"login":"jdegoes","id":156745,"node_id":"MDQ6VXNlcjE1Njc0NQ==","avatar_url":"https://avatars1.githubusercontent.com/u/156745?v=4","gravatar_id":"","url":"https://api.github.com/users/jdegoes","html_url":"https://github.com/jdegoes","followers_url":"https://api.github.com/users/jdegoes/followers","following_url":"https://api.github.com/users/jdegoes/following{/other_user}","gists_url":"https://api.github.com/users/jdegoes/gists{/gist_id}","starred_url":"https://api.github.com/users/jdegoes/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/jdegoes/subscriptions","organizations_url":"https://api.github.com/users/jdegoes/orgs","repos_url":"https://api.github.com/users/jdegoes/repos","events_url":"https://api.github.com/users/jdegoes/events{/privacy}","received_events_url":"https://api.github.com/users/jdegoes/received_events","type":"User","site_admin":false},"labels":[],"state":"closed","locked":false,"assignee":null,"assignees":[],"milestone":null,"comments":1,"created_at":"2018-06-25T00:17:06Z","updated_at":"2018-07-06T20:06:38Z","closed_at":"2018-07-06T20:06:38Z","author_association":"MEMBER","body":"Following #53, interruption can be made more precise, which may address #64. \r\n\r\nCurrently `uninterruptibly` is implemented like so:\r\n\r\n```scala\r\n                    curIo = for {\r\n                      _ <- enterUninterruptible\r\n                      v <- io.io\r\n                      _ <- exitUninterruptible\r\n                    } yield v\r\n```\r\n\r\nThis is not actually precise, because if `io.io`. fails, then the fiber will be in a permanently non-interruptible state. In theory, this can be solved by:\r\n\r\n```scala\r\n                    curIo = for {\r\n                      _ <- enterUninterruptible\r\n                      e <- io.io.attempt\r\n                      _ <- exitUninterruptible\r\n                      v <- e.fold(IO.fail)(IO.now)\r\n                    } yield v\r\n```\r\n\r\nBut this makes it much slower. With `Ensuring` becoming a fast operation thanks to #53, we can do better:\r\n\r\n```scala\r\n                    curIo = enterUninterruptible.flatMap(_ => io.io.ensuring(exitUninterruptible))\r\n```\r\n\r\nBecause `enterUninterruptible` cannot fail, and because once in such a state, the fiber cannot be interrupted during the `flatMap`, the only place for the computation to fail is `io.io`, which is now attached with a finalizer that exits the uninterruptible section.\r\n\r\nNow some care is needed elsewhere. In particular, when a `Finalizer` is being run.\r\n\r\n```scala\r\ndef apply(a: Any): IO[E, Any] = finalizer.widenError[E] *> IO.now(a)\r\n```\r\n\r\nIn the failure scenario, if the finalizer is popped off the stack during error or interruption, then it's uninterruptible status must be guaranteed (and, it seems like this is true!).\r\n\r\nBut in the success scenario, if the `Finalizer` is popped off the stack via `nextInstr`, then it's quite possible that the action will be interrupted before anything inside the `Finalizer.finalizer` is actually run.\r\n\r\nIn order to guard against this, one option is to modify `nextInstr` so that it checks to see if the next instruction is a `Finalizer`, and if so, it enters an uninterruptible section (`noInterrupt += 1`), and pushes another action on the stack (`_ => exitUninterruptible`) to exit the interruptible section after the finalizer has been executed.\r\n\r\nNote there is no need and of course it would create a circular loop for `ensuring` to be used here. The reason is that if the finalizer fails (which is the only way the above composite io can fail), then the fiber will be terminated, so the lack of exiting the uninterruptible section has no effect.\r\n\r\nOther logic around interruption / finalizers should be checked and confirmed in this ticket."}}
{"actor":{"display_login":"jdegoes"}}