이 코드가 코드 16으로 종료되는 이유는 무엇입니까?

이 코드가 코드 16으로 종료되는 이유는 무엇입니까?

스레드를 생성하기 위해 clone() 시스템 호출을 사용하려고 합니다. 그러나 프로그램은 t2_thread() 함수에서 반환되면 자체적으로 종료됩니다. 왜 이런 문제가 발생합니까? 내가 무엇을 놓치고 있나요?

#define _GNU_SOURCE
#include<sys/syscall.h>
#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
#include<errno.h>
#include<sched.h>

int t2_thread(void *arg)
{
        printf("Thread 2 (%ld)\n",syscall(SYS_gettid));
        return;
}
int main(int argc, char **argv)
{
        const size_t STCK_SZ = 65536;
        char *stck;
        int flags;
        stck = malloc(STCK_SZ);
        if(stck == NULL)
        {
                perror("malloc");
                exit(EXIT_FAILURE);
        }
        flags = CLONE_SIGHAND |CLONE_FS |CLONE_VM |CLONE_FILES | CLONE_THREAD;
        if(clone(t2_thread, stck + STCK_SZ, flags, NULL)==-1)
        {
                perror("clone");
                exit(EXIT_FAILURE);
        }

        printf("Thread 1 (%ld)\n",syscall(SYS_gettid));

        for(;;)
        {
                printf("T1\n");
                sleep(1);
        }
        exit(EXIT_SUCCESS);
}

그런데 이 프로그램의 출력은 다음과 같습니다.

Thread 1 (8963)
T1
Thread 2 (8964)

$echo $?
16

for 루프를 무한히 실행하려면 어떻게 해야 하나요?

답변1

2.26 이전의 GNU libc 버전과 x86_64를 포함한 일부 아키텍처에서 libc는 전달된 함수 (매개변수로 값을 반환하므로 임의의 16을 전달하지 않음) 에서 반환된 후 clone()결국 호출됩니다 . 이로 인해 모든 스레드( 전체 exit_group()프로세스)이 종료됩니다.

그것은 고정되어있다이번에 제출하세요(바라보다해당 오류 보고서).

commit 3f823e87ccbf3723eb4eeb63b0619f1a0ceb174e
Author: Adhemerval Zanella <[email protected]>
Date:   Thu Jun 22 08:49:34 2017 -0300

   Call exit directly in clone (BZ #21512)

   On aarch64, alpha, arm, hppa, mips, nios2, powerpc, sh, sparc, tile,
   and x86_64 the clone syscall jumps to _exit after the child execution
   and the function ends the process execution by calling exit_group.
   This behavior have a small issue where threads created with
   CLONE_THREAD using clone syscall directly will eventually exit the
   whole group altogether instead of just the thread created.  Also,
   s390, microblaze, ia64, i386, and m68k differs by calling exit
   syscall directly.

   This patch changes all architectures to call the exit syscall
   directly, as for s390, microblaze, ia64, i386, and m68k.  This do not
   have change glibc internal behavior in any sort, since the only
   usage of clone implementation in posix_spawn calls _exit directly
   in the created child (fork uses a direct call to clone).

   Checked on x86_64-linux-gnu, i686-linux-gnu, aarch64-linux-gnu,
   powerpc-linux-gnu, powerpc64le-linux-gnu, sparc64-linux-gnu,
   and sparcv9-linux-gnu.

exit이전 버전의 경우 syscall( syscall(SYS_exit, 0))을 직접 호출하여 이 문제를 해결할 수 있습니다 return. 또는 함수를 수정하지 않으려면 다음 clone()과 같이 정의된 래퍼 함수를 ​​전달하세요.

int wrapper(void *arg)
{
  syscall(SYS_exit, t2_thread(arg));
  return 0; /* never reached */
}

관련 정보