Subversion Repositories Kolibri OS

Rev

Rev 4349 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
4349 Serge 1
/* TLS emulation.
2
   Copyright (C) 2006, 2008, 2009 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
 
27
#include 
28
#include 
29
#include 
30
#include 
31
 
32
void *tls_alloc(void);
33
void __mutex_lock(volatile int *val);
34
 
35
 
36
static inline void yield(void)
37
{
38
    __asm__ __volatile__(
39
    "int $0x40"
40
    ::"a"(68), "b"(1));
41
};
42
 
43
int __gthread_once (__gthread_once_t *once, void (*func) (void))
44
{
45
    if (once == NULL || func == NULL)
46
        return EINVAL;
47
 
48
    if (! once->done)
49
    {
50
        if(++once->started == 0)
51
        {
52
            (*func) ();
53
            once->done = 1;
54
        }
55
        else
56
        {
57
      /* Another thread is currently executing the code, so wait for it
58
         to finish; yield the CPU in the meantime.  If performance
59
         does become an issue, the solution is to use an Event that
60
         we wait on here (and set above), but that implies a place to
61
         create the event before this routine is called.  */
62
            while (! once->done)
63
                yield();
64
        }
65
    }
66
    return 0;
67
}
68
 
69
 
70
#define __GTHREAD_ONCE_INIT {0, -1}
71
 
72
typedef unsigned int word __attribute__((mode(word)));
73
typedef unsigned int pointer __attribute__((mode(pointer)));
74
 
75
struct __emutls_object
76
{
77
  word size;
78
  word align;
79
  union {
80
    pointer offset;
81
    void *ptr;
82
  } loc;
83
  void *templ;
84
};
85
 
86
struct __emutls_array
87
{
88
  pointer size;
89
  void **data[];
90
};
91
 
92
void *__emutls_get_address (struct __emutls_object *);
93
void __emutls_register_common (struct __emutls_object *, word, word, void *);
94
 
95
static __gthread_mutex_t emutls_mutex;
96
static __gthread_key_t   emutls_key;
97
static pointer           emutls_size;
98
 
99
static void emutls_destroy (void *ptr)
100
{
101
    struct __emutls_array *arr = ptr;
102
    pointer size = arr->size;
103
    pointer i;
104
 
105
    for (i = 0; i < size; ++i)
106
    {
107
        if (arr->data[i])
108
            free (arr->data[i][-1]);
109
    }
110
    free (ptr);
111
};
112
 
113
static void emutls_init (void)
114
{
115
    if (__gthread_key_create (&emutls_key, emutls_destroy) != 0)
116
        abort ();
117
}
118
 
119
static void *emutls_alloc (struct __emutls_object *obj)
120
{
121
    void *ptr;
122
    void *ret;
123
 
124
  /* We could use here posix_memalign if available and adjust
125
     emutls_destroy accordingly.  */
126
    if (obj->align <= sizeof (void *))
127
    {
128
        ptr = malloc (obj->size + sizeof (void *));
129
        if (ptr == NULL)
130
            abort ();
131
        ((void **) ptr)[0] = ptr;
132
        ret = ptr + sizeof (void *);
133
    }
134
    else
135
    {
136
        ptr = malloc (obj->size + sizeof (void *) + obj->align - 1);
137
        if (ptr == NULL)
138
            abort ();
139
        ret = (void *) (((pointer) (ptr + sizeof (void *) + obj->align - 1))
140
              & ~(pointer)(obj->align - 1));
141
        ((void **) ret)[-1] = ptr;
142
    }
143
 
144
    if (obj->templ)
145
        memcpy (ret, obj->templ, obj->size);
146
    else
147
        memset (ret, 0, obj->size);
148
 
149
    return ret;
150
}
151
 
152
void * __emutls_get_address (struct __emutls_object *obj)
153
{
154
    pointer offset = obj->loc.offset;
155
 
156
    if (__builtin_expect (offset == 0, 0))
157
    {
158
        static __gthread_once_t once = __GTHREAD_ONCE_INIT;
159
        __gthread_once (&once, emutls_init);
160
        __gthread_mutex_lock (&emutls_mutex);
161
        offset = obj->loc.offset;
162
        if (offset == 0)
163
        {
164
            offset = ++emutls_size;
165
            obj->loc.offset = offset;
166
        }
167
        __gthread_mutex_unlock (&emutls_mutex);
168
    }
169
 
170
    struct __emutls_array *arr = __gthread_getspecific (emutls_key);
171
    if (__builtin_expect (arr == NULL, 0))
172
    {
173
        pointer size = offset + 32;
174
        arr = calloc (size + 1, sizeof (void *));
175
        if (arr == NULL)
176
            abort ();
177
        arr->size = size;
178
        __gthread_setspecific (emutls_key, (void *) arr);
179
    }
180
    else if (__builtin_expect (offset > arr->size, 0))
181
    {
182
        pointer orig_size = arr->size;
183
        pointer size = orig_size * 2;
184
        if (offset > size)
185
            size = offset + 32;
186
        arr = realloc (arr, (size + 1) * sizeof (void *));
187
        if (arr == NULL)
188
            abort ();
189
        arr->size = size;
190
        memset (arr->data + orig_size, 0,
191
               (size - orig_size) * sizeof (void *));
192
        __gthread_setspecific (emutls_key, (void *) arr);
193
    }
194
 
195
    void *ret = arr->data[offset - 1];
196
    if (__builtin_expect (ret == NULL, 0))
197
    {
198
        ret = emutls_alloc (obj);
199
        arr->data[offset - 1] = ret;
200
    }
201
  return ret;
202
}
203
 
204
 
205
void __emutls_register_common (struct __emutls_object *obj,
206
              word size, word align, void *templ)
207
{
208
    if (obj->size < size)
209
    {
210
        obj->size = size;
211
        obj->templ = NULL;
212
    }
213
    if (obj->align < align)
214
        obj->align = align;
215
    if (templ && size == obj->size)
216
        obj->templ = templ;
217
}