Skip site navigation (1)Skip section navigation (2)
Date:      Sun, 28 Nov 1999 16:48:20 -0800 (PST)
From:      Matthew Dillon <dillon@apollo.backplane.com>
To:        Julian Elischer <julian@whistle.com>
Cc:        arch@freebsd.org
Subject:   Re: Threads stuff
Message-ID:  <199911290048.QAA47070@apollo.backplane.com>
References:   <Pine.BSF.4.10.9911281602440.544-100000@current1.whistle.com>

next in thread | previous in thread | raw e-mail | index | archive | help

:> 
:> 	* Kernel stack sharing by multiple threads in the non-blocking case,
:> 	  which can lead to better memory and cache resource utilization.
:> 
:> 	* An infinite number of threads can be created as long as they do not
:> 	  all need a kernel stack simultaniously.
:> 
:> 	* Kernel management issues are complex, but not terribly so.  For
:> 	  example, you have a thousand threads and they all suddenly decide
:> 	  to block inside the kernel - the kernel needs a mechanism to 
:> 	  disallow kernel entry (setup the thread to force a restart of the
:> 	  system call and then switch threads because no KSE resources are 
:> 	  available).
:
:The UTS can know its limit on KSEs and simply catch them on the way
:down. Count them at the door like a night club bouncer.. one out, one in..
::-)

    This isn't necessarily useful for the UTS to know.  The UTS needs a 
    virtual cpu resource 'environment' and should not have to know anything
    beyond that.  So, for example, the number of cpu's you tell the UTS
    it owns does not have to be the same as the number of actual cpu's in
    the system or even the number of cpu's you intend to schedule it across.

:>     Problems:
:> 
:> 	* You have to manage dynamic allocation and deallocation of KSE's
:> 	  (verses simply preassigning one per thread).
:> 
:
:I don't think this is too hard, and we may endup using the 
:same code in things like interrupt handler threads. :-)

    In the scheme I am thinking of, an interrupt handler thread can simply
    be a KSE associated with a single 'kernel' special 'process'.

:> 	* You have non-deterministic resource utilization for an application.
:> 	  The worst case KSE useage is going to be one per thread, but the
:> 	  userland may well allow thousands of threads to be allocated first
:> 	  and then realize only later that it does not have the kernel 
:...
:
:programmer error?
:In the current world, a programmer may decide to fork 1000000 times too.

    In the world of threads the situation is different.  Certain programming
    problems are best implemented if you can assume a huge number of
    available 'threads'.  We have to make the concious decision to either
    support or not support such environments.  I believe it would be possible
    to support such environments using the dynamic KSE concept so while I
    do not in general like the idea of dynamic KSE's, I'm willing to go along
    with it if we can find a sensibile way to implement them.

    Also keep in mind that we may, years down the line, wish to expand the
    environment to support massively parallel computing - cross platform
    computing.  In such environments several hundred thousand threads is
    not uncommon.

:> 	* You compound the management issues within the userland scheduler 
:> 	  itself because not only can the userland scheduler switch between 
:> 	  threads, now so can the kernel when it decides it must block.
:...
:
:No the blocked thread 'returns' to the UTS, notifying it of its blocking.
:There has to be a UTS no matter what, even if it's copntrolling the
:thread contexts by remote control in the kernel (yur suggestion).
:If the context is all in user memory, it's pageable. In the kernel it's wired kernel memory.. which is more valuable?

    Well, if you do this you are doubling your context switch overhead.  It
    may work for system calls but will definitely not work for faults or other
    potential blockages without adding a lot of complexity.   Considering 
    the fact that programs use mmap() more and more heavily, having to deal 
    with faults is a major consideration.

:> 	  such as VM faults, and cannot schedule around such things itself.
:> 	  This can lead to non-deterministic operation.
:
:The UTS can have upcalls for these events. (see the paper on
:Scheduler activations)

    Yes, I understand where you are coming from.  I believe the scheme to be
    too complex, however.   Hmm.  Let me restate that:  I think the kernel
    ought to have the support for a UTS, but that it should not be required
    for native thread support to function.  The kernel should be able to 
    support threads natively without a UTS simply because most threaded
    applications will not need the added sophistication.  This isn't to say
    that the UTS is entirely absent, only that it need not function in the
    heavy-handed complex way you've described in most cases and can simply
    be a simpler skeleton that keeps track of the threads.

:> 	  better able to actualy get the thread running deterministically
:> 	  because the userland scheduler might end up 'stuck' in a VM
:> 	  fault or something similar.
:
:that is unlikely to occur.
:I would assume that any thread library would get that memory wired down
:and it would be being touched all the time anyhow.

    Maybe, maybe not.  It is an added complication and should not be required
    for the kernel to operate.  Requiring wired down memory for proper 
    operation is *bad* in many cases.  If multi-threaded applications become
    ubiquitous, requiring wired down memory eats a valuable resource for idle
    processes (unless even more complexity is added to deal with that case
    on top of the complexity that already exists)

:> 	* First, that thread runnability be controlled through a system call.
:> 	  Ther userland can determine when to halt and run a thread and can
:> 	  even assign a cpu, but it must make a system call to actually 
:> 	  schedule or deschedule the thread.
:
:We are rforking to make subprocs. a subproc runs at one priority on one CPU.
:it has it's struct proc, (or most of one :-) and the threads are assigned
:to it. Any KSE that is created is automatically hung off that subproc.
:it will ony be run on that cpu unles there is intervention.
:(of which there may be may types, fro example a related subproc may be totally idle at teh time a KSE becomes unblocked.. it would be a waste to not use that other CPU)

    This seems like an added unnecessary complication that would be 
    difficult to scale dynamically to different topologies.  Or, put another
    way, the burden of knowledge is much greater with this scheme then with
    other schemes.

    You already have KSE's, that's all the execution environment you really
    need.  The KSE's will have an associated process, but the kernel is able
    to schedule KSE's across available cpu's even if several are
    associated with the same process.  Every *active* thread needs to have
    an active KSE associated with it in order to handle faults, even if it
    is not currently in a system call, which means that it is the KSE's
    the kernel associates with a cpu, not a process.  Runnable (but not
    active) threads do not need KSE's associated with them if they are not
    in the midst of a system call.

    An outline of my scheme would simply be:

	* You have a process, the process has threads

	* Each thread has a kernel Thread (or Task) structure associated
	  with it.

	* KSE's are assigned to threads as needed, with only two cases that
	  *require* a KSE assignment.

	  (1) When the thread is currently running on a cpu, a KSE must be
	      assigned to it even if the KSE's stack is not being used at
	      the moment.  

	      Reasoning:  So the kernel can preemptively switch away from the
	      thread, take interrupts, faults, and other things.

	  (2) When the thread is blocked in a system call, a KSE must be
	      assigned to it to hold the kernel stack state.

    If you do things this way then the implementation within the kernel 
    becomes trivial.  The kernel scheduler only needs to know about KSE's
    and MMU contexts (extracted from the associated struct proc), and that's
    it.  You can still impose scheduling requirements via a UTS by having
    the UTS give 'hints' to the kernel, but the UTS would not be 
    *synchronously* required to wakeup a thread or put it to sleep.

					-Matt
					Matthew Dillon 
					<dillon@backplane.com>




To Unsubscribe: send mail to majordomo@FreeBSD.org
with "unsubscribe freebsd-arch" in the body of the message




Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?199911290048.QAA47070>