On Jul 19, 2005, at 5:43 AM, Dominic Dunlop wrote:
On 19/07/2005, at 10:27 AM, Joshua Juran wrote:
I'm porting perl to a platform called Genie, which is a Unix-like
subsystem that runs in Mac OS. The purpose of this exercise is to
have a command-line perl tool available for Mac OS, in a stdio
environment with polymorphic file descriptors, without the
limitations of MPW.
Good to hear. You don't say whether this is PPC or 68k Mac OS. I guess
the former, though the FAQs on your site make me wonder.
I wonder too. I haven't looked at them in years. :-)
Genie requires CFM -- Genie programs are built as CFM drop-ins, or
plugins. CFM-68K Runtime Enabler 4.0 requires System 7.6.1, which
requires a 32-bit clean ROM (and perhaps a 68020 or better). This
leaves out the Mac II, IIx, IIcx, SE/30, and 68000-based machines
(unless an earlier version of the CFM-68K Runtime Enabler with an
earlier system works, which I don't plan to test any time soon). While
it might be possible to use code resources (with Genie fiddling the A4
register for plugin globals) I don't see the value, since much faster
Macs are readily available on the cheap. Genie does actually build and
run on 68K, although you have to patch a bug in Threads.h if you want
to use Thread Manager callbacks without crashing.
Genie's sockets support requires Open Transport -- MacTCP is not
supported. I don't think this will upset anyone.
One caveat is that Open Transport only supports CFM-68K as of version
1.3, which requires Mac OS 8.1, which in addition to ruling out
anything less than a 68040 nails you to a specific OS version.
Fortunately, the OTCFM68KGlue library hacks around this by calling OT
from a 68K code resource and should make it possible to support System
7.5.5 and 7.6.1. I haven't tried this yet.
Back in the day, I worked on keeping Perl running on PPC MachTen, a
commercial UNIX-under-Mac OS product from Tenon Intersystems
(http://www.tenon.com). The product, though still apparently
available, is, as far as I know, unsupported, and suffers from a
number of long-standing bugs and security issues. Vague requests from
some users that the code be open-sourced after support ended were
rebuffed.
Apple phrased it this way: "Open source is not a dumping ground for
dead products."[1]
Most unfortunate, since I'm sure I could have found *something* useful
in the source code. ;-) Other closed Unix-on-Mac products include
Mac06 and (though this is a stretch) Apple's own MPW. Open-source
projects include MacMiNT and PATMOS.
MachTen was delivered with gcc, so I didn't use MPW or CodeWarrior in
porting perl. If you search in old perl5-
Genie requires a real C++ compiler to build, which rules out MrC/SC.
Plugins shouldn't require C++ at all, but I haven't investigated using
anything other than MW C. Perhaps I should -- I ran into some curious
MW linker issues that prevent me from linking Genie plugins against my
own shared libraries, and had to link in the standard library
statically.
porters archives, you'll find mail about various issues I tripped
over, including malloc() (once tweaked to work, Perl's own malloc was
much faster than Mac OS' own); and fork() (MachTen, thanks to deep and
probably dark magic, has both fork() and vfork(), but the latter is
MUCH faster, as Mac OS does not support Copy on Write). You'll also
find clues in hints/machten.sh.
One of the problems is returning twice. Matthias got the idea to
provide vfork() as a macro that calls setjmp(), which he implemented in
his Natty project.[2] I opted against this for now, since what you'd
have to do with the return value of setjmp() to implement proper
vfork() semantics and what the standard says you're allowed to do with
it are not compatible. AFAICT you're not even allowed to assign the
return value to a variable. It might work anyway, but I didn't wish to
go there.
My interim solution requires as a compromise that code be written thus:
#ifndef macintosh
#define is_child_pid( pid ) ((pid) == 0)
#endif
pid_t pid;
while ( (pid = vfork()) == -1 ) sleep(5);
if ( is_child_pid( pid ) )
{
/* We're the child */
/* setenv, dup2, etc. */
execve( ... );
_exit( EXIT_FOO );
}
/* We're the parent */
waitpid( ... );
The trick here is that for a Genie plugin, vfork() saves the caller's
process context and returns the child pid (once), is_child_pid() is the
identity function (always true for a pid), and either execve() (unless
it fails) or _exit() restores the original process context AND RETURNS.
(Unless you call without forking, in which case it terminates the
caller's thread.)
Hey -- it works, doesn't it?
The third way is to decide you're not just an application but really
part of the operating system and actually implement per-process
address spaces, a la MachTen. This has been left as an exercise for
the reader.
For implementing qx// and system, vfork() is sufficient. For fork, we
should be able to use the same perl_clone()-based emulation that
Windows uses. See perlfork. It may even be possible to clone into a
'real' Genie process (which is really a kind of pseudo-process) without
resorting to pseudo-(pseudo-)processes, such that 'fork and exit' would
work.
Josh
[1] ...When asked to open-source HyperCard, at the 'Apple Handshake'
session of MacHack 2000.
[2] http://www.sourceforge.net/projects/natty/
--
Joshua Juran
Metamage Software Creations - Mac Software and Consulting
http://www.metamage.com/
* Creation at the highest state of the art *