上下文退出

不同的 Truffle(客体)语言可能使用不同的退出机制。这并非最佳,因为 Truffle 语言无法检测和处理由其他语言触发的退出。

自 22.0 版起,Truffle 支持客体语言通过使用 TruffleContext.closeExited(Node,int) 触发多语言上下文的硬性显式退出。它为语言提供了一种统一的方式来触发底层多语言上下文的退出。当触发时,所有已初始化的客体语言首先通过 TruffleLanguage.exitContext(C,ExitMode,int) 收到通知,然后所有上下文线程被停止,最后,上下文被关闭。硬性显式退出简称为“硬退出”。

硬退出只是 Truffle 中三种退出类型之一。退出类型如下:

  • 上面介绍的新硬退出
    • 硬退出通知在执行时,TruffleLanguage.exitContext(C,ExitMode,int) 的第二个参数使用 ExitMode.HARD
  • 隐式“自然退出”
    • 在正常上下文关闭期间发生。
    • 新引入的退出通知也适用于自然退出,但线程在自然退出通知后不会被强制停止,因此仍在运行的上下文线程可能会阻塞自然退出。
    • 自然退出通知在执行时,TruffleLanguage.exitContext(C,ExitMode,int) 的第二个参数使用 ExitMode.NATURAL
  • “软退出”
    • 通过抛出异常类型为 ExceptionType.EXIT 的 Truffle 异常来触发显式退出。
    • 该异常不会由 Truffle 自动在其他线程中抛出,它也不会自行触发退出通知或上下文关闭。
    • 软退出后上下文仍可完全使用,软退出之后可以接着是自然退出或硬退出。

为完整起见,多语言上下文也可以通过使用 Context.close(true)TruffleContext.closeCancelled(Node,String)TruffleContext.closeResourceExhausted(Node,String) 来取消它并关闭。取消操作会导致所有上下文线程立即停止并关闭上下文,而不会发送任何退出通知。

软退出 #

软退出是通过抛出异常类型为 ExceptionType.EXIT 的 Truffle 异常(即软退出异常)来触发的。该异常不会由 Truffle 自动在其他线程中抛出,也不会自行触发退出通知或上下文关闭。如果未被语言捕获,软退出异常最终会导致嵌入器线程向主机抛出一个 PolyglotException,其中 PolyglotException.isExit() == true,且 PolyglotException.getExitStatus() 等于软退出异常指定的值。

软退出后上下文仍可完全使用,但当嵌入器看到 PolyglotExceptionPolyglotException.isExit() == true 时,应关闭上下文,在这种情况下,软退出之后是自然退出。

自然退出 #

Natural exit schema

自然退出发生在由 Context.close()TruffleContext.close() 触发的正常上下文关闭期间。上图中所示的自然退出包含以下步骤:

  1. 自然退出由 Context.close()TruffleContext.close() 触发。

  2. 执行所有已初始化语言的退出通知 - TruffleLanguage.exitContext(C,ExitMode,int),其中 ExitMode.NATURAL 用作 ExitMode 参数。
    • 客体代码在退出通知期间正常运行。
  3. 所有已初始化语言都被终结。
    • 为所有已初始化的语言调用 TruffleLanguage.finalizeContext(C)
    • 客体代码在终结期间正常运行。
  4. 所有语言都被处置。
    • 为所有语言调用 TruffleLanguage.disposeContext(C)

硬退出 #

Hard exit schema

本节详细描述了硬退出过程。多语言上下文的硬退出可以通过 Context.Builder.useSystemExit(boolean) 进行自定义。因此,以下描述分为两个小节。一节说明系统退出未启用(Context.Builder.useSystemExit(false) - 默认)的情况,另一节说明系统退出已启用(Context.Builder#useSystemExit(true))的情况。退出过程的示意图显示在上方图表中。该图还说明了退出过程与上下文取消过程之间的关系。某些框的红色表示上下文在该点无效,并且无法运行任何客体代码。更确切地说,第一个 Truffle 安全点将根据是硬退出还是取消操作正在进行中,抛出一个特殊的 ThreadDeath 退出异常或一个特殊的 ThreadDeath 取消异常。

如果 useSystemExit 被禁用时的行为(默认) #

  1. 退出由 TruffleContext.closeExited(Node,int) 触发。

  2. 执行所有已初始化语言的退出通知 - TruffleLanguage.exitContext(C,ExitMode,int),其中 ExitMode.HARD 用作 ExitMode 参数。
    • 客体代码在退出通知期间正常运行。
    • 如果在退出通知期间(步骤 2a 期间)上下文未被取消并达到步骤 2b,则退出过程将继续到下一步。否则,退出通知将被中断,上下文立即被取消。
  3. 所有上下文线程通过从 Truffle 安全点抛出特殊的 ThreadDeath 退出异常而被强制停止。
    • 为了可靠地退出线程,语言需要确保 ThreadDeath 始终立即被重新抛出,并且客体语言的异常处理器和 finally 块不被运行。
    • 嵌入器线程最终会向主机抛出一个 PolyglotException,其中 PolyglotException.isExit() == true,且 PolyglotException.getExitStatus() 等于最初作为 TruffleContext.closeExited(Node,int) 首次调用的第二个参数指定的退出码。
    • 请注意,从步骤 3 开始,退出过程与图中所示的取消过程相似,但取消过程使用一个特殊的 ThreadDeath 取消异常,并且抛给主机的 PolyglotException 具有 PolyglotException.isCancelled() == true 而不是 PolyglotException.isExit() == true
  4. 所有已初始化语言都被终结。
    • 为所有已初始化的语言调用 TruffleLanguage.finalizeContext(C)
    • TruffleLanguage.finalizeContext(C) 中运行任何客体代码,都会从第一个 Truffle 安全点抛出特殊的 ThreadDeath 退出异常。
    • 语言应跳过任何需要运行客体代码的终结操作。语言可以通过检查 TruffleLanguage.exitContext(C,ExitMode,int) 是否之前以 ExitMode.NATURAL 调用,或者通过检查 TruffleContext.isClosed() 是否返回 false 来判断是否可以在 TruffleLanguage.finalizeContext(C) 中运行客体代码。
  5. 所有语言都被处置。
    • 为所有语言调用 TruffleLanguage.disposeContext(C)
  6. 上下文被关闭。

如果 useSystemExit 被启用时的行为 #

  1. 退出由 TruffleContext.closeExited(Node,int) 触发。
    • 与系统退出禁用时相同。
  2. 执行所有已初始化语言的退出通知 - TruffleLanguage.exitContext(C,ExitMode,int),其中 ExitMode.HARD 用作 ExitMode 参数。
    • 与系统退出禁用时相同。
  3. 调用 System.exit(int) 来终止整个主机应用程序,提供最快的退出方式。
    • 传递给 System.exit(int) 的退出码是最初作为 TruffleContext.closeExited(Node,int) 首次调用的第二个参数指定的退出码。

使用示例 #

SimpleLanguage 演示了硬上下文退出的用法。以下方面得到了演示:

联系我们