summaryrefslogtreecommitdiff
path: root/include/private/thread_local_alloc.h
blob: 32b6a3e5fe6024013f1415441e8da1046cd17f94 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
/* 
 * Copyright (c) 2000-2005 by Hewlett-Packard Company.  All rights reserved.
 *
 * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
 * OR IMPLIED.  ANY USE IS AT YOUR OWN RISK.
 *
 * Permission is hereby granted to use or copy this program
 * for any purpose,  provided the above notices are retained on all copies.
 * Permission to modify the code and to distribute modified code is granted,
 * provided the above notices are retained, and a notice that the code was
 * modified is included with the above copyright notice.
 */

/* Included indirectly from a thread-library-specific file.	*/
/* This is the interface for thread-local allocation, whose	*/
/* implementation is mostly thread-library-independent.		*/
/* Here we describe only the interface that needs to be known	*/
/* and invoked from the thread support layer;  the actual	*/
/* implementation also exports GC_malloc and friends, which	*/
/* are declared in gc.h.					*/

#include "private/gc_priv.h"

#if defined(THREAD_LOCAL_ALLOC)

#include "gc_inline.h"


# if defined USE_HPUX_TLS
#   error USE_HPUX_TLS macro was replaced by USE_COMPILER_TLS
# endif

# if !defined(USE_PTHREAD_SPECIFIC) && !defined(USE_WIN32_SPECIFIC) && \
     !defined(USE_WIN32_COMPILER_TLS) && !defined(USE_COMPILER_TLS) && \
     !defined(USE_CUSTOM_SPECIFIC)
#   if defined(MSWIN32) || defined(MSWINCE) || defined(CYGWIN32)
#     if defined(__GNUC__)  /* Fixed for versions past 2.95? */
#       define USE_WIN32_SPECIFIC
#     else
#       define USE_WIN32_COMPILER_TLS
#     endif /* !GNU */
#   elif defined(LINUX) && !defined(ARM32) && \
		 (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >=3))
#     define USE_COMPILER_TLS
#   elif (defined(GC_DGUX386_THREADS) || defined(GC_OSF1_THREADS) || \
         defined(GC_DARWIN_THREADS) || defined(GC_AIX_THREADS)) || \
	 defined(GC_NETBSD_THREADS)
#     define USE_PTHREAD_SPECIFIC
#   elif defined(GC_HPUX_THREADS)
#     ifdef __GNUC__
#      define USE_PTHREAD_SPECIFIC
         /* Empirically, as of gcc 3.3, USE_COMPILER_TLS doesn't work.	*/
#     else
#      define USE_COMPILER_TLS
#     endif
#   else
#     define USE_CUSTOM_SPECIFIC  /* Use our own.	*/
#   endif
# endif

# include <stdlib.h>

/* One of these should be declared as the tlfs field in the	*/
/* structure pointed to by a GC_thread.				*/
typedef struct thread_local_freelists {
#   ifdef THREAD_LOCAL_ALLOC
	void * ptrfree_freelists[TINY_FREELISTS];
	void * normal_freelists[TINY_FREELISTS];
#	ifdef GC_GCJ_SUPPORT
	  void * gcj_freelists[TINY_FREELISTS];
#	  define ERROR_FL ((void *)(word)-1)
	  	/* Value used for gcj_freelist[-1]; allocation is 	*/
	  	/* erroneous.						*/
#	endif
		/* Free lists contain either a pointer or a small count */
		/* reflecting the number of granules allocated at that	*/
		/* size.						*/
		/* 0 ==> thread-local allocation in use, free list	*/
		/*       empty.						*/
		/* > 0, <= DIRECT_GRANULES ==> Using global allocation,	*/
		/*       too few objects of this size have been		*/
		/* 	 allocated by this thread.			*/
		/* >= HBLKSIZE  => pointer to nonempty free list.	*/
		/* > DIRECT_GRANULES, < HBLKSIZE ==> transition to	*/
		/*    local alloc, equivalent to 0.			*/
#	define DIRECT_GRANULES (HBLKSIZE/GRANULE_BYTES)
		/* Don't use local free lists for up to this much 	*/
		/* allocation.						*/

#   endif
} *GC_tlfs;

# if defined(USE_PTHREAD_SPECIFIC)
#   define GC_getspecific pthread_getspecific
#   define GC_setspecific pthread_setspecific
#   define GC_key_create pthread_key_create
#   define GC_remove_specific(key)  /* No need for cleanup on exit. */
    typedef pthread_key_t GC_key_t;
# elif defined(USE_COMPILER_TLS) || defined(USE_WIN32_COMPILER_TLS)
#   define GC_getspecific(x) (x)
#   define GC_setspecific(key, v) ((key) = (v), 0)
#   define GC_key_create(key, d) 0
#   define GC_remove_specific(key)  /* No need for cleanup on exit. */
    typedef void * GC_key_t;
# elif defined(USE_WIN32_SPECIFIC)
#   include <windows.h>
#   define GC_getspecific TlsGetValue
#   define GC_setspecific(key, v) !TlsSetValue(key, v)
    	/* We assume 0 == success, msft does the opposite.	*/
#   define GC_key_create(key, d)  \
	((d) != 0? (ABORT("Destructor unsupported by TlsAlloc"),0) \
	 	 : ((*(key) = TlsAlloc()) == TLS_OUT_OF_INDEXES? \
		       (ABORT("Out of tls"), 0): \
		       0))
#   define GC_remove_specific(key)  /* No need for cleanup on thread exit. */
    	/* Need TlsFree on process exit/detach ? */
    typedef DWORD GC_key_t;
# elif defined(USE_CUSTOM_SPECIFIC)
#   include "private/specific.h"
# else
#   error implement me
# endif


/* Each thread structure must be initialized.	*/
/* This call must be made from the new thread.	*/
/* Caller holds allocation lock.		*/
void GC_init_thread_local(GC_tlfs p);

/* Called when a thread is unregistered, or exits.	*/
/* We hold the allocator lock.				*/
void GC_destroy_thread_local(GC_tlfs p);

/* The thread support layer must arrange to mark thread-local	*/
/* free lists explicitly, since the link field is often 	*/
/* invisible to the marker.  It knows how to find all threads;	*/
/* we take care of an individual thread freelist structure.	*/
void GC_mark_thread_local_fls_for(GC_tlfs p);

extern
#if defined(USE_COMPILER_TLS)
  __thread
#elif defined(USE_WIN32_COMPILER_TLS)
  __declspec(thread)
#endif
GC_key_t GC_thread_key;

/* This is set up by the thread_local_alloc implementation.  But the	*/
/* thread support layer calls GC_remove_specific(GC_thread_key)		*/
/* before a thread exits.						*/
/* And the thread support layer makes sure that GC_thread_key is traced,*/
/* if necessary.							*/

#endif /* THREAD_LOCAL_ALLOC */