123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204 |
- /* TLS emulation.
- Copyright (C) 2006-2015 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;
- }
|