Re: proc fs and shared pids

Al Longyear (longyear@netcom.com)
Wed, 7 Aug 1996 07:40:35 -0700 (PDT)


Linus Torvalds wrote:
>
> These kinds of issues are _exactly_ why clone() is such a good idea. With
> clone() there is never any ambiguity when it comes to fork/exec/exit,
> something that is not true of traditional threads. And the clone()
> semantics are actually _sane_ for all these cases.
>
> If you look at threads as just contexts of execution, WITHOUT the idiotic
> threads/process separation that traditional threads packages use, the
> semantics are always clear:
>
> - fork() is exactly the same as "clone(0)", and as such it's just
> another way to create a new thread. It's _completely_ orthogonal to
> all the other thread operations, and if you think of fork() as
> clone(0) (and that's actually how it's implemented inside the kernel
> too, not just a "conceptual" idea) there is never any question of what
> happens.
> - execve() is just a way to change the VM space of a task. Whether that
> task is a "thread" or a "process" in traidional parlance is totally
> irrelevant. A execve() does not change the VM space of other tasks.
> - the exit() system call closes down only the task that called it.
> Nothing else makes sense (if you want to have other behaviour you use
> "atexit()" to send a signal to the other threads you want to shut
> down).
> - quite naturally, a terminal signal kills only the task that got the
> signal.
>
> The above are all problems that exist with "traditional" threads, as you
> point out. The fact that the problems exist in the first place, and that
> traditional threads do not have clear-cut answers to them is just another
> reason why traditional threads are obviously not the right thing. If the
> semantics aren't clear, you CANNOT consider a interface a good one.

Ok. Let's suppose that we go with the concept of a clone for a moment.

Let me pose one additional question then. This is not a question about
what we have TODAY, but one of what we want TOMORROW when we say that
"Linux has threads." (I know the answer for today. :) )

Does the cloning go forward in time as it does in a traditional thread
model?

Suppose you have a process. It has one thread. It opens a file by
calling the open procedure. Ok. It now has the file open.

It then calls "create_thread" or "clone(0)" or whatever to create a
new thread.

Both threads now have the same file open. That is understood by all
models.

Now, the second thread opens yet another file by calling open().

Does the first thread get a new descriptor for the newly opened file?

Traditional thinking would indicate that it should. It would say that
files are a resource owned by the process and not by a thread. As
such, the file should be given to the first thread of the process
since it is owned by all threads of the process.

And, if it is given to the first thread, what do we do about closing
the file? If the file is stored as a process structure item for each
thread then both threads must close the file as there would be two
references to the opened file. Yet, only one thread really opened the
file and only one thread should close it.

If you don't like files, then substitute signal processing procedures,
memory allocation or semaphores or any other shared resource that you
would want to allocate/reserve for the term 'file' above.

I don't have an answer to these questions. These are not questions
which have only one 'right' answer. These are questions to ponder over
when you consider the design of threads in a POSIX environment.

> WHY? You just pointed out yourself only _some_ of the problems with that
> approach. The whole approach is stupidity incarnate. The only reason that
> people are using the stupid thread/process approach is historical (due to
> the fact that you can implement that kind of limited threading with no
> kernel support, by "hiding" the threads inside the processes the kernel
> knows about). It's only a half-hearted approach at doing threading.

I don't believe that we are talking about the same issue here. I do
not say that threads are managed by the process in some
fashion. Threads are a resource of the kernel and are assigned to the
process as needed.

The kernel dispatches THREADS, not PROCESSES. The threads contain only
the context needed to dispatch the instructions. This would be the
current registers, priority, state, wait list, etc.

A thread then has a pointer to the process context. The process
context would contain things such as memory maps, open file lists,
identification (owner and group), etc. It would have all of the
information which was not in the TSS (and I don't consider the map
table, pointed to by the the TSS's cr3 to be "in the TSS") or needed
to dispatch the unit of execution.

The value of 'current' would point to the thread storage, not the
process storage.

Now, if you wish to duplicate all of the process releated information
such as map tables, etc. on a per-thread basis, then that is OK as
well ( for the time being, that is. :) )

I am sure that whatever scheme that is devised will work. I only
suggest that the more common problems of "well, threads are easy so we
can do them" need to be considered.

> I see that you use "COE": what I meant with COE was the exact opposite of
> what you say. A COE is not just the CPU state and priority. A COE is
> _everything_ that is needed to actually run, and thus it includes memory
> mappings etc. It's the "struct task_struct" in Linux world. After all, you
> can't dispatch a thread without all the other info..

As I indicated, a thread dispatch may be done with nothing more than a
TSS, priority/state information (along with the linkage information to
place the thread on some priority queue structure), a wait list which
is needed for a blocked thread, AND a pointer to the "rest of the
information". The rest of the information in the process table is just
baggage when it comes to the dispatcher. It is needed for other
things, true, but not in terms of giving execution to a sequence of
instructions.

I guess that it really comes down to a design philosphy.

Do you want to keep the information in one place and keep pointers to
the data along with reference counts of linked lists OR do you want to
duplicate the information in several different places?

If you duplicate the information then you need to be concerned about
currency. (This is true even if you declare that you won't keep the
copies current -- at least you did consider the problem at one point.)
Again, there is no "one" solution. You just need to choose. Either
solution is BOTH good AND bad.

-- 
Al Longyear           longyear@netcom.com
Finger for PGP key