Messages in this thread | | | Subject | Re: kernel thread support - LWP's | Date | Fri, 16 Jul 1999 01:28:25 -0400 | From | Zack Weinberg <> |
| |
Khimenko Victor wrote: > Hmm. I know it's not really related to linux-kernel but still... WHY glibc > is getting 20 usecs or so and can it be shrinked down to 3 usecs ? Usually > peoples (like Apache developers, for examle) do not use clone(), it uses > pthreads: clone is nice and all but it's non-portable...
pthread_create() has to do a hell of a lot more work than just clone(). Part of this is the ugly implementation, part is (I think) intrinsic to the attempt to stack POSIX thread semantics on top of clone().
There is an internal thread used by libpthread. It's called the "manager". It gets created the first time you call pthread_create. It sits blocked in select() on a pipe.
Assuming the manager is already active, pthread_create writes a message down that pipe saying "please create another thread". The manager wakes up and creates a new child, which involves a pile of work both before and after the call. In the end it kicks the original thread back awake with a signal.
The minimum sequence is
<calling thread> write sigsuspend <switch to manager> select returns getppid read geteuid mmap, twice clone <switch to child> getpid <back in manager> kill select <calling thread is awake again>
That's _minimum_. Add at least two calls to sched_setscheduler (one parent, one child) if you run RT threads. There might be N calls to waitpid in between getppid and read. Plus there's a bunch of copying data around in user space. There are some mutexes that have to be acquired and dropped. Etc.
Why is it doing all this crap? Because of another requirement of the POSIX thread spec, which hasn't got any air in the conversation yet: Any thread in the process can do the equivalent of waitpid for any other thread in the process. Linux doesn't allow that; you can only wait for a task that you yourself spawned (unless you are init). The workaround is to make all the threads children of the "manager". It waits for them and passes back exit statuses to the threads calling pthread_join.
There's another lovely detail: The "initial thread" (the one that was executing before the first call to pthread_create) isn't a child of the manager; it's the parent of. Per POSIX, the manager has to notice when the initial thread goes away and kill all the others. That's why there is a getppid in the above. The select times out every two seconds just so it can check.
---
If there were a way to specify - ideally at clone time - that any task in some group (process group would be fine with me) can wait for this child, then the above gunk could be reduced to clone() plus the work of setting up the child's stack (the mmaps) and user-level context (data for pthread_setspecific, per-thread errno, etc.) And that would get you a hell of a lot closer to 3usec thread create times. If you had a CLONE_VM_WITH_NEW_STACK that created a new stack for the child (still visible to both) then more overhead would go away, plus clone() wouldn't need a special assembly stub that only works if you use CLONE_VM.
It would also be handy to have a "disown" call which had the effect of immediately reparenting the target process to init. Currently "detached threads" have to be waited for too.
zw
- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.rutgers.edu Please read the FAQ at http://www.tux.org/lkml/
| |