• Updated 2023-07-12: Hello, Guest! Welcome back, and be sure to check out this follow-up post about our outage a week or so ago.

A/UX Mac-side hybrid applications: some notes on building them.

cheesestraws

Well-known member
There don't seem to be much information out there on writing applications for A/UX that aren't just ports from other UNIXes. I've now written a couple of Mac applications that use A/UX facilities—and I've done it more than once, so by YouTube standards that means I'm an expert. Heaven help us all. So, here are some thoughts.

There are really two kinds of "hybrid" application. The first is a UNIX program that calls the Macintosh Toolbox and OS calls. The second is to build a Mac application that makes UNIX system calls. Apple's documentation tries to encourage you to do the former, for fairly good reasons, but in the hobbyist world with small audiences, it's probably a better use of effort to build a Mac application that has optimisations for A/UX (such as using native UNIX sockets instead of MacTCP when on A/UX).

To check whether you can do this, you can just check 'a/ux' in the Gestalt Manager, something like:

C:
void auxinit(int alertID) {
    long auxversion;
    OSErr err;
    
    err = Gestalt('a/ux', &auxversion);
    
    if (err != noErr || auxversion < 2) {
        StopAlert(alertID, nil);
        
        ExitToShell();
    }
}

Once you know you're running on A/UX, you can make system calls. Apple's own advice on how to do this is "write a C program in A/UX that uses it, build it with cc, disassemble it, then copy and paste the assembler info your project". This does work, but is very tedious. So you'd write something like this:

C:
#include sys/types.h
#include sys/stat.h

void main() {}
    struct stat buf;
    fstat(0, &buf);
}

Then compile it with

$ cc fstat.c

Loading this into your disassembler of choice (a modern one, like IDA Pro or Ghidra, can make this considerably less tedious: though note that I've had some funky misparses with IDA) will give you something like this:

Code:
    movea.l 4(sp), a0
    move.l 8(sp), d1
    moveq #0x7c, d0
    trap #0xf
    bcs.w err
    rts
err:
    jmp cerror
    
cerror:
    move.l d0, errno
    moveq #-1, d0
    movea.l d0, a0
    rts

which you can then wrap with the appropriate prototype and declarations (taken from the man page) to get something like this. Note that this uses 'long' where the manual page uses 'int' because 'int' on Mac compilers tends to be 16 bits, and on A/UX it's definitely 32:

C:
long errno = 0;

struct    stat
{
    // lots of stuff taken from sys/stat.h here
}

asm long fstat(long fd, struct stat* buf) {
    movea.l 4(sp), a0
    move.l 8(sp), d1
    moveq #0x7c, d0
    trap #0xf
    bcs.w err
    rts
err:
    jmp cerror
    
cerror:
    move.l d0, errno
    moveq #-1, d0
    movea.l d0, a0
    rts
}

The shortcut, of course, is to get someone else to do this for you. Apple produced a load of assembly snippets for various calls, which are in the "AUX System Calls" ZIP file attached to this thread. Those are easier than doing the disassembly yourself. For other people who use CodeWarrior, auxsock.zip contains a wrapper for some of the syscalls that I have found useful.

This all works fine right up until you want to use any asynchronous code at all, whereupon a major, but subtle problem raises its head.

Remember that you're sharing a Mac environment with hybrid applications that have their own process contexts. Imagine you have a VBL interrupt in your Mac application, and a hybrid process with its own process is running. When that process is hogging the Mac (say, it has a menu open because the mouse button is down in the menu bar) and your VBL interrupt runs, it runs /in the process context of the hybrid process/. This means that any UNIX resources you have open are not available. So, check your pid in asynchronous code before using things like file descriptors. This is why getpid() is in auxsock.zip.

Any questions that I can pretend to know the answers to? :-D
 

Attachments

  • AUX System Calls.zip
    248.5 KB · Views: 2
  • auxsock.zip
    2.8 KB · Views: 2

MrFahrenheit

Well-known member
Are there benefits to writing an A/UX hybrid app?

Is there something the hybrid app can do within the A/UX playpen that can’t be accomplished by a regular Mac OS application in the same space?

Is the reason for a hybrid app for compatibility? As in, would an app that does something a specific way break under A/UX but coding it as a hybrid makes it work?

As you know, A/UX intrigues me a lot. I’m not a software developer though and my experience with A/UX is relegated to many times installing it and just trying it out casually. I did setup an Apache web server under A/UX in 2005 or so, just for fun. I’ve been debating on setting one up that is public just for people to see how it works connecting to it.

I guess one of the benefits of A/UX would have been running a web server on it and also using Mac OS applications on the same system, locally.
 

Phipli

Well-known member
Can you port Blender for me?

Also, thank you for documenting your experiments, much appreciated.
 

cheesestraws

Well-known member
Are there benefits to writing an A/UX hybrid app?

The main advantages I've found so far is that the BSD sockets API for building networking applications is much easier and much faster than MacTCP, even A/UX's fake MacTCP. I'm fairly sure this is one of the ways that AppleShare Pro manages its high transfer rates, for example. But then, I'm a networks person, and I tend to go straight to 'writing network applications'. Perhaps another use case is writing Mac applications to make the UNIX side more friendly, because you can talk to UNIX processes "on their own terms" as it were.

Honestly, the reason I was exploring this was mostly "nobody else seemed to be and it looked interesting" :)

As in, would an app that does something a specific way break under A/UX but coding it as a hybrid makes it work?

also, A/UX's ersatz MacTCP is ropy, which is what sent me down this rabbit hole in the first place. I was trying to get minivnc running, and it really didn't want to play, and I refused to give up...

Also, thank you for documenting your experiments, much appreciated.

Hopefully at some point the notes might be useful!
 
Top