aboutsummaryrefslogtreecommitdiffstats
path: root/gcc-4.9/libgcc/emutls.c
diff options
context:
space:
mode:
authorBen Cheng <bccheng@google.com>2014-03-25 22:37:19 -0700
committerBen Cheng <bccheng@google.com>2014-03-25 22:37:19 -0700
commit1bc5aee63eb72b341f506ad058502cd0361f0d10 (patch)
treec607e8252f3405424ff15bc2d00aa38dadbb2518 /gcc-4.9/libgcc/emutls.c
parent283a0bf58fcf333c58a2a92c3ebbc41fb9eb1fdb (diff)
downloadtoolchain_gcc-1bc5aee63eb72b341f506ad058502cd0361f0d10.tar.gz
toolchain_gcc-1bc5aee63eb72b341f506ad058502cd0361f0d10.tar.bz2
toolchain_gcc-1bc5aee63eb72b341f506ad058502cd0361f0d10.zip
Initial checkin of GCC 4.9.0 from trunk (r208799).
Change-Id: I48a3c08bb98542aa215912a75f03c0890e497dba
Diffstat (limited to 'gcc-4.9/libgcc/emutls.c')
-rw-r--r--gcc-4.9/libgcc/emutls.c203
1 files changed, 203 insertions, 0 deletions
diff --git a/gcc-4.9/libgcc/emutls.c b/gcc-4.9/libgcc/emutls.c
new file mode 100644
index 000000000..fd6d86ed9
--- /dev/null
+++ b/gcc-4.9/libgcc/emutls.c
@@ -0,0 +1,203 @@
+/* TLS emulation.
+ Copyright (C) 2006-2014 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 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"
+#include "gthr.h"
+
+typedef unsigned int word __attribute__((mode(word)));
+typedef unsigned int pointer __attribute__((mode(pointer)));
+
+struct __emutls_object
+{
+ word size;
+ word align;
+ union {
+ pointer offset;
+ void *ptr;
+ } loc;
+ 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;
+#else
+static __gthread_mutex_t emutls_mutex;
+#endif
+static __gthread_key_t emutls_key;
+static pointer emutls_size;
+
+static void
+emutls_destroy (void *ptr)
+{
+ struct __emutls_array *arr = ptr;
+ pointer size = arr->size;
+ pointer i;
+
+ for (i = 0; i < size; ++i)
+ {
+ if (arr->data[i])
+ free (arr->data[i][-1]);
+ }
+
+ free (ptr);
+}
+
+static void
+emutls_init (void)
+{
+#ifndef __GTHREAD_MUTEX_INIT
+ __GTHREAD_MUTEX_INIT_FUNCTION (&emutls_mutex);
+#endif
+ if (__gthread_key_create (&emutls_key, emutls_destroy) != 0)
+ abort ();
+}
+#endif
+
+static void *
+emutls_alloc (struct __emutls_object *obj)
+{
+ void *ptr;
+ void *ret;
+
+ /* We could use here posix_memalign if available and adjust
+ emutls_destroy accordingly. */
+ if (obj->align <= sizeof (void *))
+ {
+ ptr = malloc (obj->size + sizeof (void *));
+ if (ptr == NULL)
+ abort ();
+ ((void **) ptr)[0] = ptr;
+ ret = ptr + sizeof (void *);
+ }
+ else
+ {
+ ptr = malloc (obj->size + sizeof (void *) + obj->align - 1);
+ if (ptr == NULL)
+ abort ();
+ ret = (void *) (((pointer) (ptr + sizeof (void *) + obj->align - 1))
+ & ~(pointer)(obj->align - 1));
+ ((void **) ret)[-1] = ptr;
+ }
+
+ if (obj->templ)
+ memcpy (ret, obj->templ, obj->size);
+ else
+ memset (ret, 0, obj->size);
+
+ return ret;
+}
+
+void *
+__emutls_get_address (struct __emutls_object *obj)
+{
+ if (! __gthread_active_p ())
+ {
+ if (__builtin_expect (obj->loc.ptr == NULL, 0))
+ obj->loc.ptr = emutls_alloc (obj);
+ return obj->loc.ptr;
+ }
+
+#ifndef __GTHREADS
+ abort ();
+#else
+ pointer offset = __atomic_load_n (&obj->loc.offset, __ATOMIC_ACQUIRE);
+
+ 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 = obj->loc.offset;
+ if (offset == 0)
+ {
+ offset = ++emutls_size;
+ __atomic_store_n (&obj->loc.offset, offset, __ATOMIC_RELEASE);
+ }
+ __gthread_mutex_unlock (&emutls_mutex);
+ }
+
+ struct __emutls_array *arr = __gthread_getspecific (emutls_key);
+ if (__builtin_expect (arr == NULL, 0))
+ {
+ pointer size = offset + 32;
+ arr = calloc (size + 1, sizeof (void *));
+ if (arr == NULL)
+ abort ();
+ arr->size = size;
+ __gthread_setspecific (emutls_key, (void *) arr);
+ }
+ else if (__builtin_expect (offset > arr->size, 0))
+ {
+ pointer orig_size = arr->size;
+ pointer size = orig_size * 2;
+ if (offset > size)
+ size = offset + 32;
+ arr = realloc (arr, (size + 1) * sizeof (void *));
+ if (arr == NULL)
+ abort ();
+ arr->size = size;
+ memset (arr->data + orig_size, 0,
+ (size - orig_size) * sizeof (void *));
+ __gthread_setspecific (emutls_key, (void *) arr);
+ }
+
+ void *ret = arr->data[offset - 1];
+ if (__builtin_expect (ret == NULL, 0))
+ {
+ ret = emutls_alloc (obj);
+ arr->data[offset - 1] = ret;
+ }
+ return ret;
+#endif
+}
+
+void
+__emutls_register_common (struct __emutls_object *obj,
+ word size, word align, void *templ)
+{
+ if (obj->size < size)
+ {
+ obj->size = size;
+ obj->templ = NULL;
+ }
+ if (obj->align < align)
+ obj->align = align;
+ if (templ && size == obj->size)
+ obj->templ = templ;
+}