Subversion Repositories Kolibri OS

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
6515 serge 1
/* TLS emulation.
2
   Copyright (C) 2006-2015 Free Software Foundation, Inc.
3
   Contributed by Jakub Jelinek .
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
.  */
25
 
26
#include "tconfig.h"
27
#include "tsystem.h"
28
#include "coretypes.h"
29
#include "tm.h"
30
#include "libgcc_tm.h"
31
#include "gthr.h"
32
 
33
typedef unsigned int word __attribute__((mode(word)));
34
typedef unsigned int pointer __attribute__((mode(pointer)));
35
 
36
struct __emutls_object
37
{
38
  word size;
39
  word align;
40
  union {
41
    pointer offset;
42
    void *ptr;
43
  } loc;
44
  void *templ;
45
};
46
 
47
struct __emutls_array
48
{
49
  pointer size;
50
  void **data[];
51
};
52
 
53
void *__emutls_get_address (struct __emutls_object *);
54
void __emutls_register_common (struct __emutls_object *, word, word, void *);
55
 
56
#ifdef __GTHREADS
57
#ifdef __GTHREAD_MUTEX_INIT
58
static __gthread_mutex_t emutls_mutex = __GTHREAD_MUTEX_INIT;
59
#else
60
static __gthread_mutex_t emutls_mutex;
61
#endif
62
static __gthread_key_t emutls_key;
63
static pointer emutls_size;
64
 
65
static void
66
emutls_destroy (void *ptr)
67
{
68
  struct __emutls_array *arr = ptr;
69
  pointer size = arr->size;
70
  pointer i;
71
 
72
  for (i = 0; i < size; ++i)
73
    {
74
      if (arr->data[i])
75
	free (arr->data[i][-1]);
76
    }
77
 
78
  free (ptr);
79
}
80
 
81
static void
82
emutls_init (void)
83
{
84
#ifndef __GTHREAD_MUTEX_INIT
85
  __GTHREAD_MUTEX_INIT_FUNCTION (&emutls_mutex);
86
#endif
87
  if (__gthread_key_create (&emutls_key, emutls_destroy) != 0)
88
    abort ();
89
}
90
#endif
91
 
92
static void *
93
emutls_alloc (struct __emutls_object *obj)
94
{
95
  void *ptr;
96
  void *ret;
97
 
98
  /* We could use here posix_memalign if available and adjust
99
     emutls_destroy accordingly.  */
100
  if (obj->align <= sizeof (void *))
101
    {
102
      ptr = malloc (obj->size + sizeof (void *));
103
      if (ptr == NULL)
104
	abort ();
105
      ((void **) ptr)[0] = ptr;
106
      ret = ptr + sizeof (void *);
107
    }
108
  else
109
    {
110
      ptr = malloc (obj->size + sizeof (void *) + obj->align - 1);
111
      if (ptr == NULL)
112
	abort ();
113
      ret = (void *) (((pointer) (ptr + sizeof (void *) + obj->align - 1))
114
		      & ~(pointer)(obj->align - 1));
115
      ((void **) ret)[-1] = ptr;
116
    }
117
 
118
  if (obj->templ)
119
    memcpy (ret, obj->templ, obj->size);
120
  else
121
    memset (ret, 0, obj->size);
122
 
123
  return ret;
124
}
125
 
126
void *
127
__emutls_get_address (struct __emutls_object *obj)
128
{
129
  if (! __gthread_active_p ())
130
    {
131
      if (__builtin_expect (obj->loc.ptr == NULL, 0))
132
	obj->loc.ptr = emutls_alloc (obj);
133
      return obj->loc.ptr;
134
    }
135
 
136
#ifndef __GTHREADS
137
  abort ();
138
#else
139
  pointer offset = __atomic_load_n (&obj->loc.offset, __ATOMIC_ACQUIRE);
140
 
141
  if (__builtin_expect (offset == 0, 0))
142
    {
143
      static __gthread_once_t once = __GTHREAD_ONCE_INIT;
144
      __gthread_once (&once, emutls_init);
145
      __gthread_mutex_lock (&emutls_mutex);
146
      offset = obj->loc.offset;
147
      if (offset == 0)
148
	{
149
	  offset = ++emutls_size;
150
	  __atomic_store_n (&obj->loc.offset, offset, __ATOMIC_RELEASE);
151
	}
152
      __gthread_mutex_unlock (&emutls_mutex);
153
    }
154
 
155
  struct __emutls_array *arr = __gthread_getspecific (emutls_key);
156
  if (__builtin_expect (arr == NULL, 0))
157
    {
158
      pointer size = offset + 32;
159
      arr = calloc (size + 1, sizeof (void *));
160
      if (arr == NULL)
161
	abort ();
162
      arr->size = size;
163
      __gthread_setspecific (emutls_key, (void *) arr);
164
    }
165
  else if (__builtin_expect (offset > arr->size, 0))
166
    {
167
      pointer orig_size = arr->size;
168
      pointer size = orig_size * 2;
169
      if (offset > size)
170
	size = offset + 32;
171
      arr = realloc (arr, (size + 1) * sizeof (void *));
172
      if (arr == NULL)
173
	abort ();
174
      arr->size = size;
175
      memset (arr->data + orig_size, 0,
176
	      (size - orig_size) * sizeof (void *));
177
      __gthread_setspecific (emutls_key, (void *) arr);
178
    }
179
 
180
  void *ret = arr->data[offset - 1];
181
  if (__builtin_expect (ret == NULL, 0))
182
    {
183
      ret = emutls_alloc (obj);
184
      arr->data[offset - 1] = ret;
185
    }
186
  return ret;
187
#endif
188
}
189
 
190
void
191
__emutls_register_common (struct __emutls_object *obj,
192
			  word size, word align, void *templ)
193
{
194
  if (obj->size < size)
195
    {
196
      obj->size = size;
197
      obj->templ = NULL;
198
    }
199
  if (obj->align < align)
200
    obj->align = align;
201
  if (templ && size == obj->size)
202
    obj->templ = templ;
203
}