Ps Display Thread Name

How can I get the whole thread name when I use `ps -T -p [pid]`

The thread name length is restricted to 16 characters (including the terminating null byte \0). If the length, including the \0, exceeds 16 bytes, the string is silently truncated before storing it.

See pthread_setname_np and proc.5 -> find /proc/[pid]/task/[tid]/comm.

Related:

How to get the full executable name of a running process in Linux

Name of running threads inside a process

As hinted at in the pthread_setname_np, the new name is accessible as ps format specifier comm, but not args or command (which is what is usually printed):

ps H -C <cmd name> -o 'pid tid args comm'

illustrates the difference (adapted from the man page). I haven't been able to find a good piece of documentation that discusses this explicitly, though.

Here, <cmd name> is the name of your program's binary.

Python thread name doesn't show up on ps or htop

First install the prctl module. (On debian/ubuntu just type sudo apt-get install python-prctl)

from threading import Thread
import time
import prctl

def sleeper():
prctl.set_name("sleeping tiger")
while True:
time.sleep(10)
print "sleeping"

t = Thread(target=sleeper, name="Sleeper01")
t.start()
t.join()

This prints

$ ps -T
PID SPID TTY TIME CMD
22684 22684 pts/29 00:00:00 bash
23302 23302 pts/29 00:00:00 python
23302 23303 pts/29 00:00:00 sleeping tiger
23304 23304 pts/29 00:00:00 ps

Note: python3 users may wish to use pyprctl.

Can Windbg display thread names?

