**This is an old revision of the document!**

Custom Startup Programs

OpenOS provides a variety of tools for running programs automatically. This document describes all of those tools, how to use them, and their comparative advantages and disadvantages. Note that some of these options were not available or as robust an option in older versions of the operating system. The 1.7.2 development builds (across all supported minecraft versions) have full support as documented here. The next general available OC 1.7.3 will include all of the development build fixes.

Before we cover the tools for running programs automatically, this document reviews background vs foreground, blocking calls, threads, and event listeners.

Background vs Foreground Interactive Processes

A foreground interactive program interrupts or delays OpenOS from loading the shell. This type of modal process is a natural fit for programs that need to wait for user input. For developing background processes, OpenOS provides threads and event listeners. When designing a custom startup program, a user is at liberty to choose either background or foreground approach, as may suit their needs.

Blocking Calls

When building a background process you need to know what is a blocking call, and what is blocked when you call it. There are two distinct types of blocking calls: machine blocking and system yielding.

Machine blocking calls are a subset of component api, such as a filesystem file read, which cause the entire OpenComputer machine state to wait. These blocking calls are outside the control of the operating system, are truly blocking, and outside our control. Thus we generally are not referring to machine blocking calls when we discuss whether an operation is blocking or not. During a machine blocking call nothing in the system is running.

In contrast, the system call computer.pullSignal yields the current thread (event.pull and os.sleep also call computer.pullSignal). OpenOS creates a single init thread and runs all processes inside that one thread. If you create multiple coroutines and resume them in a continuous loop, once any single coroutine makes a system yield call – your loop would be blocked on that one coroutine. You would not see it yield back to you. For all intents and purposes, all coroutines in that thread are essentially suspended. When developing a background application this is a critical workflow to understand. If you need your application to sleep for 10s before resuming its work, and you call os.sleep(10), you block execution of the the foreground application (because are in the same thread). System yielding methods include: term.read, os.sleep, and event.pull.

Threads

Review the threading library api documentation here. Threads are ideal for developing a background application whose design, for the most part, can disregard the rest of the system.

OpenOS threads are nonblocking processes

As we discussed previously, making a system yield call (anything that calls computer.pullSignal), will suspend all coroutines in the current thread. However, you have the option to create your own thread. Any other thread that makes a system yield call does not block your thread, and your thread is free to make system yield calls without blocking any other thread. If you want your background process to broadcast a network message once every second, you can easily do so with a short while loop:

snippet.lua
while true do
  modem.broadcast(port, msg)
  os.sleep(1)
end

OpenOS threads are "event cooperative"

Event signals are queued and are removed from that queue when you pull them. If you have multiple and distinct areas of code making pullSignal (or event.pull) calls, one process may rob signals that another process was expecting (event handlers registered via event.listen is not affected by this). Threads pull from their own queue (there is no additional memory cost for this, technically a thread is a registered event handler that is unaffected by signal robbers), and when designing your background application running on an OpenOS thread, you need not concern yourself with the rest of the system and the events it may care about.

OpenOS threads are not suitable for low memory systems

OpenOS needs less than 130k of ram to boot and run the interactive shell. One stick of tier 1 ram provides 196k of ram, thus leaving you with more than 60k of “wiggle” room. This low memory state is already severe as it is. However, the boot process does not fully load the available system libraries. Loading the thread library allocates an additional ~20k, and each user thread costs ~5k. These are conservative measurements and, frankly, imprecise due to the nature of the Lua VM and how it allocates memory in chunks. I will admit, the threading library could be optimized for memory costs. However, the threading library has thus far been strongly focused on correctness and robustness. Future versions will likely have reduced cost. Ideally, your system has >100k free even with all the libraries you need loaded, and all of your programs running.

Event Listeners

Boot Signals

Tools For Automatic Program Execution

Interactive Shell Startup (.shrc)

/etc/profile is “sourced” (as a list of shell commands) each time the shell loads, not just every boot. (e.g. if the user types 'exit' in the shell, the shell would reload but the machine is not rebooting)

/home/.shrc is “sourced” via /etc/profile note that /etc/motd is actually run via /etc/profile

I recommend editing /home/.shrc rather than /etc/profile purely for organizational purposes. Again, these files are “sourced” (as shell commands) and not “lua executed”. I'll keep further detailed walkthroughs to a ocdoc update.

Runscripts (rc)

/bin/rc can be used to enable boot level scripts. Hopefully in the future of openos this feature is given a pretty nice upgrade; today it is basic.

Filesystem Autorun (autorun.lua)

/autorun.lua (and not /home/autorun.lua) can be used for scripts to execute on drives that are automounted by the filesystem. This doesn't apply to the rootfs. This definitely could use more explanation, please note that this definitely is not what you're looking for.

Boot Scripts (/boot/)

You can also create “boot” scripts (these are generally intended for system library initialization). The existing boot scripts are found in /boot, and are numbered to support load order. This system is deprecated (at least in my mind) and I would like to eventually retire this system, fair warning

Contents