The Libmach emulation has been written in C. Because of the
object-oriented design of the port data management layer, we also
considered using C++ for some of the internal parts, but we hesitated
because we didn't have any experience with C++ cross compilers. It is
well possible to write efficient object-oriented programs using C: The
X11 toolkit library is a convincing example. 4.1.1 Ports
We've implemented a subset of Libmach's mach_port_* interface. The emulation routines manage a task's local port name space using the port data management layer. It currently is impossible to manipulate a remote task's port name space.
The routines implemented are:
Other routines of the Libmach interface will be implemented when necessary; their implementation is easy and straightforward.
The port data management layer consists of implementations of the classes shows in figure [here]. All classes implement constructor and destructor routines (if the class is not an abstract class), init and done methods, routines to change their port name, and a ,,friend''(1) routine which looks them up (i.e. returns a pointer to them) using a given port name. The higher level classes also contain routines to modify their list of rights, and to look them up using their system-wide name.
The object-oriented flavour of the port data management library is achieved in the same way as in the X11 toolkit library. [16]
The three-phase-commit protocol described in section [here] hasn't been implemented, yet: Only the special case of
transferring send rights of ports the sending tasks holds the receive
right for works. Also, port reference counting hasn't been
implemented, yet: So far, receive right holders don't get notified
when a tasks manipulates reference counts for their send rights.
Consequently, dead name notifications and port-deleted notifications
also don't work.
4.1.2 IPC
The mach_msg emulation provides the original mach_msg interface. The following routines are involved in the emulation and encapsulation:
The layout of the encapsulated message follows the example given in figure
[here]. struct msg_encapsulated {
MessageDopeT message_size;
MessageDopeT message;
unsigned long un_name;
int msgnum;
StrDopeT machmsg;
StrDopeT machaux;
};
The original message buffer is transmitted in the machmsg field. So the message parsing in mach_msg_trap_rcv parses the same structure and is identical to the parsing in mach_msg_trap_send.
We only implemented the following port right transfer types: MACH_MSG_TYPE_MAKE_SEND and MACH_MSG_TYPE_MAKE_SEND_ONCE. The long form of message components (msgt_longform) is not supported. The msgt_deallocate flag is not supported, it is already depreciated in Mach [8]
Condition variables are not available yet, so busy-waiting is used for synchronization. In order to avoid the performance impact of busy-waiting the task yields its processor time (in L3: ipc_switch). The receive operation does not manage timouts, hence it always waits until a message has been received.
The port service thread receives messages. It has to provide preallocated buffers before it knows the required size of the buffers, so these buffers have a fixed size too. After the message has been received the buffers could be truncated, but the current memory management doesn't support this. When the receive buffer is too small the receive operation for this message fails.
The data type mqueue_t is intended to store received messages in a FIFO.
These routines manipulate message queues:
The MIG-generated stubs require some support routines that are part of Libmach. These routines provide allocation/deallocation of memory (mig_allocate, mig_deallocate), initialization (mig_init), port-specific functions and an improved strncopy.
These MIG-specific routines were copied from
Mach's Libmach and adapted to the L3-specific functions. The memory
management routines use _libmach_malloc and
_libmach_free which allocate storage from the library's heap
(see below).
4.1.3 Virtual Memory Interface
As explained in section [here], we've implemented only a small part of Mach's memory management interface:
Both routines have several restrictions compared to Mach's implementation, as explained in section [here]; basically, they only provide the functionality of the traditional Unix malloc/free interface.
Internally, the library knows about two classes of memory objects:
At startup, the library initialization code allocates two data spaces
and creates two heaps upon them: One is used to resolve
vm_allocate requests, and the other one for library-internal
memory management: allocation of port data structures, rights, message
buffers, and so on. The size and location within the task's address
space of these two heaps are compile-time constants.
4.1.4 Utilities
The Libmach emulation library contains several general utilities and helper routines.
To support printing messages on an L3 terminal using L3's native printf implementation, our library contains a wrapper which allows linking cross-compiled programs against L3's standard C libraries.
Other debugging aids include macros which allow priority-based tracing of events (using printf), a verbose exception handler (able to tell which exception killed a thread), a routine which can invoke the L3 kernel debugger, and assertion/panic routines which can trigger a core dump (which can later be analyzed in the cross development environment).
The C Threads Library emulation discussed in section [here] hasn't been implemented, yet.