Event system

Phoenix’s event system is a bit different from CraftOS’s events. Like CraftOS, events are stored in a queue that are pushed to each process when they yield. However, event parameters are now stored in a key-value table instead of unpacked as multiple return values. This makes it easier for developers to quickly grab the parameters they need, and makes code more readable. An event is only sent through two values: the type of the event (a string), and a table with the parameters. For example, a timer event might return "timer", {id = 0}.

Since threads may yield for reasons other than waiting for events (syscalls, preemption), events are only passed when the thread yields with event as the first parameter. Each process has its own event queue, and all threads in a process share the event queue. Any thread may wait for an event, and multiple threads may wait at the same time. If multiple threads are waiting for an event, each thread will get the same event when one is passed.

There are a few different types of events that Phoenix may send.

CraftOS events

These events are converted from system events that the computer sends and filtered to the right process(es). They hold the same data that the ComputerCraft events do (potentially with additional metadata added), with names for each parameter.

Here’s the mappings for each event that’s directly exposed to the user. Each parameter column lists the new name of the parameter that is in that position in CraftOS. If an event has a variable number of parameters, the last parameter is a table with the rest of the parameters.

Event type Parameter 1 Parameter 2 Parameter 3 Parameter 4 Parameter 5 Additional parameters
alarm id          
char character          
computer_command args          
disk (call hardware.listen first) device          
disk_eject (call hardware.listen first) device          
http_failure => handle_status_change id        
  • status: The new status of the handle
http_success => handle_status_change id        
  • status: The new status of the handle
key keycode isRepeat      
  • ctrlHeld: Whether Control is held
  • altHeld: Whether Alt is held
  • shiftHeld: Whether Shift is held
key_up keycode        
  • ctrlHeld: Whether Control is held
  • altHeld: Whether Alt is held
  • shiftHeld: Whether Shift is held
modem_message (call hardware.listen first) device channel replyChannel message distance  
monitor_resize (call hardware.listen first) device          
mouse_click button x y    
  • buttonMask: Bitmask of all buttons currently down
  • device: If sent on a monitor, the device it was sent on
mouse_drag button x y    
  • buttonMask: Bitmask of all buttons currently down
  • device: If sent on a monitor, the device it was sent on
mouse_up button x y    
  • buttonMask: Bitmask of all buttons currently down
  • device: If sent on a monitor, the device it was sent on
mouse_scroll direction x y    
  • device: If sent on a monitor, the device it was sent on
paste text          
peripheral => device_added (call hardware.listen first) device          
peripheral_detach => device_removed (call hardware.listen first) device          
redstone            
rednet_message => handle_data_ready id          
speaker_audio_empty device          
task_complete id success results      
term_resize            
timer id          
turtle_inventory            
websocket_closed => handle_status_changed id        
  • status: The new status of the handle
websocket_failure => handle_status_changed id        
  • status: The new status of the handle
websocket_success => handle_status_changed id        
  • status: The new status of the handle
websocket_message => handle_data_ready id          

Some events aren’t directly exposed in Phoenix:

  • http_check: The checkurl syscall only allows synchronous checking, so http_check is automatically consumed while running and not sent to the program.
  • terminate: terminate events are converted to SIGINT signals, and are not sent as events.

Events related to networking (http_*, websocket_*, rednet_message) are converted to new handle_status_changed and handle_data_ready events for use with the networking system. These only send the ID of handles that changed, and the status if changed - use the handle itself to extract any additional data required. Events related to devices are only sent to processes which call the devlisten syscall (hardware.listen when using libsystem), and the device field replaces the side, pointing to the path or UUID of the device the event applies to.

Key event keycodes

Unlike CraftOS, Phoenix exposes a keycode set that is public and consistent, and using hard-coded constants is not discouraged (though it is recommended to use libsystem’s keys library for ease of use & reading). Keycodes are automatically converted from CraftOS codes to Phoenix codes in the kernel - it is not necessary to attempt to load the CraftOS keys API from your program, and in fact those codes will not work at all.

Phoenix’s keycode set uses lowercase (if applicable) ASCII codes for keys with a printable representation, and unprintable keys are organized in groups in the upper byte range. The complete keycode set is listed below, assuming US QWERTY layout.

