monday, 21 may 2007

posted at 10:10

I implemented SET_FILE_SIZE late last week. I don't want to talk about it, read the code if you need the details. Its a nightmare and I had to rewrite it three times before it was right. It shouldn't have been difficult, as its just an exercise in linked-list management, but as usual it took me a little while to realise this.

Work on FAT is really winding down now, so I'm starting to move into hacking on DOS. The eventual goal for me is to remove IOFS and use packets natively, and to fix up all the boot sequence and volume management stuff. I did the first bit this morning.

The only real stumbling block for using packets over IOFS is the addition overhead of using messages over Exec IO calls. IO calls (via DoIO()) simply calls a device's BeginIO vector - no mess, no fuss. On the other hand, sending a message (via PutMsg()) disables task switches and interrupts, adds the message to the ports' message list, then triggers the interrupt or signal. Later, when the thing listening on the port (ie the filesystem) receives the message, it calls GetMsg() to get the message, which does another round of disabling task switches and interrupts. This overhead was deemed unacceptable by advocates of IOFS.

It is alleviated slightly by an undocumented port type. A disassembly of the Amiga 1.2 exec.library reveals that when the port type == 3, no signalling or interrupt is done but instead a handler function is called directly. I've implemented this as PA_CALL. Its good for compatibility, but still not quite what we want to replace IOFS, as it still disables task switches while it adds the message to the list.

I had a brief discussion with Staf Verhaegen a couple of weeks ago, and we came up with a solution - a new port type that doesn't disable task switches but simply calls a handler function (like PA_CALL) with the message as an argument to the function. This makes it equivalent to DoIO(). You really need to know what you're doing to use it (in particular you don't get your messages from WaitPort() and PutMsg() any longer), but it allows filesystems to be called without any additional overhead (assuming they've been written to support this) and doesn't require any changes in DOS or applications - they just call PutMsg() (or SendPkt()) like normal. I've implemented this this morning as PA_FASTCALL.

I wrote a test program, tests/timeport that sends one million messages to each of the different port types and times how long they take (including a standard PA_SIGNAL reply). The timings are for comparison purposes only, but its still revealing:

8.System:> tests/timeport
testing with 1000000 messages
PA_SIGNAL: 15.10s
PA_SOFTINT: 7.220s
PA_CALL: 3.940s

Now to commit. Hopefully there won't be too much fallout :P