CLONE_THREAD
cloneシステムコールをCLONE_THREADフラグによるpid/tid/sid/gidの検証サンプルです。
pidとgidが同じプロセスはグループリーダとなります。シェルがコマンドを起動する時、fork/cloneでプロセスを作成し、シェルがそのプロセスのgidをpidで更新して後、execで差し替えていると思います。(execが差し替えてるのかもしれません・・・)シェルで起動したコマンドプロセス毎に独自のpidをgidに設定することで、、以降の子プロセスはこのgidを継承することで、シェルコマンド下単位での管理が可能となります。
CLONE_THREADフラグは、 CLONE_SIGHANDが設定されてなければなりません。そしてCLONE_SIGHANDフラグは、CLONE_VMが設定されなければなりません。CLONE_THREADはCLONE_SIGHAND/CLONE_VMが設定されなければ、cloneはエラーとなります。
CLONE_SIGHANDはシグナル・ハン ドラを共有しますが、親プロセスのcurrent->sighand->countインクリメントするだけで、CLONE_VMはp->mm = current->mm/p->active_mm = current->mmとし、親プロセスのメモリ空間を共有します。故にCLONE_SIGHANDはcurrent->sighand->countインクリメントするだけでシグナルハンドラの共有が可能となり、CLONE_SIGHANDフラグは、CLONE_VMが設定されなければなりません。
#define _GNU_SOURCE
#include <sched.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/syscall.h>
#define STACK_SIZE (1024 * 1024)
void get_pid(char *);
static int childFunc(void *arg)
{
get_pid("clone");
return 0;
}
int main(int argc, char *argv[])
{
char *stack;
char *stackTop;
pid_t pid;
stack = malloc(STACK_SIZE);
stackTop = stack + STACK_SIZE;
if(argc == 2) {
get_pid("thread parent");
pid = clone(childFunc, stackTop, CLONE_THREAD | CLONE_SIGHAND | CLONE_VM, NULL);
}
else {
get_pid("parent");
pid = clone(childFunc, stackTop, 0, NULL);
}
sleep(1);
waitpid(pid, NULL, 0);
exit(EXIT_SUCCESS);
}
void get_pid(char* p)
{
printf("%-20s: pid=%d, tid=%d, sid=%d gid=%d\n",
p,
syscall(SYS_getpid),
syscall(SYS_gettid),
syscall(SYS_getsid, 0),
syscall(SYS_getpgid, 0));
}
SYS_getpid/SYS_gettid/SYS_getsid/SYS_getpgidシステムコールは以下の通りです。pid=task->group_leader->pids[PIDTYPE_PID].pid tid=task->pids[PIDTYPE_PID].pid sid=task->group_leader->pids[PIDTYPE_SID].pid; gid=task->group_leader->pids[PIDTYPE_PGID].pid;
結果
[root@localhost test]# ./a.out parent : pid=3415, tid=3415, sid=3222 gid=3415 clone : pid=3416, tid=3416, sid=3222 gid=3415CLONE_THREADでない時、クーロン作成時、 p->group_leader = pで、p->pids[PIDTYPE_PID]にプロセス自身のIDが、p->pids[PIDTYPE_PGID]にcurrent->pids[PIDTYPE_PGID]が、p->pids[PIDTYPE_SID]にcurrent->pids[PIDTYPE_SID]が設定されます。pidとtidはプロセス自身のI同で、sid/gidは親プロセスを継承します。CLONE_THREADならpidとtidは同値になります。
[root@localhost test]# ./a.out THREAD thread parent : pid=3425, tid=3425, sid=3222 gid=3425 clone : pid=3425, tid=3426, sid=3222 gid=3425CLONE_THREADの時、p->group_leader = current->group_leaderで、p->pids[PIDTYPE_PID]のみプロセス自身のIDが設定されます。従ってpid/tid/sid/gidは親のそれを継承します。pidとtidが異なるプロセスはCLONE_THREADである。と言う事です。pidが同じで、そのpidとtidプロセスが違うプロセス等は、pidのプロセスからCLONE_THREADで作成されたプロセスと言う事です。
補足
検証結果のparent/hread parentのgidは、pidと同じです。forkからcloneをコールすると、必ずgidは親のgidを継承しますが、シェルコマンドでのgidはカレントのpidと同じで、親(シェル)のgidを継承していません。pidとgidが同じプロセスはグループリーダとなります。シェルがコマンドを起動する時、fork/cloneでプロセスを作成し、シェルがそのプロセスのgidをpidで更新して後、execで差し替えていると思います。(execが差し替えてるのかもしれません・・・)シェルで起動したコマンドプロセス毎に独自のpidをgidに設定することで、、以降の子プロセスはこのgidを継承することで、シェルコマンド下単位での管理が可能となります。
CLONE_THREADフラグは、 CLONE_SIGHANDが設定されてなければなりません。そしてCLONE_SIGHANDフラグは、CLONE_VMが設定されなければなりません。CLONE_THREADはCLONE_SIGHAND/CLONE_VMが設定されなければ、cloneはエラーとなります。
CLONE_SIGHANDはシグナル・ハン ドラを共有しますが、親プロセスのcurrent->sighand->countインクリメントするだけで、CLONE_VMはp->mm = current->mm/p->active_mm = current->mmとし、親プロセスのメモリ空間を共有します。故にCLONE_SIGHANDはcurrent->sighand->countインクリメントするだけでシグナルハンドラの共有が可能となり、CLONE_SIGHANDフラグは、CLONE_VMが設定されなければなりません。






