Wednesday, November 04, 2009

lab 105 - automount


lab 105 - automount


A small modification to mntgen yields an automounter which automatically mounts a server based on path name. This is a fairly crude proof of concept with hardwired port numbers and top-level mount path -- but it would be fairly easy to make it a bit more robust. Essentially, I just added a mount command to the code which dynamically adds the directory node to the mntgen tree on reference. Then I made the file system handling call its own thread so that the mount could reference the synthetic without locking up the original single threaded synthetic file server. One problem is that unknown servers take some time to respond with file note found, which is less than desirable. Fixing this and other annoyances is left as an exercise for the reader.


% ls /amnt
% mount {automnt} /amnt
% ls /amnt
% ls /amnt/localhost/usr/inferno



Thursday, August 06, 2009

lab 104 - ducts: bi-directional mount channels


lab 104 - ducts: bi-directional mount channels


Hi there, I want to talk to you about ducts. Are your ducts old fashion, out of date?

In this lab, I'll walk through a little facility I built to allow me to have bi-directional mounts over a single file descriptor channel. The nature of the way I access my Blue Gene environment requires me to do an awful lot over a single communications channel. I wanted the ability to both access the target node's file system while simultaneously exporting mine, while only using a single file descriptor.

To facilitate this, I wrote a little 9P-knowledgeable multiplexor which directs T-msgs to an export thread and R-msgs to a mount thread while multiplexing the responses from those threads back onto the same file descriptor.

The initial implementation of the base mechanism was relatively simple until I had to start considering how to clean things up when I started unmounting directories on one side or both. The liberal use of sys->pipe throughout the code meant it was somewhat difficult to detect when things were finished. I ended up adding a signaling packet to the protocol to notify the remote Duct when I had closed my mount, and then implemented a channel based monitor infrastructure so I could track what was still running and appropriately shut down the various pieces as things unmounted (it is possible to unmount one side without unmounting the other).

The interface is fairly simple, if using the module interface you spawn an uplink, specifying an input file descriptor and an output file descriptor for the connection (which may be the same FD), the path you wish to export and the mount point for where you want to place the imported file hierarchy.

If you are running it from the command line, it uses stdin and stdout for the input and output FDs and you only need specify the export path and mount point.


host1% listen -A tcp!*!1127 duct /usr/ericvh /n/foo

host2% dial -A tcp!host1!1127 duct /usr/inferno /n/bar


  • 104/duct.m
  • 104/duct.b

Sunday, June 28, 2009

lab 103 - python content assist


lab 103 - python content assist


Building on lab 102 I've started to write an acme client for python content-assist in python. I read the code for python's IDLE editor and pulled some pieces out of that to help with my implementation. The and modules are copied out of idlelib and reduced to just the functions I needed.

Just as in lab 102 the acme client is implemented using pyxp to connect to the acme file system.

In an acme editor window execute PyAssist. Start typing some python. After typing a dot the client will display available attributes for the module. Continue typing and it will reduce the list to those names with a matching prefix. Press the Tab key to complete a name or prefix depending on whether there is one or more names.


After typing an open parenthesis the client will show the call tip for the function.


The client implements an Import command so that more python modules can be added to the namespace. PyAssist doesn't attempt to parse the edited script. Idlelib includes code that could help to do this. But for now you need to pass a module name as argument to the Import command.

A next step for python integration to acme is to implement a debugger. Python comes with libraries for this too, so a debugger similar to the acme debugger adeb should be a future lab. I might then run edited scripts in a sub shell and inspect that process' namespace similar to the IDLE implementation, so that content-assist adapts to the script being edited.



Tuesday, June 23, 2009

lab 102 - python acme client


lab 102 - python acme client


A recent post to 9phackers announced Pyxp, another implementation of Styx in Python.

I immediately downloaded Pyxp and tried it out. I had no trouble using it so I started thinking about python clients I could write. Python is still new to me so writing a styx client was an excuse to get more practice.

