Skip to main content

Process Scheduling

Each script in XXTouch Elite runs as an independent process, referred to as a script process. To avoid conflicts and management difficulties caused by multiple script processes running simultaneously, script processes dispatched in the following ways can only have one instance at a time:

  • Started via volume keys
  • Started via OpenAPI calls
  • Triggered by Activator events
  • Started via the X.X.T.E. application interface
  • Directly debugged or launched via IDEs like VSCode plugins, XXTStudio, etc.
  • Started remotely via group control software, cloud control software, etc.
  • Restarted by “Daemon Mode” after unexpected termination
  • Started by features like “Startup Script” or “Scheduled Tasks”
info
  • You can use utils.launch_args to retrieve the launch arguments of the current script, allowing you to handle different launch methods accordingly.
  • Scripts started via command line or the cloud control daemon service daemon.lua are not subject to the above restrictions.

Terminate Script Process

Script processes can be terminated in the following ways:

  • os.exit
  • Script execution completion
  • Stopped via volume keys
  • Stopped via OpenAPI calls
  • Stopped via Activator events
  • Stopped via IDEs like VSCode plugins, XXTStudio, etc.
  • Stopped remotely via group control software, cloud control software, etc.
  • Sending SIGINT, SIGTERM, or SIGKILL signals to the script process via the command line kill

When a script process terminates, it immediately stops event listeners, closes the UI, terminates all threads and subprocesses (except those ignoring the SIGHUP signal) it has dispatched, and releases all CPU and memory resources occupied by the process group.

Restart Script Process

Restart Script (os.restart)

Declaration

success, failure_reason = os.restart([ script_name ])

Parameters and Return Values

  • script_name
    • string, optional, a valid script name. Defaults to ""
  • success
    • boolean, operation can only fail if a script name is provided; if successful, this function does not return
  • failure_reason string

Description

  • Terminates the current script process and schedules a reload of the current script file after 2 seconds.
  • If a script file is provided, it reloads the script file at the specified path.
  • If the operation fails, this function returns false along with the failure reason. Common reasons include the provided script file not existing.
caution
  • Current script refers to the entry script at startup.
  • If the current script is modified, os.restart will re-read and run the updated script file from the file system.
  • Do not use this function in a multithreaded environment. Short-delay restarts may cause other logical issues that you need to handle.

Example 1

os.restart
os.restart()  -- Restart to the "current script file"

Example 2

os.restart.path
os.restart("main.lua")  -- Restart to "/var/mobile/Media/1ferver/lua/scripts/main.lua"

Dispatch New Process

Execute Bash Command (os.run)

Declaration

success, reason, exit_code_or_signal, stdout, stderr = os.run(command[, timeout_seconds])

Parameters and Return Values

  • command string
  • timeout_seconds integer, optional
  • success boolean
    • Returns true if successful
    • Returns nil instead of false if failed
  • reason enum
    • exit: Command completed normally; the next number is the exit code
    • signal: Command was interrupted by a signal; the next number is the signal value
  • exit_code_or_signal integer
  • stdout string
  • stderr string

Description

This function is similar to os.execute but adds the following features:

  • Supports stdout and stderr stream redirection
    • Captures the output of the command as return values
  • Supports an optional timeout_seconds parameter:
    1. 1 second before timeout: Sends a SIGTERM signal to the system interpreter
    2. On timeout: Sends a SIGKILL signal to the system interpreter
    3. Forcefully closes stdout and stderr streams
    4. Returns the data already retrieved from the streams
tip

Refer to Command Line Tools to execute another Lua interpreter and set a timeout.

caution

Avoid passing multi-line or overly complex commands; troubleshooting issues can be very difficult.
Write complex Bash/Lua script content to a file first, then execute the file.

Example 1: Command Execution

os.run
os.execute("echo -n aaa")       --> true "exit" 0
--
-- Compared to os.execute, os.run returns the output of the command
os.run("echo -n aaa") --> true "exit" 0 "aaa" ""
os.run("sleep 5; echo -n aaa") --> true "exit" 0 "aaa" ""