For .NET threads, the following works for "normal" Threads (manually created threads, since I don't know a way to name threadpool threads):

A Thread is a class and thus can be found in the .NET managed heap:

0:000>.loadby sos clr
0:000> !dumpheap -stat -type Thread
MT Count TotalSize Class Name
...
725e4960 11 572 System.Threading.Thread

Note that there is other output as well, since !dumpheap looks for parts of class names. The Method Table (MT) however, identifies a class uniquely, so that's what we use from now on:

0:000> !dumpheap -short -mt 725e4960
023123d0
02312464
02313c80
...

These are the addresses of Thread objects. Since it is clean output, we can use it in a loop:

0:000> .foreach (address {!dumpheap -short -mt 725e4960}) {.echo ${address} }
023123d0
02312464
02313c80
...

Inside the loop, we can use the address to get more information about the thread. First, let's find out how a Thread looks like internally:

0:000> !do 023123d0
Name: System.Threading.Thread
...
Fields:
MT Field Offset Type VT Attr Value Name
...
725e3e18 400076e c System.String 0 instance 02313c0c m_Name
...

At offset +0xC (depending on the bitness!), there's the m_Name member. That's a string. Let's find out how a string looks like:

0:000> !do poi(023123d0+c)
Name: System.String
...
Fields:
MT Field Offset Type VT Attr Value Name
...
725e4810 40000ac 8 System.Char 1 instance 4d m_firstChar

So, the first character of the string is at offset +0x08. Strings in .NET are Unicode, so we can view it with du:

0:000> du poi(023123d0+c)+8
02313c14 "My named thread 0"

Combine all this knowledge into a single command:

.foreach (address {!dumpheap -short -mt 725e4960})
{
du poi(${address}+c)+8
}

(formatted for readability, put it all in one line)

If you try that, you'll find that it may output something like

00000008  "????????????????????????????????"

This happens when m_Name is null. If you care about that, you can add a check for null:

.foreach (address {!dumpheap -short -mt 725e4960})
{
.if (poi(${address}+c) != 0) {
du poi(${address}+c)+8
}
}

(formatted for readability, put it all in one line)

Other improvements:

  • do the same for the thread ID
  • prettify output (use .printf instead of dd and du)

Final result:

.foreach (address {!dumpheap -short -mt 725e4960}) 
{
.if (poi(${address}+c) != 0)
{
.printf "%d ",poi(${address}+28);
.printf "%mu\r\n", poi(${address}+c)+8
}
}

How to set the name of a thread in Linux pthreads?

Use the prctl(2) function with the option PR_SET_NAME (see the docs).

Note that old versions of the docs are a bit confusing. They say

Set the process name for the calling process

but since threads are light weight processes (LWP) on Linux, one thread is one process in this case.

You can see the thread name with ps -o cmd or with:

cat /proc/$PID/task/$TID/comm

or in between the () of cat /proc/$PID/task/$TID/stat:

4223 (kjournald) S 1 1 1 0...

or from GDB info threads between double quotes:

* 1    Thread 0x7ffff7fc7700 (LWP 6575) "kjournald" 0x00007ffff78bc30d in nanosleep () at ../sysdeps/unix/syscall-template.S:84                                                                                  

p_thread set thread name not showing up in htop

I figured it out. I had a filter in htop, and that was hiding my named threads. Once I removed that filter, it showed.

Perl threads- can they be named uniquely? (Linux)

Update 2020-10-21:
I just discovered an even better way to achieve this - the actual linux syscall. https://man7.org/linux/man-pages/man2/prctl.2.html

Troels Liebe Bentsen has kindly contributed a module that handles this neatly.
https://metacpan.org/pod/Sys::Prctl

Far more seamless than fiddling with $0 !!!

Original Post content continues below....

ps -T -p 126193
PID SPID TTY TIME CMD
126193 126193 pts/11 00:00:00 test2.pl
126193 126194 pts/11 00:00:00 __thr1 #<--- now unique
126193 126195 pts/11 00:00:00 __thr2 #<--- now unique
top -H -p 126193

PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
126193 xxxxxxx+ 20 0 305948 7972 2244 S 0.0 0.0 0:00.01 test2.pl
126194 xxxxxxx+ 20 0 305948 7972 2244 S 0.0 0.0 0:00.00 __thr1
126195 xxxxxxx+ 20 0 305948 7972 2244 S 0.0 0.0 0:00.00 __thr2

##################

Thanks to @ikegami , I found a solution that will work.

Couple of small changes were needed in order to get keep the child threads alive, and also needed to stop the main thread from joining them back in. (Based on how it behaves, I assume that if the child threads reach the end of the sub they are spawned with, they are completely terminated and Linux cleans them up - even though the main thread hasn't called join on them yet.

To anyone else reading this page in future, I would love to know why each of pstree, ps, and top, all show a different result.

Any how, leaving this info and comparisons here in case its helpful to others.

End result:

  • Using ps command , it does NOT appear to be possible to get the modified name of the threads. It only shows the string of what the last thread that touched $0 set it to
  • Similarly, using pstree pstree -p -a -l 144741 also only shows the main thread as the name for each child, and does not show anything about the changes made by the threads
  • But, very fortunately, using top works!!!! top -H -b -p 180547 , which clearly shows the main thread, and all child threads by the name they set using $0

Example from ps:

app_sy+ 180547 131203 180547  0    3 18:08 pts/1    00:00:00 thr2
app_sy+ 180547 131203 180548 0 3 18:08 pts/1 00:00:00 thr2
app_sy+ 180547 131203 180549 0 3 18:08 pts/1 00:00:00 thr2

Example using pstree:

test.pl,180547
|-{test.pl},180548
`-{test.pl},180549

And the winner, using top -n 1 -H -b -p 180547 , which shows the distinct names applied to $0 by each thread successfully!!!!!!

top - 18:00:08 up 69 days,  8:53,  3 users,  load average: 4.10, 3.95, 4.05
Threads: 3 total, 0 running, 3 sleeping, 0 stopped, 0 zombie
%Cpu(s): 7.7 us, 33.5 sy, 0.0 ni, 58.8 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st
KiB Mem : 13144056+total, 1351640 free, 45880316 used, 84208608 buff/cache
KiB Swap: 16777212 total, 16777212 free, 0 used. 78196224 avail Mem

PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
180547 app_+ 20 0 299572 7152 2144 S 0.0 0.0 0:00.00 test.pl
180548 app_+ 20 0 299572 7152 2144 S 0.0 0.0 0:00.02 thr1
180549 app_+ 20 0 299572 7152 2144 S 0.0 0.0 0:00.01 thr2

Adding Modified version of Ikegami's code here for future reference for others looking at this page, saved as test.pl :

#!/usr/bin/perl

use strict;
use warnings;
use feature qw( say );
use threads;
use threads::shared;

my $phase :shared = 0;
my $main_pid = $$;
sub advance {
lock $phase;
++$phase;
cond_signal($phase);
}

sub wait_for {
lock $phase;
cond_wait($phase) while $phase != $_[0];
}

sub advance_and_wait_for {
lock $phase;
++$phase;
cond_signal($phase);
cond_wait($phase) while $phase != $_[0];
}

my $thr1 = async {
my $id = 'thr1';
wait_for(0);
advance_and_wait_for(2);
say "[$id] Setting \$0 to $id.";
$0 = $id;
say "[$id] \$0 = $0";
print `ps -eLf|grep $main_pid` =~ s/^/[$id] /mrg;
advance_and_wait_for(4);
say "[$id] \$0 = $0";
advance();
while(1){
sleep 1;
}
};

my $thr2 = async {
my $id = 'thr2';
wait_for(1);
advance_and_wait_for(3);
say "[$id] \$0 = $0";
say "[$id] Setting \$0 to $id.";
$0 = $id;
say "[$id] \$0 = $0";
print `ps -eLf| grep $main_pid` =~ s/^/[$id] /mrg;
advance();
while(1){
sleep 1;
}

};
sleep 5;
print "Main thread pid is $main_pid - and \$0 is ($0)\n";

my $waitfor = <STDIN>;

$_->join for $thr1, $thr2;


Related Topics



Leave a reply



Submit