I started with an acme client. I translated the acmewin limbo module I use for most acme-sac clients to python. Below is a simple example opening a new acme window and doing some operations on it.

from acmewin import Acmewin

win = Acmewin()
win.writebody("hello, world!\n\n\n")
win.replace("/goodbye/", "GOODBYE")",")

Remember to export the namespace before trying it out.

% styxlisten -A 'tcp!*!localhost' export /

I recently saw on Hacker News a repost of Peter Norvig's spelling corrector. I thought this would make an easy first trial of my python acmewin code. I implemented a client to offer spelling suggestions to an editor window. It works somewhat like my earlier acme content assist code. This client opens the event file of another window it is assisting and writes text out to its own window. In this case it offers a suggested spelling for the word currently being typed.


Here's the implementation. Note that this is single threaded and it is not reading the event file of the second window. I haven't gotten that far in the Python book.


import sys
from acmewin import Acmewin
import spell

win = Acmewin(int(sys.argv[1]))
outwin = Acmewin()

while True:
    (c1, c2, q0, q2, flag, nr, r) = win.getevent()
    if c2 in "xX":
        if flag & 2:
        if flag & 8:
        win.writeevent(c1, c2, q0, q2)
        if c2 == "x" and r == "Del":
    if c1 == "K" and c2 == "I":
        ch = r[0]
        if ch in " \t\r\n":
            outwin.replace(",", "")
        while q0 >= 0 and not (ch in " \t\r\n"):
            sss =, q0+1)
            if not sss:
                # print("empty sss %d" % q0)
                sss = " "
            ch = sss[0]
            q0 -= 1
        if q0 < 0 and not(ch in " \t\r\n"):
            q0 = 0
            q0 += 2
        ss =,q2)
        lastcorrect = spell.correct(ss)
        outwin.replace(",", lastcorrect)

To run this we need to know the id of the window we are assisting, so we need a wrapper to send the $acmewin environment variable as an arg to the script. For that I have a script called SpellAssist.

$home/python/ $acmewin

Now that I have a simple assist-like client working I'd like to develop it further. I'd like to try having content assist for python inside acme. It should be possible to adapt the python code that implements the IDLE editor to this purpose.


big.txt the large text file used to train the spelling corrector. Note that the path is hardcoded in and should be changed locally.

Monday, June 15, 2009

lab 101 - limbo B+ tree


lab 101 - limbo B+ tree


This lab is an implementation of a B+ tree. It is code from a much older lab that was overly complicated and buggy. I pulled the B+ tree code out, tried to fix the bugs and clean it up. The interface is roughly the same as dbm(2). Here is a synopsis.

include "btree.m";
btreem := load Btreem Btreem->PATH;
Datum, Btree: import Btreem;

