It's been a few years since I looked (and messed) around with
threads, so forgive any errors I make. The below is given as
food for thought...
As I remember, there are 3 basic types of threads;
o Kernel Thread (basically for _kernel_ processes)
o Light Weight Process (what I'm interrested in here)
o User Level Thread
clone() tries to give Linux LWPs. Basically, this involves
allocating and setting up a _new_ task struct, and referencing some
other structures (signal handlers, etc) from the clone()ing process. I
would say this is the _wrong_ way round.
The new thread should use the _old_ task struct, and allocate memory
for the state which it does not want to share with the cloning process.
This could be achieved with a new structure 'thread struct', which
contains the thread's state. An incomplete list of what would be in the
o Kernel Stack
o Saved Registers (inc. FPU)
o Signal Mask
o An alternative signal stack (sigaltstack())
o Ptr back to task struct
o Scheduling pri
o I'm sure there's more....
'thread structures' would be doubly-linked off the task struct, with
(obviously) at least one thread per task. Threads would be the unit
of scheduling and context switching. On entering the kernel, the
globals 'current' and 'thread' would be set to the entering
task struct and thread struct respectively.
A task only 'dies' when _all_ it's threads have exited.
All threads within a task _share_ the same pid. This _isn't_ a major
restriction. Signals are split into two groups; exceptions and
interrupts. An exeception is a signal generated by a thread due to
its direct actions, such as; SIGILL, SIGSEGV. An exception
is delievered to the thread which generated the execption.
Interrupts (which are any signals that are not exceptions) are
delievered to any thread within the task which is not ignoring the
signal. When signals are used for inter-task communication, the
sending task _shouldn't_ care about what thread receives the signal.
Signals should not be used for inter-thread communication within a
thread - there are much better inter-commun. methods for threads.
Note: threads would share their signal handlers, but not their signal
Sharing the task struct among threads does cause one problem, with
fork(). Should fork() create a new task which contains only the
calling thread? Or should it create a new task containing all the
threads in the parent task? The answer depends on why the thread is
forking, and the solution (as Solarias, I believe) is to have two
forks - one for each case.
Under '/proc/pid' would be the 'normaly' files that contain the
task info, and a sub-directory for each thread in the task.
OK, I've missed a lot out, but this is the basic idea.