Complete keycode table
CodeKey namekeys name
0x08Backspacekeys.backspace
0x09Tabkeys.tab
0x0AEnter/returnkeys.enter
0x1BEscape (reserved)none
0x20Space Barkeys.space
0x27Apostrophe/quotekeys.apostrophe
0x2CComma/left angle bracketkeys.comma
0x2DMinus/underscorekeys.minus
0x2EPeriod/right angle bracketkeys.period
0x2FSlash/question markkeys.slash
0x30Zero/right parenthesiskeys.zero
0x31One/exclamation markkeys.one
0x32Two/at symbolkeys.two
0x33Three/hashkeys.three
0x34Four/dollar signkeys.four
0x35Five/percent signkeys.five
0x36Six/caretkeys.six
0x37Seven/ampersandkeys.seven
0x38Eight/asteriskkeys.eight
0x39Nine/left parenthesiskeys.nine
0x3BSemicolon/colonkeys.semicolon
0x3DEquals/pluskeys.equals
0x5BLeft bracket/left curly bracekeys.leftBracket
0x5CBackslash/pipekeys.backslash
0x5DRight bracket/right curly bracekeys.rightBracket
0x60Backtick (grave)/tildekeys.grave
0x61Akeys.a
0x62Bkeys.b
0x63Ckeys.c
0x64Dkeys.d
0x65Ekeys.e
0x66Fkeys.f
0x67Gkeys.g
0x68Hkeys.h
0x69Ikeys.i
0x6AJkeys.j
0x6BKkeys.k
0x6CLkeys.l
0x6DMkeys.m
0x6ENkeys.n
0x6FOkeys.o
0x70Pkeys.p
0x71Qkeys.q
0x72Rkeys.r
0x73Skeys.s
0x74Tkeys.t
0x75Ukeys.u
0x76Vkeys.v
0x77Wkeys.w
0x78Xkeys.x
0x79Ykeys.y
0x7AZkeys.z
0x7FDeletekeys.delete
0x80Insertkeys.insert
0x81F1keys.f1
0x82F2keys.f2
0x83F3keys.f3
0x84F4keys.f4
0x85F5keys.f5
0x86F6keys.f6
0x87F7keys.f7
0x88F8keys.f8
0x89F9keys.f9
0x8AF10keys.f10
0x8BF11keys.f11
0x8CF12keys.f12
0x8DF13keys.f13
0x8EF14keys.f14
0x8FF15keys.f15
0x90F16keys.f16
0x91F17keys.f17
0x92F18keys.f18
0x93F19keys.f19
0x94F20keys.f20
0x95F21keys.f21
0x96F22keys.f22
0x97F23keys.f23
0x98F24keys.f24
0x99F25keys.f25
0x9AConvert (Japanese)keys.convert
0x9BNo Convert (Japanese)keys.noconvert
0x9CKana (Japanese)keys.kana
0x9DKanji (Japanese)keys.kanji
0x9EYenkeys.yen
0x9FNum Pad Decimalkeys.numPadDecimal
0xA0Num Pad 0keys.numPad0
0xA1Num Pad 1keys.numPad1
0xA2Num Pad 2keys.numPad2
0xA3Num Pad 3keys.numPad3
0xA4Num Pad 4keys.numPad4
0xA5Num Pad 5keys.numPad5
0xA6Num Pad 6keys.numPad6
0xA7Num Pad 7keys.numPad7
0xA8Num Pad 8keys.numPad8
0xA9Num Pad 9keys.numPad9
0xAANum Pad Addkeys.numPadAdd
0xABNum Pad Subtractkeys.numPadSubtract
0xACNum Pad Multiplykeys.numPadMultiply
0xADNum Pad Dividekeys.numPadDivide
0xAENum Pad Equalskeys.numPadEquals
0xAFNum Pad Enterkeys.numPadEnter
0xB0Left Controlkeys.leftCtrl
0xB1Right Controlkeys.rightCtrl
0xB2Left Alt (Option)keys.leftAlt
0xB3Right Alt (Option)keys.rightAlt
0xB4Left Shiftkeys.leftShift
0xB5Right Shiftkeys.rightShift
0xB6Left Super (Windows/Command)keys.leftSuper
0xB7Right Super (Windows/Command)keys.rightSuper
0xB8Caps Lockkeys.capsLock
0xB9Num Lockkeys.numLock
0xBAScroll Lockkeys.scrollLock
0xBBPrint Screenkeys.printScreen
0xBCPausekeys.pause
0xBDMenukeys.menu
0xBEStopkeys.stop
0xBFAxkeys.ax
0xC0Upkeys.up
0xC1Downkeys.down
0xC2Leftkeys.left
0xC3Rightkeys.right
0xC4Page Upkeys.pageUp
0xC5Page Downkeys.pageDown
0xC6Homekeys.home
0xC7Endkeys.end
0xC8Circumflexkeys.circumflex
0xC9Atkeys.at
0xCAColonkeys.colon
0xCBUnderscorekeys.underscore

Phoenix events

These events are generated by various parts of the kernel, and are not directly associated with any underlying CraftOS event. They are sent through coroutine.yield() like any other event. This list also includes events that can be triggered by both CraftOS events and Phoenix routines.

Event type Description Parameters
device_added Sent when a device is added as a child of a device with events enabled.
  • device: The path of the device that was added
