A repurposable application-downloader and -launcher

View the Project on GitHub setlog/trivrost


trivrost uses files as locks for synchronisation between multiple trivrost instances and the processes started by them. In this document we explain this mechanism for developers who have an interest in working on the trivrost source code.

The problem

Desired behaviour

Proposed solutions

Of the following proposals, those written in bold text were implemented.

For (a)

  1. trivrost keeps running after starting the application and watches for its termination. Behaviour with other trivrost instances is communicated via IPC (Inter Process Communication).
    • This can only work for as long as trivrost is not being executed over the network.
    • Go has no feature-complete libraries for this.
  2. We manage a list of process ids in a list and only update bundles when none of the listed processes are running.

For (b)

  1. Synchronize update phase via IPC.
    • Same problems as above.
  2. Create a lock file which contains the process id of trivrost and then only the trivrost instance listed in it may perform bundle updates.

Process signatures

Introducing: the lock file and the process signature files

Execution behavior

A trivrost instance won’t perform any actions on the file system nor launch any other applications unless it owns the .lock, whereafter it will ascertain that its process signature is stored in the .launcher-lock file. At launch, trivrost will attempt to obtain the .lock first. This process can be seen in AcquireLock(), triggered by LauncherMain(). The self-restarting of trivrost through Restart() in the case of LockClaimed is happening because in all cases except LockOwned the trivrost binary may have changed through an update by another trivrost instance, so we restart to guarantee we are on the latest version. In the case of LockClaimed the Restart() function writes the process signature of the restarted trivrost process into .launcher-lock before releasing the .lock and terminating.

The .execution-lock is less complicated, because it is only accessed by the one trivrost instance which already holds the .lock. In executeCommands() the process signature of the started application is added to a list in the .execution-lock file. In Run() we wait for all processes in the .execution-lock file to stop running – using AwaitApplicationsTerminated() – in case we have an update to apply while depending processes are still running.