17494Sjkh/* This testcase is part of GDB, the GNU debugger. 27494Sjkh 37494Sjkh Copyright 2016-2023 Free Software Foundation, Inc. 47494Sjkh 57494Sjkh This program is free software; you can redistribute it and/or modify 67494Sjkh it under the terms of the GNU General Public License as published by 77494Sjkh the Free Software Foundation; either version 3 of the License, or 87494Sjkh (at your option) any later version. 97494Sjkh 107494Sjkh This program is distributed in the hope that it will be useful, 117494Sjkh but WITHOUT ANY WARRANTY; without even the implied warranty of 127494Sjkh MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 137494Sjkh GNU General Public License for more details. 147494Sjkh 157494Sjkh You should have received a copy of the GNU General Public License 167494Sjkh along with this program. If not, see <http://www.gnu.org/licenses/>. */ 177494Sjkh 187494Sjkh#define _GNU_SOURCE 197494Sjkh#include <stdlib.h> 207494Sjkh#include <unistd.h> 217494Sjkh#include <sched.h> 227494Sjkh#include <pthread.h> 237494Sjkh 247494Sjkhstatic void 257494Sjkhmarker () 267494Sjkh{} 277494Sjkh 287494Sjkh#define STACK_SIZE 0x1000 2965437Sphantom 30142665Sphantom/* These are used to signal that the threads have started correctly. The 317494Sjkh GLOBAL_THREAD_COUNT is set to the number of threads in main, then 327494Sjkh decremented (under a lock) in each new thread. */ 337494Sjkhpthread_mutex_t global_lock = PTHREAD_MUTEX_INITIALIZER; 347494Sjkhint global_thread_count = 0; 3579754Sdd 3659460Sphantomstatic int 3759460Sphantomclone_fn (void *unused) 387494Sjkh{ 3984306Sru /* Signal that this thread has started correctly. */ 407494Sjkh if (pthread_mutex_lock (&global_lock) != 0) 417494Sjkh abort (); 427494Sjkh global_thread_count--; 4379754Sdd if (pthread_mutex_unlock (&global_lock) != 0) 447494Sjkh abort (); 457494Sjkh 4679754Sdd return 0; 477494Sjkh} 487494Sjkh 497494Sjkhint 507494Sjkhmain (void) 5179754Sdd{ 5279754Sdd int i, pid; 537494Sjkh unsigned char *stack[6]; 5479754Sdd 557494Sjkh /* Due to bug gdb/19675 the cloned thread _might_ try to reenter main 5679754Sdd (this depends on where the displaced instruction is placed for 5779754Sdd execution). However, if we do reenter main then lets ensure we fail 5865485Sache hard rather then just silently executing the code below. */ 5965485Sache static int started = 0; 6065485Sache if (!started) 6165485Sache started = 1; 627494Sjkh else 6365485Sache abort (); 6465485Sache 6565485Sache for (i = 0; i < (sizeof (stack) / sizeof (stack[0])); i++) 6665485Sache stack[i] = malloc (STACK_SIZE); 6765485Sache 6865485Sache global_thread_count = (sizeof (stack) / sizeof (stack[0])); 6965485Sache 7065485Sache for (i = 0; i < (sizeof (stack) / sizeof (stack[0])); i++) 7165485Sache { 7265485Sache pid = clone (clone_fn, stack[i] + STACK_SIZE, CLONE_FILES | CLONE_VM, 7365485Sache NULL); 7465485Sache } 7565485Sache 7665485Sache for (i = 0; i < (sizeof (stack) / sizeof (stack[0])); i++) 7765485Sache free (stack[i]); 7865485Sache 7965485Sache /* Set an alarm so we don't end up stuck waiting for threads that might 8065485Sache never start correctly. */ 8165485Sache alarm (120); 8265485Sache 8365485Sache /* Now wait for all the threads to start up. */ 8465485Sache while (global_thread_count != 0) 8565485Sache { 8665485Sache /* Force memory barrier so GLOBAL_THREAD_COUNT will be refetched. */ 8765485Sache asm volatile ("" ::: "memory"); 8865485Sache sleep (1); 8979754Sdd } 9065485Sache 917494Sjkh /* Call marker, this is what GDB is waiting for. */ 9265485Sache marker (); 9365485Sache} 9465485Sache