Btree: adt {
 create: fn(file: string, perm: int): ref Btree;
 open: fn(file: string, flags: int): ref Btree;
 fetch: fn(b: self ref Btree, key: Datum): Datum;
 delete: fn(b: self ref Btree, key: Datum): int;
 store: fn(b: self ref Btree, key: Datum, val: Datum):int;

 firstkey: fn(b: self ref Btree): Datum;
 nextkey: fn(b: self ref Btree, key: Datum): Datum;

 flush: fn(b: self ref Btree);
 close: fn(b: self ref Btree);

init: fn();

Like Dbm the keys and values are stored as arrays of bytes, and being a B+tree the values are stored only in the leaf nodes. The maximum key and val size is 255 each. The block size is 8192, so the maximum leaf node size is 515 making the minimum branching factor 15. The maximum number of records in an internal nodes assuming an int as key is 630.

The delete is not fully implemented; it doesn't merge nodes.

Here is some example code listing the full contents of a btree.

sys := load Sys Sys->PATH;
btreem := load Btreem Btreem->PATH;
Datum, Btree: import btreem;

bt :="", Sys->ORDWR);
for(key := bt.firstkey(); key != nil; key = bt.nextkey(key)){
 v := bt.fetch(key);
 sys->print("%s %s\n", string key, string v);

Here is a rough comparison of btree vs. dbm. This simple test is more of a sanity check that the btree doesn't do anything horribly wrong in its implementation (which it did originally, by making a syscall to get the daytime for every block it tried to get).

% awk '{print $1, NR}' < /lib/words | tr -d 'cr' > t1

% >
% >dbm.pag
% >dbm.dir

% time sh -c 'btree/store < t1' 
0l 4.172r 4.172t

% time sh -c 'dbm/store dbm < t1'
0l 35.25r 35.25t

% ls -l dbm.*
--rw-rw---- M 6 xcs0998 XCS0998    8192 Jun 04 12:38 dbm.dir
--rw-rw---- M 6 xcs0998 XCS0998 1048576 Jun 04 12:38 dbm.pag
--rw-rw---- M 6 xcs0998 XCS0998 770048 Jun 04 12:36

% time sh -c 'btree/list > /dev/null'
0l 5.187r 5.187t

% time sh -c 'dbm/list dbm > /dev/null'
0l 9.438r 9.438t



Sunday, June 07, 2009

lab 100 - limbo tags


lab 100 - limbo tags


I've been playing more with exuberant ctags. It's possible to make ctags recognize limbo source code using regular expressions to identify symbols we want tagged.

Here's a command I defined called ltags. It will search for functions, assuming the function name is not preceded by spaces, and, more reliably, find adt and module definitions:

os -t ( /n/D/ctags57/ctags.exe  -n 
 '--regex-limbo=/([a-zA-Z][a-zA-Z0-9]+) *: *adt */\1/t/'  
 '--regex-limbo=/([a-zA-Z][a-zA-Z0-9]+) *: *module */\1/c/'  
 $* ) 

Try running it under /, and use relative path names:

% cd /
% ltags -R appl module

And open the acme client

Ctag /tags


I added a command "Tag" to the Ctag program that will find and print all matching symbols to the name given as argument. Mouse-chording makes this nice to use. Right-clicking on symbol names will open the source file at that location. Browsing the whole limbo source hierarchy is then made quite easy.



Saturday, May 30, 2009

lab 99 - catching up with inferno-os


lab 99 - catching up with inferno-os


I had fallen way behind in keeping acme-sac code up to date with inferno-os. I tried to correct that this week by merging changes and adding files from inferno-os.

I wrote a script, part of this labs files, to check the differences between inferno-os and acme-sac. I'm hoping by using this script I'll stay up to date with inferno-os as changes are made. The script compares sub-trees, such as the limbo source code hierarchy, the C source code, the manual pages, and the /lib directory. It prints out commands to diff the files or copy the file over.

% inf
inferno synchronization:
  appl    show changed limbo files
  sys     show changed C source files
  man     show changed man pages
  lib     show changed /lib files
  cmd     show changed sh scripts below /dis
  update  refresh file tree info for local and remote
  adiff   adiff selected file with inferno-os equivalent
  diff    diff selected file with inferno-os equivalent
  missing show files missing from local tree
  added   show files added to local tree
% inf update
% inf sys
diff -u /sys/emu/port/win-x11a.c /n/D/inferno-os/emu/port/win-x11a.c
cp /n/D/inferno-os/emu/port/win-x11a.c /sys/emu/port/win-x11a.c


There is a short list of directories I did not synchronize because I know every file has changed; I consider these a fork, though the changes to charon are not dramatic,

/appl/acme/  /appl/charon/  /acme/

There is a list of directories acme-sac has removed from the inferno-os hierarchy:

/FreeBSD/  /libbio/     /utils/
/Hp/       /libdynld/   /appl/alphabet/
/Inferno/  /libkern/    /appl/collab/
/Irix/     /liblogfs/   /appl/demo/
/NetBSD/   /libnandfs/  /appl/ebook/
/OpenBSD/  /libprefab/  /appl/spree/
/Plan9/    /libtk/      /appl/tiny/
/asm/      /tools/      /appl/wm/

And finally there is a sub-tree we need to actually synchronize:

Linux    appl/grid lib       libkeyring  libmp   module
Nt       appl/lib  lib9      libmath     libsec
appl     appl/math libdraw   libmemdraw  include
appl/cmd emu       libinterp libmemlayer man

After comparing these sub-trees I built a list of files that were intentionally removed and files locally changed. Any file found "missing", where inferno-os added new functionality, was copied over. Files that were not marked as locally changed but nevertheless contained changes were merged, usually overwritten with the latest from inferno-os. There is also a list of files added to acme-sac apart from anything below /acme.

I found it useful to use the side-by-side diff functionality from lab 95. I added some simple interactive merge functionality that worked if you start from the end of the file and stepped backwards through the diffs using a PrevDiff command on the adiff output and calling the command Merge to apply the currently highlighted change. The implementation of this Merge command was pretty simple because it involved just copying the selected text from the source file over to the target. Given acme's filesystem interface this is literally a file copy,

cp /mnt/acme/$b/rdsel /mnt/acme/$a/wrsel

The PrevDiff commands does the work of setting up the selected texts correctly, properly handling the case of added, changed, or deleted text.

The list of files in the changed list should be reduced. Some of these are changes that could be pushed to inferno-os. E.g., diff adds the -u flag, os has changes from rog implementing host file name translation. Some files will need to be continually merged, such as the man page indices.

The list of files and directories removed are mostly just functionality either specific to running inferno as a native os, or the Tk functionality. There shouldn't be anything there people would really miss in an acme-sac environment. Though if there is let me know.



Monday, May 18, 2009

lab 98 - acme Ctag


lab 98 - acme Ctag


Ctag is a new client for acme that reads the tags file generated by ctags. In particular I worked with Exuberant Ctags on windows. While working on acme content-assist in lab 94 I thought a next possible step was using ctags for code completion. So in writing this program I wanted to explore using exuberant ctags by doing something easier, that is by providing assistance with code navigation.

Exuberant ctags understands many languages, but for the current effort I tried it on Java and Python.

For example, I generated tags for the python standard libraries,

ctags -R --excmd=number --exclude=test

Then run the client on the tags file,

Ctag /n/D/Python30/tags

What you start with is a blank window. In the tagline is a File command. Give it an argument of a filename which it will grep for in the ctags file.

File mailbox


It will then show all classes and methods within matching files. You can right-click on a method name to open the file at the line where the method is defined.

Ctag gives a top down view of a project. It is like the Outline view of some IDEs. A next step would be to implement the reverse direction, but probably as part of the content assist.



lab 97 - acme Navigator


lab 97 - acme Navigator


I created a simple directory browser for acme. Called Navigator, it opens directories in the same window. This makes descending deep but unfamiliar directory hierarchies easier because it avoids the proliferation of windows that clutter the desktop.


The client understands the command Pin for creating a standard acme directory window for the current directory (to pin the current directory to the desktop). This is an example for a rather simple client for acme.



Sunday, May 17, 2009

lab 96 - acme color schemes


lab 96 - acme color schemes


The inferno version of acme always contained some code to configure the acme color scheme, but I'm not sure if it always, if ever worked.

I modified the code a little in acme-sac to make the color configuration work. And I came up with a few new schemes.

The schemes are checked into acme-sac under /acme/color. To use a different scheme add a line like this to your $home/lib/profile

run /acme/color/evening

Running the "evening" scheme will make acme look like this.


The configuration files sets a few environment variables of the following form:


This sets the foreground text color in the body text to black. It's possible to mix two colors, as for the standard acme background.


Another simple scheme is "bw" for black and white.


There is also a file /acme/color/standard for the default acme color scheme which can be copied tweaked.

Saturday, May 16, 2009

lab 95 - acme side-by-side diff


lab 95 - acme side-by-side diff


Here's a script I wrote to help do side-by-side diffs in Acme. Run adiff as normal inside acme. And then in the adiff output window type the command NextDiff. Executing this command will step through each diff in the adiff output and highlight the changed region in each file.


The script will highlight each line, avoiding the cursor jump to highlighted regions as happens by plumbing or right-clicking on a file pattern. Though the cursor jump will occur the first time the diffed files are opened, for subsequent execution of NextDiff for diffs within the same files the cursor will remain over the NextDiff command and the highlighted regions will change with file scrolling to show at least part of the changed regions.

When the files first open you'll still need to manually arrange the files side by side. There is no acme API for window placement. However, the command will save some amount of scrolling, clicking, and mouse movement within the adiff output.

Here's the script for acme-sac. Some slight changes might need to be made for inferno, and something very similar should work in p9p acme.


fn findwin {
 file = $1
 < /mnt/acme/index getlines {
  (w x y z zz f rest) := ${split ' ' $line }
  if {~ $f $file} {echo $w}

fn highlight {
 file = $1
 lineno = $2
 a := `{findwin $file}
 if {! ~ $#a 0} {
  cd /mnt/acme/$a
  <> addr {
   echo -n $lineno > addr
   echo 'dot=addr' > ctl
   echo show > ctl 
  plumb $file:$lineno

cwd = `pwd
cd /mnt/acme/$acmewin
 echo -n 'addr=dot' >ctl
 (a b) := `cat 
 echo -n '/^[^\-<>].*\n/' > addr
 echo -n 'dot=addr' > ctl
 echo -n show > ctl
 (f1 cmd f2) := `{getline data}
 (f1 l1) = ${split ':' $f1}
 (f2 l2) = ${split ':' $f2}
 f1 = `{cleanname -d $cwd $f1}
 f2 = `{cleanname -d $cwd $f2}
 highlight $f1 $l1
 highlight $f2 $l2
} <> addr

The findwin and highlight functions I have used before in the acme debugger interface, adeb, in /appl/acme/acme/debug/adeb.b.

Wednesday, April 08, 2009

lab 94 - acme content assist


lab 94 - acme content assist


This lab explores a way of implementing content assist for acme. I've focused on the user interface and how that might work inside acme and not specific language support.

The command is called Assist. Launch it within an editor window and it will provide assistance for that window only. A new window will open and while you type in the edit window Assist will attempt to match the currently typed word against the content of /lib/words using the command look(1). The results are displayed in the +Assist window.

With results in the +Assist window and with focus still in the editor window type Ctrl-l to step down through the results. Each result will be selected in turn and the selection will wrap around to the top. To choose a selection and replace the currently edited word with the selected text type Ctrl-k.

The Assist command also supports file completions. Start typing a path in the edit window and type Ctrl-y to show file completions in the +Assist window. Use Ctrl-l and Ctrl-k to navigate and select from the results.

Assist assumes /lib/words exists and is the default for finding word completions. You can download a copy of /lib/words from plan9port. You can also run Assist with a filename for your own list of words. It should follow the format expected by look(1).


Some interesting things about the implementation. Acme isn't aware of the control keys. It adds the control character to the document and the Assist plugin reads it and removes it from the document. In this way plugins can define their own special keys as long as acme does not already process them in some special way (see table below).

The Assist plugin does cause the editor window to change its behaviour slightly. Assist has to resend all events so that normal editor commands like Put and Undo are understood. However, because we've opened the event file the normal refresh of the tag line with Undo and Put when the file is dirtied does not happen.

The +Assist window is off to the side, or it could be placed just below the edit window. This is pretty good. But your eye does need to travel to see completion suggestions. Maybe not as ideal as the info popup appearing just below the cursor position. However, this method fits in far better to the acme model.

Special Keys

While working on this I thought I'd map out the control keys already understood by acme. The ASCII control characters are mostly passed through to the document. However, a number are interpreted by acme in a special way. In the table below NA, non-assigned, means they have their standard ASCII assignment.

Ctrl KeyDescription
amove cursor to beginning of line
b NA
c copy
d NA (eof)
e move cursor to end of line
f file completion
g NA
h delete
i tab
j NA (carriage return)
k NA
l NA
m newline
n NA
o NA
p move cursor to beginning of document
q move cursor to end of document
r NA
s NA
t NA
u delete to start of line
v paste
w delete to start of word
x cut
y NA
z undo
[ escape
\ NA
] NA
^ NA
_ NA
? ?

There are also mappings for the Home keys. These mappings are for the acme editor window in the most recent commits to acme-sac (the up/down arrow have been changed compared to other acmes).

Homescroll to beginning of document
Endscroll to end of document
PgUpscroll page up
PgDownscroll page down
Left Arrowmove cursor left one char
Right Arrowmove cursor right one arrow
Up Arrowmove cursor up one line
Down Arrowmove cursor down one line

None of the function keys are interpreted or even passed to the console on windows inferno. The escape key has some special meaning, it selects the last entered text, or cuts the selected text if text is selected. The Alt key is also used for entering unicode keys.



Sunday, March 29, 2009

Google Summer of Code 2009


Google Summer of Code 2009


Plan 9 has been accepted this year as a mentoring organization for Google Summer of Code. The Plan 9 group accepts projects to do with the operating system Plan 9 from Bell Labs and from related technologies such as Inferno, Plan 9 from User Space, v9fs, 9vx, and Glendix.

If you're a student and you like any of these technologies you should apply immediately to the GSoC with your a project proposal. You can take any of the ideas you've seen explored in this blog and build on them, or develop your own ideas and take Plan 9/Inferno into new territory. I would love to see projects that extend Acme-SAC such as with content-assist or syntax highlighting. Or new Inferno applications in particular for the Nintendo DS. Inferno is an "integrating environment" so try integrating Inferno with Eclipse, Python, or Ruby.

The deadline for student project proposals is April 3rd, so you need to be quick. There is so much cool stuff you could be working on this summer; Don't let this opportunity slip away.

Saturday, January 03, 2009

lab 92 - vxinferno


lab 92 - vxinferno


In this lab I create a new Inferno builtin module that calls the vx32 library and get a minimal system working that runs native x86 code, with system calls redirected to inferno's system calls and therefore making the inferno namespace visible to the sandboxed code.

Vx32 is a new user-level sandboxing library by Bryan Ford and Russ Cox. From the vx32 paper,

"Vx32 is a multipurpose user-level sandbox that enables any application to load and safely execute one or more guest plug-ins, confining each guest to a system call API controlled by the host application and to a restricted memory region within the host’s address space."

Inferno, being a virtual operating system, provides its own system call API to limbo applications. The same system calls are available as a C API for use by native libraries that appear as builtin modules or devices within the inferno environment. This C API is a natural fit for building a Vx32 sandbox allowing native code of all kinds to run within inferno, which has considerable flexibility over the namespace made available to the native code. This would allow inferno to be extended in new ways beyond limbo, builtins, or external processes that export styx protocol. It also extends the reach of native code that when run in this hosted environment its use of files take on even greater significance.

Please read the vx32 paper, download the code and play with it. I haven't included the vx32 code in the lab. Instead this lab is more tutorial in creating a new builtin module for inferno. This labs code, linked to in the steps below, is all the code necessary to make vx32 appear as a builtin. I've done enough to show some simple examples working, but I haven't defined the full system call interface.

So here are the steps in creating a new builtin module linkage.

module interface

Create the limbo module interface, e.g. /module/vxrun.m. I created the interface to closely resemble the vxrun application in the vx32 distribution. The module contains one function to load and run a native ELF executable.

Edit /module/runt.m to include new include the new module interface. This file includes all builtin modules and is used later to generate a runtime C struct.

incorporate library code

Copy library and header files into inferno-os tree. I copied vx32.h to /include/vx32.h. I created a new libvx32 folder at the root of the tree and created a dummy mkfile. I didn't copy all the source into the tree, I cheated and just copied libvx32.a to /Linux/386/lib. But the emu build will expect the folder and mkfile to exist. So this is a placeholder for now.

add builtin to libinterp

Implement the builtin linkage /libinterp/vxrun.c This is the bulk of the work, where we call the vx32 API and map the system calls defined in the codelet C library that comes with the vx32 distribution, libvxc, to inferno's API defined in /include/kernel.h.

The template can be generated by /dis/limbo from the vxrun.m interface

% limbo -T Vxrun /module/vxrun.m
#include <lib9.h>
#include <isa.h>
#include <interp.h>
#include "Vxrunmod.h"

 builtinmod("$Vxrun", Vxrunmodtab);

Vxrun_run(void *fp)
 F_Vxrun_run *f = fp;

Which is actually wrong, it should be,

 builtinmod("$Vxrun", Vxrunmodtab, Vxrunmodlen);

The hard work is the filling in the Vxrun_run() function. A lot of this code was taken from vx32/src/vxrun/vxrun.c.

The main work of running the native code and redirecting syscalls is in the following loop,

 for (;;) {
  int rc = vxproc_run(p);
  if (rc < 0){
   *f->ret = -4;
  if (rc == VXTRAP_SYSCALL) {
   if(dosyscall(p, f->ret))

In dosyscall we switch on the syscall number and call the Inferno method, e.g.,

static int 
dosyscall(vxproc *proc, int* fret)
 switch (NUM) {
  fd = ARG1;
  addr = ARG2;
  len = ARG3;
  if (!vxmem_checkperm(proc->mem, addr, len, VXPERM_WRITE, NULL))
   print("bad arguments to read");
  ret = kread(fd, (char*)m->base + addr, len);
... other syscalls
 RET = ret;
 return 1;

To get this to build we need to edit the /libinterp/mkfile. Add vxrun.$O to the list of OFILES, add vxrun.m to the list of MODULES, and add the following rules to ensure the module header, vxrunmod.h, is generated.

vxrunmod.h:D: $MODULES
 rm -f $target && limbo -t Vxrun -I../module ../module/runt.m > $target
vxrun.$O: vxrunmod.h

We can now compile libinterp.

edit emu config

The final step is to edit /emu/Linux/emu configuration file and add the dependencies on the vxrun module and the vx32 library. We can now build a new emu that has the vx32 vxrun as a builtin module.


We need a limbo command to call the module. I included vxinferno.b in the lab code. But it does nothing more than load the module and call it passing in any command line arguments.

init(nil:ref Draw->Context, args:list of string)
 vxrun := load Vxrun Vxrun->PATH;
 vxrun->run(tl args);

I used the vx32-gcc to compile the native code. I included one example, cat.c, that would test the system calls, open, read, write, from the inferno namespace. Note that the name of the executable to call from inside Inferno is the host pathname, because vx32 itself is not using the Inferno system calls. This could be fixed by either changing the elf loader, or by using the library call to load the ELF from memory.

$ cd ~/vx32/src/vxrun
$ vxrungcc cat.c 
$ emu -s -r ~/inferno-os
; vxinferno /home/caerwyn/vx32/src/vxrun/_a.out /dev/drivers
#/ root
#c cons
#e env
#M mnt


This lab confirmed vx32 as a builtin to inferno would work. Now it needs to be implemented in full. I'd most like to see vx32 ported to windows. There is an effort to port vx32 to windows, but it seems to have stalled.

I think this is really cool!