device_removed Sent when a device’s child is removed.
  • device: The path of the device that was removed
fsevent Sent when a process calls fsevent on a path, and that path is modified.
  • path: The path that was modified
  • event: The type of modification that was done, which is one of the options listed below
  • name: If the path refers to a directory and the modification was done on an entry inside the directory, the file name that was modified
  • process: The ID of the process that triggered the event
handle_data_ready Sent when a connected network handle receives more data.
  • id: The ID of the handle that has more data
handle_status_change Sent when the status of a network handle changes.
  • id: The ID of the handle that changed status
  • status: The new status of the handle
  • error: If the status is error, the error message associated with the status
network_event Sent when a control network message is received after a netevent call. A copy of the control message
network_request Sent when a listening PSP socket receives a new connection.
  • uri: The URI passed to the listen call that received the connection
  • ip: The IP of the remote client
  • handle: The handle for the connection
process_complete Sent when a child process exits.
  • id: The ID of the process that exited
  • thread: The ID of the last thread that exited
  • value: If the last thread exited successfully, the value that the thread returned
  • n: The number of return values from the last thread
  • error: If the last thread errored, the error that it threw
  • traceback: A traceback if the thread errored
  • Additional return values are in integer keys.
remote_event Sent when another process posts a remote event, explained below. See below
syslog Sent when a message is posted to an opened log. A copy of the options table passed to the corresponding syslog call
syslog_close Sent when an opened log is removed from the system.
  • id: The ID of the log that was closed
tty_event Sent when a TTY created with mktty has its contents updated.
  • id: The ID of the TTY that was modified

Filesystem event types

| Event | File? | Dir? | Description | |———————|——-|——-|————-| | open | x | | Triggered when the target file is opened in write or append mode. | | open_child | | x | Triggered when the target directory has a file opened in write or append mode. | | remove | x | x | Triggered when the target file or directory is removed. | | remove_child | | x | Triggered when the target directory has a child removed. | | rename_from | x | x | Triggered when the target file or directory is being renamed. | | rename_from_child | | x | Triggered when the target directory has a child renamed. | | rename_to | | | Triggered when the target path has been replaced with a renamed file or directory. | | rename_to_child | | x | Triggered when the target directory has a new child from a rename. | | mkdir | | | Triggered when the target path now exists and is a directory. | | mkdir_child | | x | Triggered when the target directory has a new child directory. | | link | | | Triggered when the target path now exists and is a link. | | link_child | | x | Triggered when the target directory has a new child link. | | mkfifo | | | Triggered when the target path now exists and is a FIFO. | | mkfifo_child | | x | Triggered when the target directory has a new child FIFO. |

Signals

Signals are the most basic type of IPC in Phoenix. They do not have any metadata associated with them, and are only used to send a trigger to a process that will be executed immediately. The event type is "signal", and the parameters contains a single field called signal with the signal sent. A signal is sent to a process through the kill syscall, taking the PID of the target process and the signal to send. A signal may be any number, but the system only uses the signals listed below. Signals may only be sent to processes running as the same user as the sender, unless the sender is running as root.

For most signals, they are simply sent as events to the process. However, processes can also have a function called whenever a signal is sent to the process. This will cause the signal to not be added to the event queue. Many of the built-in signals have handlers attached by default - notably, the ones that kill the process. Processes can replace or remove these handlers (or handlers for other signals) through the signal syscall.

In the case of SIGABRT, an additional parameter is added to the signal: error. This parameter is passed when an uncaught error occurs, and is also passed to the handler function if one is installed. This allows the process to add a global error handler to the process that can transform the error message as needed. By default, this simply calls debug.traceback on the message and prints it to the system log, as well as sending the message to standard error.

ID POSIX name libsystem name Built-in triggers Default action
1 SIGHUP hangup Terminal disconnected Terminate
2 SIGINT interrupt ^C is pressed Terminate
3 SIGQUIT quit ^\ is pressed Terminate w/traceback
6 SIGABRT abort Uncaught error occurs Terminate w/traceback
9 SIGKILL kill   Kill (cannot be overridden)
10 SIGUSR1 user1   Ignore
12 SIGUSR2 user2   Ignore
13 SIGPIPE pipe Pipe breaks Terminate
15 SIGTERM terminate   Terminate
18 SIGCONT continue Process continued Ignore
19 SIGSTOP stop ^Z is pressed Stop
21 SIGTTIN bg_input Input from background Stop
22 SIGTTOU bg_output Output from background Stop

Remote events

Remote events are the primary method of IPC in Phoenix. A remote event is sent with the type "remote_event", and can be sent from any process to any process. A remote event may contain any data as the payload, as well as an independent type. The parameter table contains the following fields:

  • sender: The PID of the process that sent the event.
  • type: The type of event as reported by the sender.
  • data: The parameter sent to the process.