Example 2: Command Execution Timeout (Normal Termination)

os.run.timeout
--
-- The first command times out before completion
-- Sends SIGTERM signal 15 to terminate the system interpreter and its subprocesses
os.run("sleep 5; echo -n aaa", 3) --> nil "signal" 15 "" ""
--
-- The second command times out before completion
-- Sends SIGTERM signal 15 to terminate the system interpreter and its subprocesses
-- Returns the partial output retrieved from the stream before termination
os.run("echo -n bbb; sleep 5; echo -n aaa", 3) --> nil "signal" 15 "bbb" ""
--
-- Command completes without timeout, returns the full output from the stream
os.run("echo -n bbb; sleep 5; echo -n aaa", 3) --> true "exit" 0 "bbbaaa" ""

Example 3: Command Execution Timeout (Unable to Terminate Normally)

trap.sh
#!/bin/bash
trap "" SIGTERM
exec "$@"
os.run.kill
--
-- At the end of the 2nd second, sends SIGTERM signal 15 to the system interpreter, but the signal is ignored
-- At the end of the 3rd second, sends SIGKILL signal 9 to the system interpreter, forcibly killing the process
os.run("trap.sh sleep 5", 3)
nil "signal" 9 "" ""

Example 4: Execute Another Lua Interpreter (Nesting)

os.run.lua
os.run("lua -e \"sys.alert(1)\"", 3)

Script Termination Callback

This is not a function but a method that utilizes Lua’s garbage collection mechanism to execute some code when the script ends (or is terminated).

Simple Example

-- Keywords: Script Termination Callback, Script End Callback
any_variable_name = {}
setmetatable(any_variable_name, {
__gc = function(...)
sys.toast('Terminated!')
sys.msleep(500)
end
})
--
while true do
sys.toast("You can try manually terminating the script now\n\n"..os.date("%Y-%m-%d %H:%M:%S"))
sys.msleep(1000)
end
note

Define a global object (table value) and set its destructor to a function. When the Lua virtual machine ends, the destructor of all Lua objects (including the one you defined) will be called. In Lua, a destructor refers to the object’s __gc metamethod.

Complete Encapsulation Example

atexit.lua
function atexit(callback)  -- The parameter is a function. Use atexit(a_function) to register a function to execute when the script ends. Avoid long execution times.
____atexit_guard____ = ____atexit_guard____ or {}
if type(____atexit_guard____) == 'table' then
if not getmetatable(____atexit_guard____) then
setmetatable(____atexit_guard____, {
__gc = function(self)
if type(self.callback) == 'function' then
pcall(self.callback)
end
end
})
end
____atexit_guard____.callback = callback
else
error('Do not name your variable `____atexit_guard____`.')
end
end
-- The above code can be copied to the beginning of your script. Below is an example of usage.
--
-- Use atexit to register a termination callback function
atexit(function()
sys.toast('Terminated!')
sys.msleep(500)
end)
--
while true do
sys.toast("You can try manually terminating the script now\n\n"..os.date("%Y-%m-%d %H:%M:%S"))
sys.msleep(1000)
end

Other Functions

Send Global Notification (notify_post)

Declaration

notify_post(notification_name)

Parameters and Return Values

  • notification_name string
    • ch.xxtou.notification.remote-access.on: Enable Remote Access
    • ch.xxtou.notification.remote-access.off: Disable Remote Access
    • ch.xxtou.notification.restart: Immediately terminate the script and restart the XXTouch Elite daemon
    • ch.xxtou.notification.boom: Immediately terminate the script and uninstall XXTouch Elite

Description

Sends a top-level global notification to the Darwin operating system, equivalent to the native notify_post function.

Lock Process ID File (lockfile)

Declaration

success = lockfile(file_path)

Parameters and Return Values

  • file_path string
  • success boolean

Description

Creates or locks the file path and writes the script process’s process ID as text. This is equivalent to a pidfile, preventing multiple singleton scripts from running simultaneously.

Example

lockfile
if not lockfile("/tmp/daemon.lua.singleton") then
return -- If the file is already locked by another process, it indicates no need to run again.
end