Subversion Repositories Kolibri OS

Rev

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