OSDN Git Service

2010-06-18 Jerry DeLisle <jvdelisle@gcc.gnu.org>
[pf3gnuchains/gcc-fork.git] / gcc / emutls.c
index f26d217..b7ee3bd 100644 (file)
@@ -1,32 +1,27 @@
 /* TLS emulation.
-   Copyright (C) 2006 Free Software Foundation, Inc.
+   Copyright (C) 2006, 2008, 2009 Free Software Foundation, Inc.
    Contributed by Jakub Jelinek <jakub@redhat.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 2, or (at your option) any later
+Software Foundation; either version 3, or (at your option) any later
 version.
 
-In addition to the permissions in the GNU General Public License, the
-Free Software Foundation gives you unlimited permission to link the
-compiled version of this file into combinations with other programs,
-and to distribute those combinations without any restriction coming
-from the use of this file.  (The General Public License restrictions
-do apply in other respects; for example, they cover modification of
-the file, and distribution when not linked into a combine
-executable.)
-
 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.
 
-You should have received a copy of the GNU General Public License
-along with GCC; see the file COPYING.  If not, write to the Free
-Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
-02110-1301, USA.  */
+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"
@@ -48,6 +43,15 @@ struct __emutls_object
   void *templ;
 };
 
+struct __emutls_array
+{
+  pointer size;
+  void **data[];
+};
+
+void *__emutls_get_address (struct __emutls_object *);
+void __emutls_register_common (struct __emutls_object *, word, word, void *);
+
 #ifdef __GTHREADS
 #ifdef __GTHREAD_MUTEX_INIT
 static __gthread_mutex_t emutls_mutex = __GTHREAD_MUTEX_INIT;
@@ -60,15 +64,16 @@ static pointer emutls_size;
 static void
 emutls_destroy (void *ptr)
 {
-  void ***arr = (void ***) ptr;
-  unsigned long int size = (unsigned long int) arr[0];
-  ++arr;
-  while (--size)
+  struct __emutls_array *arr = ptr;
+  pointer size = arr->size;
+  pointer i;
+
+  for (i = 0; i < size; ++i)
     {
-      if (*arr)
-       free ((*arr)[-1]);
-      ++arr;
+      if (arr->data[i])
+       free (arr->data[i][-1]);
     }
+
   free (ptr);
 }
 
@@ -130,48 +135,52 @@ __emutls_get_address (struct __emutls_object *obj)
 #ifndef __GTHREADS
   abort ();
 #else
-  pointer offset;
+  pointer offset = obj->loc.offset;
 
-  if (__builtin_expect (obj->loc.offset == 0, 0))
+  if (__builtin_expect (offset == 0, 0))
     {
       static __gthread_once_t once = __GTHREAD_ONCE_INIT;
       __gthread_once (&once, emutls_init);
       __gthread_mutex_lock (&emutls_mutex);
-      offset = ++emutls_size;
-      obj->loc.offset = offset;
+      offset = obj->loc.offset;
+      if (offset == 0)
+       {
+         offset = ++emutls_size;
+         obj->loc.offset = offset;
+       }
       __gthread_mutex_unlock (&emutls_mutex);
     }
-  else
-    offset = obj->loc.offset;
 
-  void **arr = (void **) __gthread_getspecific (emutls_key);
+  struct __emutls_array *arr = __gthread_getspecific (emutls_key);
   if (__builtin_expect (arr == NULL, 0))
     {
       pointer size = offset + 32;
-      arr = calloc (size, sizeof (void *));
+      arr = calloc (size + 1, sizeof (void *));
       if (arr == NULL)
        abort ();
-      arr[0] = (void *) size;
+      arr->size = size;
       __gthread_setspecific (emutls_key, (void *) arr);
     }
-  else if (__builtin_expect (offset >= (pointer) arr[0], 0))
+  else if (__builtin_expect (offset > arr->size, 0))
     {
-      pointer orig_size = (pointer) arr[0];
+      pointer orig_size = arr->size;
       pointer size = orig_size * 2;
-      if (offset >= size)
+      if (offset > size)
        size = offset + 32;
-      arr = realloc (arr, size * sizeof (void *));
+      arr = realloc (arr, (size + 1) * sizeof (void *));
       if (arr == NULL)
        abort ();
-      memset (arr + orig_size, 0, (size - orig_size) * sizeof (void *));
+      arr->size = size;
+      memset (arr->data + orig_size, 0,
+             (size - orig_size) * sizeof (void *));
       __gthread_setspecific (emutls_key, (void *) arr);
     }
 
-  void *ret = arr[offset];
+  void *ret = arr->data[offset - 1];
   if (__builtin_expect (ret == NULL, 0))
     {
       ret = emutls_alloc (obj);
-      arr[offset] = ret;
+      arr->data[offset - 1] = ret;
     }
   return ret;
 #endif