Viewing file: generic-morestack-thread.c (5.19 KB) -rw-r--r-- Select action/file-type: (+) | (+) | (+) | Code (+) | Session (+) | (+) | SDB (+) | (+) | (+) | (+) | (+) | (+) |
/* Thread library support for -fsplit-stack. */ /* Copyright (C) 2009-2022 Free Software Foundation, Inc. Contributed by Ian Lance Taylor <iant@google.com>.
This file is part of GCC.
GCC is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version.
GCC is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
Under Section 7 of GPL version 3, you are granted additional permissions described in the GCC Runtime Library Exception, version 3.1, as published by the Free Software Foundation.
You should have received a copy of the GNU General Public License and a copy of the GCC Runtime Library Exception along with this program; see the files COPYING3 and COPYING.RUNTIME respectively. If not, see <http://www.gnu.org/licenses/>. */
#include "tconfig.h" #include "tsystem.h" #include "coretypes.h" #include "tm.h" #include "libgcc_tm.h"
/* If inhibit_libc is defined, we cannot compile this file. The effect is that people will not be able to use -fsplit-stack. That is much better than failing the build particularly since people will want to define inhibit_libc while building a compiler which can build glibc. */
#ifndef inhibit_libc
#include <errno.h> #include <signal.h> #include <pthread.h>
#include "generic-morestack.h"
/* We declare the pthread functions we need as weak, so that libgcc_s.so does not need to be linked against -lpthread. */
extern int pthread_once (pthread_once_t *, void (*) (void)) __attribute__ ((weak));
extern int pthread_key_create (pthread_key_t *, void (*) (void *)) __attribute__ ((weak));
extern int pthread_setspecific (pthread_key_t, const void *) __attribute__ ((weak));
extern int pthread_sigmask (int, const sigset_t *, sigset_t *) __attribute__ ((weak));
/* The key for the list of stack segments to free when the thread exits. This is created by pthread_key_create. */
static pthread_key_t segment_list_key;
/* Used to only run create_key once. */
static pthread_once_t create_key_once = PTHREAD_ONCE_INIT;
/* Release all the segments for a thread. This is the destructor function used by pthread_key_create, and is called when a thread exits. */
static void free_segments (void* arg) { /* We must block signals in case the signal handler tries to split the stack. We leave them blocked while the thread exits. */ if (pthread_sigmask) { sigset_t mask;
sigfillset (&mask); pthread_sigmask (SIG_BLOCK, &mask, NULL); }
__morestack_release_segments ((struct stack_segment **) arg, 1); }
/* Set up the key for the list of segments. This is called via pthread_once. */
static void create_key (void) { int err;
err = pthread_key_create (&segment_list_key, free_segments); if (err != 0) { static const char msg[] = "pthread_key_create failed: errno "; __morestack_fail (msg, sizeof msg - 1, err); } }
/* Pass information from the pthread_create wrapper to stack_split_initialize_thread. */
struct pthread_create_args { void *(*start_routine) (void *); void *arg; };
/* Initialize a thread. This is called via pthread_create. It calls a target dependent function to set up any required stack guard. */
static void* stack_split_initialize_thread (void *) __attribute__ ((no_split_stack));
static void * stack_split_initialize_thread (void *varg) { struct pthread_create_args *args = (struct pthread_create_args *) varg; int err; void *(*start_routine) (void *); void *arg;
__stack_split_initialize ();
err = pthread_setspecific (segment_list_key, (void *) &__morestack_segments); if (err != 0) { static const char msg[] = "pthread_setspecific failed: errno "; __morestack_fail (msg, sizeof msg - 1, err); }
start_routine = args->start_routine; arg = args->arg; free (args); return (*start_routine) (arg); }
/* This function wraps calls to pthread_create to make sure that the stack guard is initialized for new threads. FIXME: This hack will not be necessary if glibc supports -fsplit-stack directly. */
int __wrap_pthread_create (pthread_t *, const pthread_attr_t *, void *(*start_routine) (void *), void *) __attribute__ ((visibility ("hidden")));
extern int __real_pthread_create (pthread_t *, const pthread_attr_t *, void *(*start_routine) (void *), void *) __attribute__ ((weak));
int __wrap_pthread_create (pthread_t *tid, const pthread_attr_t *attr, void *(*start_routine) (void *), void *arg) { int err; struct pthread_create_args* args;
err = pthread_once (&create_key_once, create_key); if (err != 0) { static const char msg[] = "pthread_once failed: errno "; __morestack_fail (msg, sizeof msg - 1, err); }
args = malloc (sizeof (struct pthread_create_args)); if (args == NULL) return EAGAIN; args->start_routine = start_routine; args->arg = arg; return __real_pthread_create (tid, attr, stack_split_initialize_thread, args); }
#endif /* !defined (inhibit_libc) */
|