At SingleStore, we are out to build awesome software and we’re always trying to solve hard problems. A few days ago, I uncovered a cool Linux mystery with some colleagues and fixed it. We thought sharing that experience might benefit others.

The scene of the crimeWhile developing an internal tool to get stack traces, we decided to use the `SYS_tgkill`t

tgkill
t
tgid
t
tid
t

t

tgid
t
/proc/self/status
t

cat /proc/self/status
Name:   cat
State:  R (running)
Tgid:   26473
Ngid:   0
Pid:    26473
PPid:   26378
... <snip> ...

The first prototype of this internal tool used the `SYS_getpid`t

tgid
t

This worked for most developers at SingleStore, but some developers were running environments with newer Linux distributions and it didn’t seem to work in those instances.

t

/proc/self/status
tbeforet
Tgid
t

commit 3e42979e65dace1f9268dd5440e5ab096b8dee59
Author: Richard W.M. Jones <rjones@redhat.com>
Date:   Fri May 20 17:00:05 2016 -0700
   procfs: expose umask in /proc/<PID>/status
... <snip> ...
--- a/fs/proc/array.c
+++ b/fs/proc/array.c
@@ -162,6 +176,10 @@ static inline void task_state(struct seq_file *m, struct pid_namespace *ns,
       ngid = task_numa_group_id(p);
       cred = get_task_cred(p);
+       umask = get_task_umask(p);
+       if (umask >= 0)
+               seq_printf(m, "Umask:\t%#04o\n", umask);
+
       task_lock(p);
       if (p->files)
               max_fds = files_fdtable(p->files)->max_fds;
       task_unlock(p);
       rcu_read_unlock();
       seq_printf(m,
               "State:\t%s\n"
               "Tgid:\t%d\n"
               "Ngid:\t%d\n"

The motive
t

tgid
t
pid
tLinux reference on thread groups states:

Thread groups were a feature added in Linux 2.4 to support the POSIX threads notion of a set of threads that share a single PID. Internally, this shared PID is the so-called thread group identifier (TGID) for the thread group. Since Linux 2.4, calls to getpid(2) return the TGID of the caller.

t

/proc/self/status
t
Tgid
t
Pid
t

The culprit
t

/proc/self/status
t
fs/proc/array.c
t
Tgid
t
Pid
t

tgid = task_tgid_nr_ns(p, ns);
... <snip> ...
seq_put_decimal_ull(m, "\nTgid:\t", tgid);
seq_put_decimal_ull(m, "\nNgid:\t", ngid);
seq_put_decimal_ull(m, "\nPid:\t", pid_nr_ns(pid, ns));

t

task_tgid_nr_ns
t
kernel/pid.c
t
Pid
t
Tgid
t

pid_t task_tgid_nr_ns(struct task_struct *tsk, struct pid_namespace *ns){return pid_nr_ns(task_tgid(tsk), ns);} EXPORT_SYMBOL(task_tgid_nr_ns);

t

task_tgid
t
include/linux/sched.h
t
pid
t

static inline struct pid *task_tgid(struct task_struct *task){return task->group_leader->pids[PIDTYPE_PID].pid;} 

Elementary, my dear Watsont

status
t
getpid
t