ImperialViolet

UK-DMCA (13 Aug 2002)

Coderman is working on a new project - PeerFrogs. Looks like it forms the basis for his CodeCon 2 submission.

From Danny O'Brien (the NTK guy):

I'm pretty sure it's a statutory instrument with negative resolution -
which is to say, it becomes law the moment it's announced, butParliament has forty days to pass a motion annulling it. AFAIK, that's
how most EU Directives are implemented.

Oh crap

That means MP's have to get off their backsides and actually do something active. We screwed.

Userland page fault handling

One of the weaknesses of user land threading is that you have to alloc a fixed area as thread stack space. This imposes an extra, non-trivial, cost on thread creation as the stack size for all threads is determined by the biggest (unless you pass a hint at creation time which is dangerous).

The solution to this is to do the same as the kernel does; handle page faults as the threads fall off the bottom of the stack space and map in pages to catch them. That way you have to set a fixed max size for stacks - but you don't have to map in all those pages. You use up address space, not memory

Of course, address space isn't exactly huge in a 32-bit machine. On most Linux boxes I think dlls are mapped in at 0x80000000 (it's 0x00100000 here, but that's because I run funny kernel patches). That leaves half the address space free for mapping since the main stack grows down from the 3GiB mark.

So, assuming that we have 2GiB of address space for stacks we can reserve 128KiB for stacks and fit in 16384 threads. When you consider that most threads will take about at least 8KiB of actual stack, and that 8KiB*16384 = 134MB of stack, that limit doesn't seem to bad. (It's still not great thou, and there is some deep&dangerous hackery that can get around it, email me if you want details).

The actual page fault handling turns out not to be too hard. First mmap a couple of pages from /dev/zero for the signal stack (since we are trapping when we run out of stack we need the SIGSEGV handler to run on a different stack), fill out a stack_t struct and setup the SIGSEGV to use it. In the handler, process the siginfo_t and find the stack which faulted and use mmap to add another stack:

void sig_segv (int sig, siginfo_t *siginfo, void *d)
{
	// Walk the threads and find the one that faulted from the fault
	// address in siginfo->si_addr

	// Use mmap with MAP_FIXED to map in another page at the right place
}

void
setup_fault_handler ()
{
	stack_t sigst;
	struct sigaction sigact;
	char *sigstack;
	int devzerofd;

	devzerofd = open ("/dev/zero", O_RDWR);

	sigstack = mmap (NULL, 8192, PROT_READ | PROT_WRITE, MAP_PRIVATE, devzerofd, 0);

	sigst.ss_sp = sigstack;
	sigst.ss_flags = 0;
	sigst.ss_size = 8192;

	sigact.sa_sigaction = sig_segv;
	// set the sigact mask
	sigact.sa_flags = SA_ONSTACK | SA_SIGINFO;

	sigaltstack (&sigst, NULL);
	sigaction (SIGSEGV, &sigact, NULL);
}