Subversion Repositories Kolibri OS

Rev

Blame | Last modification | View Log | RSS feed

  1. /* Thread library support for -fsplit-stack.  */
  2. /* Copyright (C) 2009-2015 Free Software Foundation, Inc.
  3.    Contributed by Ian Lance Taylor <iant@google.com>.
  4.  
  5. This file is part of GCC.
  6.  
  7. GCC is free software; you can redistribute it and/or modify it under
  8. the terms of the GNU General Public License as published by the Free
  9. Software Foundation; either version 3, or (at your option) any later
  10. version.
  11.  
  12. GCC is distributed in the hope that it will be useful, but WITHOUT ANY
  13. WARRANTY; without even the implied warranty of MERCHANTABILITY or
  14. FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  15. for more details.
  16.  
  17. Under Section 7 of GPL version 3, you are granted additional
  18. permissions described in the GCC Runtime Library Exception, version
  19. 3.1, as published by the Free Software Foundation.
  20.  
  21. You should have received a copy of the GNU General Public License and
  22. a copy of the GCC Runtime Library Exception along with this program;
  23. see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
  24. <http://www.gnu.org/licenses/>.  */
  25.  
  26. #include "tconfig.h"
  27. #include "tsystem.h"
  28. #include "coretypes.h"
  29. #include "tm.h"
  30. #include "libgcc_tm.h"
  31.  
  32. /* If inhibit_libc is defined, we can not compile this file.  The
  33.    effect is that people will not be able to use -fsplit-stack.  That
  34.    is much better than failing the build particularly since people
  35.    will want to define inhibit_libc while building a compiler which
  36.    can build glibc.  */
  37.  
  38. #ifndef inhibit_libc
  39.  
  40. #include <errno.h>
  41. #include <pthread.h>
  42.  
  43. #include "generic-morestack.h"
  44.  
  45. /* We declare the pthread functions we need as weak, so that
  46.    libgcc_s.so does not need to be linked against -lpthread.  */
  47.  
  48. extern int pthread_once (pthread_once_t *, void (*) (void))
  49.   __attribute__ ((weak));
  50.  
  51. extern int pthread_key_create (pthread_key_t *, void (*) (void *))
  52.   __attribute__ ((weak));
  53.  
  54. extern int pthread_setspecific (pthread_key_t, const void *)
  55.   __attribute__ ((weak));
  56.  
  57. /* The key for the list of stack segments to free when the thread
  58.    exits.  This is created by pthread_key_create.  */
  59.  
  60. static pthread_key_t segment_list_key;
  61.  
  62. /* Used to only run create_key once.  */
  63.  
  64. static pthread_once_t create_key_once = PTHREAD_ONCE_INIT;
  65.  
  66. /* Release all the segments for a thread.  This is the destructor
  67.    function used by pthread_key_create, and is called when a thread
  68.    exits.  */
  69.  
  70. static void
  71. free_segments (void* arg)
  72. {
  73.   __morestack_release_segments ((struct stack_segment **) arg, 1);
  74. }
  75.  
  76. /* Set up the key for the list of segments.  This is called via
  77.    pthread_once.  */
  78.  
  79. static void
  80. create_key (void)
  81. {
  82.   int err;
  83.  
  84.   err = pthread_key_create (&segment_list_key, free_segments);
  85.   if (err != 0)
  86.     {
  87.       static const char msg[] = "pthread_key_create failed: errno ";
  88.       __morestack_fail (msg, sizeof msg - 1, err);
  89.     }
  90. }
  91.  
  92. /* Pass information from the pthread_create wrapper to
  93.    stack_split_initialize_thread.  */
  94.  
  95. struct pthread_create_args
  96. {
  97.   void *(*start_routine) (void *);
  98.   void *arg;
  99. };
  100.  
  101. /* Initialize a thread.  This is called via pthread_create.  It calls
  102.    a target dependent function to set up any required stack guard.  */
  103.  
  104. static void* stack_split_initialize_thread (void *)
  105.   __attribute__ ((no_split_stack));
  106.  
  107. static void *
  108. stack_split_initialize_thread (void *varg)
  109. {
  110.   struct pthread_create_args *args = (struct pthread_create_args *) varg;
  111.   int err;
  112.   void *(*start_routine) (void *);
  113.   void *arg;
  114.  
  115.   __stack_split_initialize ();
  116.  
  117.   err = pthread_setspecific (segment_list_key, (void *) &__morestack_segments);
  118.   if (err != 0)
  119.     {
  120.       static const char msg[] = "pthread_setspecific failed: errno ";
  121.       __morestack_fail (msg, sizeof msg - 1, err);
  122.     }
  123.  
  124.   start_routine = args->start_routine;
  125.   arg = args->arg;
  126.   free (args);
  127.   return (*start_routine) (arg);
  128. }
  129.  
  130. /* This function wraps calls to pthread_create to make sure that the
  131.    stack guard is initialized for new threads.  FIXME: This hack will
  132.    not be necessary if glibc supports -fsplit-stack directly.  */
  133.  
  134. int __wrap_pthread_create (pthread_t *, const pthread_attr_t *,
  135.                            void *(*start_routine) (void *), void *)
  136.   __attribute__ ((visibility ("hidden")));
  137.  
  138. extern int __real_pthread_create (pthread_t *, const pthread_attr_t *,
  139.                                   void *(*start_routine) (void *), void *)
  140.   __attribute__ ((weak));
  141.  
  142. int
  143. __wrap_pthread_create (pthread_t *tid, const pthread_attr_t *attr,
  144.                        void *(*start_routine) (void *), void *arg)
  145. {
  146.   int err;
  147.   struct pthread_create_args* args;
  148.  
  149.   err = pthread_once (&create_key_once, create_key);
  150.   if (err != 0)
  151.     {
  152.       static const char msg[] = "pthread_once failed: errno ";
  153.       __morestack_fail (msg, sizeof msg - 1, err);
  154.     }
  155.  
  156.   args = malloc (sizeof (struct pthread_create_args));
  157.   if (args == NULL)
  158.     return EAGAIN;
  159.   args->start_routine = start_routine;
  160.   args->arg = arg;
  161.   return __real_pthread_create (tid, attr, stack_split_initialize_thread, args);
  162. }
  163.  
  164. #endif /* !defined (inhibit_libc) */
  165.