BSD DevCenter
oreilly.comSafari Books Online.Conferences.


IRIX Binary Compatibility, Part 5
Pages: 1, 2, 3

Thread Models in IRIX and NetBSD

IRIX supports portable threads, of course, but because this is all implemented in userland, it is transparent for our IRIX emulation on NetBSD. We do not have to set up anything to support that.

Native threads are implemented through sproc(2) system calls and variants: nsproc(2), sprocsp(2), and so on. Variants differ from the original system call by offering options such as the possibility to choose where the new thread's stack will be allocated. IRIX has special terminology for native threads created by sproc(2): they constitute a share group.

Here is sproc(2)'s prototype:

pid_t sproc (void (*entry)(void *), unsigned inh, void *arg);

The first argument is the thread entry point. Once the kernel has created the new thread, it returns to userland and resumes execution at the address pointed to by the entry argument.

inh stands for inherit. This integer value holds a few flags which specify whether various resources should be shared or not between the thread and its parent. Sharable resources include: address space, UID/GID, process limits, file descriptors, umask value, and working directory.

Finally, arg is a pointer to the thread entry function's arguments. There is no argument counter, as the parent and the child are supposed to know each other well enough to be aware of what is pointed to by arg.

Now, what about NetBSD? Of course NetBSD supports user threads, although there is no built-in user thread library. If you need user threads, you have to install a third-party thread library. The NetBSD package collection includes multiple user thread libraries: devel/unproven-pthreads, devel/pth, and devel/mit-pthreads. Of course all the packages work. There are three implementations available because none is perfect, so we leave the choice to the user.

With native threads, things become more difficult since NetBSD does not support native threads yet. Given this situation, emulating IRIX native threads may seem an impossible task. Fortunately, it is not, and we will explain why a bit later. For now, let us explain why NetBSD is so poor regarding threading.

We explained before that both user threads and native threads have their drawbacks. In an ideal world, we would want both a standardized API, and a thread model where threads can take advantage of multiple processors and are not blocked because of a blocking system call issued by another thread.

NetBSD is now close to be that ideal world thanks to Nathan J. Williams, who is working on an hybrid thread model that maps user threads to kernel threads. This concept is called Scheduler Activations and was first introduced by Sun Microsystems in Solaris.

O'Reilly Gear.

There is no thread capability built into NetBSD, whether user or native, just because we want the ideal world for NetBSD and nothing else. But before we enter the perfect world, we want to emulate IRIX native threads.

In fact, NetBSD does support native threads. NetBSD just lacks the API to spawn native threads from userland. From the kernel, and especially from a foreign OS emulation subsystem, there is no problem: you can create a native thread. This has been used for Linux emulation first since a lot of Linux applications require native threads through the clone(2) system call. In order to emulate Linux's clone(2), NetBSD needed some support for native threads. We end up with this strange situation where the NetBSD kernel is able to emulate features that it does not support natively.

In the NetBSD kernel sources, native threads are supported through the fork1(9) kernel function, found in sys/kern/kern_fork.c. fork1(9) has some options, including the possibility to share the virtual memory space with the parent.

It is worth mentioning that the NetBSD fork(2) system call implementation is just a wrapper to fork1(9) with appropriate arguments:

int sys_fork(struct proc *p, void *v, register_t *retval)
        return (fork1(p, 0, SIGCHLD, NULL, 0, NULL, NULL, retval, NULL));

In this file, there is also a sys___clone() function, which is a Linux clone(2) compatible system call. It is not exported in the kernel API, but if you ever want to natively build a Linux application that uses clone(2) on NetBSD, consider adding sys___clone() to NetBSD native's syscall.master and rebuild a kernel (note that you also need to patch the libc to make the system call available).

Having described threads and the NetBSD implementation, let us move on to something more serious: the actual implementation.

Everything is done in sys/compat/irix/irix_prctl.c. Here we have the various sproc(2) variant implementations: irix_sys_pidsprocsp(), irix_sys_sprocsp() and irix_sys_sproc(), respectively implementing pidsprocsp(2), sprocsp(2), and sproc(2). All these functions call irix_sproc() with appropriate arguments. irix_sproc() does the actual work, which is mostly to call fork1(9).

Pages: 1, 2, 3

Next Pagearrow

Sponsored by: