Subject: Process vs. Threads

Hello everybody:

I have been trying to differenciate threads and process in Linux. As
I am sure you already know, other OS, namely HPUX, implement threads
in a different way. There is a thread id (TID) field in the structure
that is used by the scheduler and it is used to identify uniquely each
"task" that can be run. Using this structure makes easier to identify
which threads belong to the same process and tools such as ps or top
show the TID as a field.

I understand that changing this in the Linux kernel would mean that:
* some tools will have to be modified.
* the proc filesystem should create a directory using the TID instead
of the PID.
* some features as VM handling, signaling or exec()ing from a thread
would be more difficult to implement.
* compatibility will be broken.

However, I miss some way to indicate that two processes are, in
fact, threads of the same process. Maybe there is something I'm
missing. Let me elaborate this.

If you run 'top' (sorted by memory usage) and, lets say, you have 9
threads, you see the SIZE of these 4 threads

10:40am up 1:23, 1 user, load average: 0.26, 0.22, 0.10
52 processes: 51 sleeping, 1 running, 0 zombie, 0 stopped
CPU states: 0.0% user, 3.1% system, 0.0% nice, 96.8% idle
Mem: 322464K av, 306284K used, 16180K free, 16876K shrd, 32432K
buff
Swap: 530136K av, 8064K used, 522072K free 13660K
cached

PID USER PRI NI SIZE RSS SHARE STAT LIB %CPU %MEM TIME COMMAND
745 root 0 0 224M 217M 1596 S 0 0.0 68.9 0:00
traffic_mana
840 root 15 0 224M 217M 1596 S 0 0.0 68.9 0:00
traffic_mana
841 root 0 0 224M 217M 1596 S 0 0.0 68.9 0:13
traffic_mana
846 root 0 0 224M 217M 1596 S 0 0.0 68.9 0:00
traffic_mana
848 root 0 0 224M 217M 1596 S 0 0.0 68.9 0:00
traffic_mana
850 root 0 0 224M 217M 1596 S 0 0.0 68.9 0:00
traffic_mana
855 root 0 0 224M 217M 1596 S 0 0.0 68.9 0:00
traffic_mana
856 root 0 0 224M 217M 1596 S 0 0.0 68.9 0:00
traffic_mana
857 root 0 0 224M 217M 1596 S 0 0.0 68.9 0:00
traffic_mana

This information is missleading since there is no way to know that
these 9 threads are sharing memory. If you run 'ps axl' you can see
the hierarchy as if it was a multiprocess program, i.e. no difference
to show you that they are threads. Not even reading
/proc/<pid>/status you get info about these being threads.

Of course, I am talking about kernel 2.2.x, but AFAIK this has not
changed in the new kernels.

Would it make sense to include this as an entry of the /proc/<pid>?

Thanks for reading,

Jorge


2001-03-06 16:58:41

by Gregory Maxwell

[permalink] [raw]
Subject: Re: Process vs. Threads

On Tue, Mar 06, 2001 at 05:28:43PM +0100, Jorge David Ortiz Fuentes wrote:
[snip]
> "task" that can be run. Using this structure makes easier to identify
> which threads belong to the same process and tools such as ps or top
> show the TID as a field.
>
> I understand that changing this in the Linux kernel would mean that:
> * some tools will have to be modified.
> * the proc filesystem should create a directory using the TID instead
> of the PID.
> * some features as VM handling, signaling or exec()ing from a thread
> would be more difficult to implement.
> * compatibility will be broken.
>
> However, I miss some way to indicate that two processes are, in
> fact, threads of the same process. Maybe there is something I'm
> missing. Let me elaborate this.
[snip]
> This information is missleading since there is no way to know that
> these 9 threads are sharing memory. If you run 'ps axl' you can see
> the hierarchy as if it was a multiprocess program, i.e. no difference
> to show you that they are threads. Not even reading
> /proc/<pid>/status you get info about these being threads.
[snip]

There are no threads in Linux.
All tasks are processes.
Processes can share any or none of a vast set of resources.

When processes share a certain set of resources, they have the same
characteristics as threads under other OSes (except the huge performance
improvements, Linux processes are already as fast as threads on other OSes).

Execution contexts which share resources do not have to share memory. If we
implemented top to aggregate such processes (as you suggest), the result
would also be potentially misleading.

If we were to break compatibility it should be actually fix the situation,
not replace once misleading situation with another.

Sometimes it is handy to view a collection of execution contexts as a
singular object. However, such is also the case with a service implemented
as a collection of share-none standard unix processes (like postfix). A
better solution would be a more generalized system for service object
management. Such a solution could likely be implemented without kernel
intervention (though perhaps a general facility to determine what shares what
with who might be needed).

2001-03-06 16:59:31

by Dan Kegel

[permalink] [raw]
Subject: Re: Process vs. Threads

[email protected] wrote:
> I have been trying to differenciate threads and process in Linux. As
> I am sure you already know, other OS, namely HPUX, implement threads
> in a different way. ...
> Of course, I am talking about kernel 2.2.x, but AFAIK this has not
> changed in the new kernels.

It's starting to change a bit; see the discussion following
http://boudicca.tux.org/hypermail/linux-kernel/2000week36/0903.html
("thread group comments").

Can someone summarize the state of the thread changes in 2.4?
A lot seemed to happen, but from what I gather, nothing user-visible yet.

- Dan

2001-03-06 17:33:34

by Ulf Carlsson

[permalink] [raw]
Subject: Re: Process vs. Threads

Hi,

> Can someone summarize the state of the thread changes in 2.4?
> A lot seemed to happen, but from what I gather, nothing user-visible yet.

We have the concept of thread group now. A thread group will be
created if you use the CLONE_THREAD flag from userspace. The task
structures for the threads cloned with CLONE_THREAD will be on a list
for that thread group list and the tgid field will also be copied from
the parent process. The tgid is returned to the user by getpid(), so
all the threads will seem to have the same pid from within the process
although they will show up with different pids in /proc. The tgid
implementation is IMHO braindead.

A problem seems to be that we don't check for the tgid field in
getpid(), so theoretically when you do for example raise() from a
thread the signal could be sent to a process that you didn't intend to
send a signal to.

Also if you send a signal to a process it will be delivered to the
thread with that pid and it will remain pending if that thread is
blocking the signal, which doesn't comply with pthreads. I am
currently working on a patch for this.

I have a list of other issues, but most of them can actually be solved
within glibc.

Ulf

2001-03-07 09:04:18

by Helge Hafting

[permalink] [raw]
Subject: Re: Process vs. Threads

Gregory Maxwell wrote:

>
> There are no threads in Linux.
> All tasks are processes.
> Processes can share any or none of a vast set of resources.
>
Is there a way a user program can find out what resources
are shared among which processes?

That would allow enhancing ps, top, etc to
report memory usage correctly.

Helge Hafting

2001-03-07 23:31:59

by Albert D. Cahalan

[permalink] [raw]
Subject: Re: Process vs. Threads

Helge Hafting writes:
> Gregory Maxwell wrote:

>> There are no threads in Linux.
>> All tasks are processes.
>> Processes can share any or none of a vast set of resources.
>
> Is there a way a user program can find out what resources
> are shared among which processes?
>
> That would allow enhancing ps, top, etc to
> report memory usage correctly.

I already looked into this. Sorry, it can not be done.

Linux briefly had the code needed to support threads properly.
Linus added it with the warning that it would be removed if he
didn't get enough feedback. Well I have a real job, and the code
was gone before the weekend! Look around near 2.4.0-test8 maybe.

For proper thread support:

First you need the concept of a thread group. This groups tasks
together similar to the way they form process groups and sessions.

Then for proper POSIX thread support, you need a flag to indicate
some awkward POSIX-mandated signal behavior within a thread group.

Then for proper ps and top output, you need a reasonably efficient
way to grab all threads as a group. This could be as simple as
ensuring that /proc directory reads return related tasks together.
This works too: /proc/42/threads/98 -> ../../98

Severely non-POSIX threads are just not going to do anything sane,
unless thread groups get automatically wrapped around any threads
that share resources. So if 50 shares memory with 67, and 50 shares
the filesystem with 82, then 67 and 82 are non-POSIX threads of the
same non-POSIX process even if they share nothing with each other.

Automatic wrapping works much better, assuming it doesn't also cause
the awkward POSIX signal behavior by default. Tasks should need to
explicitly request the extra suffering.

2001-03-08 00:18:50

by Hank Leininger

[permalink] [raw]
Subject: Re: Process vs. Threads

On 2001-03-07, "Albert D. Cahalan" <[email protected]> wrote:

> Then for proper ps and top output, you need a reasonably efficient
> way to grab all threads as a group. This could be as simple as
> ensuring that /proc directory reads return related tasks together.
> This works too: /proc/42/threads/98 -> ../../98

For this (but not for other "proper thread support" things you mention)
would it be enough to have /proc publish some token that represent unique
->fs, ->mm, etc pointers? (The kernel-space address of each would work,
though that might be leaking too much info; the least userspace must treat
such values as opaque canary tokens.) This does not give you the most
efficient "ps --threads 231" but it does let ps, top, (fuser?), etc group
processes with the same vm, files, etc, no? ...I'm kinda surprised such a
thing doesn't already exist actually. Unless of course, it does exist, but
is not enough :-P

--
Hank Leininger <[email protected]>

2001-03-08 03:22:51

by David Schwartz

[permalink] [raw]
Subject: Re: Process vs. Threads



> Gregory Maxwell wrote:
>
> >
> > There are no threads in Linux.
> > All tasks are processes.
> > Processes can share any or none of a vast set of resources.
> >
> Is there a way a user program can find out what resources
> are shared among which processes?
>
> That would allow enhancing ps, top, etc to
> report memory usage correctly.

In fact, 'top' does report memory usage correctly. What 'top' should do,
however, is (by default) suppress the display of additional processes that
share a vm, showing only the 'highest parent' in the tree of processes that
share a vm.

DS



2001-03-09 09:49:40

by Albert D. Cahalan

[permalink] [raw]
Subject: Re: Process vs. Threads

Hank Leininger writes:
> On 2001-03-07, "Albert D. Cahalan" <[email protected]> wrote:

>> Then for proper ps and top output, you need a reasonably efficient
>> way to grab all threads as a group. This could be as simple as
>> ensuring that /proc directory reads return related tasks together.
>> This works too: /proc/42/threads/98 -> ../../98
>
> For this (but not for other "proper thread support" things
> you mention) would it be enough to have /proc publish some token
> that represent unique ->fs, ->mm, etc pointers? (The kernel-space
> address of each would work, though that might be leaking too much
> info; the least userspace must treat such values as opaque canary
> tokens.) This does not give you the most efficient "ps --threads 231"
> but it does let ps, top, (fuser?), etc group processes with the
> same vm, files, etc, no?

You've identified the problem yourself.

When I wrote the new ps, I made a rule for myself: the default
output would not require sorting of any kind. Output would be
produced as soon as possible. This is for performance, and to
help tolerate kernel bugs that cause a hang.

So far I've resisted using threads myself to work around the
hang problem.

It won't be "ps --threads 231". It will be one of the following
options if you do want to see individual threads: m -m -T -L
(the options are in use on Tru64, AIX, IRIX, Solaris, UnixWare...)

So think of a way to wrap tasks together, preferably in a
way that is impossible for a non-POSIX thread to escape from.
Taking a guess at it:

Have an inherited task-group-ID that gets set equal to the task ID
whenever a task breaks away from other tasks. This includes fork(),
execve(), and any unshare() call that might be implemented. Note that
this does not, and indeed _must_ not, enforce POSIX signal behavior.
(the leader of a new and empty group might be able to request the
POSIX behavior for his group, but it can not be the default)