summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--libc/bionic/libc_init_common.c31
-rw-r--r--libc/bionic/libc_init_static.c5
-rw-r--r--libc/bionic/pthread.c9
-rw-r--r--libc/bionic/pthread_internal.h2
-rw-r--r--libc/private/bionic_tls.h3
-rw-r--r--linker/linker.c25
6 files changed, 48 insertions, 27 deletions
diff --git a/libc/bionic/libc_init_common.c b/libc/bionic/libc_init_common.c
index b6a6379..7fb1246 100644
--- a/libc/bionic/libc_init_common.c
+++ b/libc/bionic/libc_init_common.c
@@ -52,12 +52,19 @@ unsigned int __page_shift = PAGE_SHIFT;
int __system_properties_init(void);
-void __libc_init_common(uintptr_t *elfdata)
+/* Init TLS for the initial thread. Called by the linker _before_ libc is mapped
+ * in memory. Beware: all writes to libc globals from this function will
+ * apply to linker-private copies and will not be visible from libc later on.
+ *
+ * Note: this function creates a pthread_internal_t for the initial thread and
+ * stores the pointer in TLS, but does not add it to pthread's gThreadList. This
+ * has to be done later from libc itself (see __libc_init_common).
+ *
+ * This function also stores elfdata argument in a specific TLS slot to be later
+ * picked up by the libc constructor.
+ */
+void __libc_init_tls(unsigned** elfdata)
{
- int argc = *elfdata;
- char** argv = (char**)(elfdata + 1);
- char** envp = argv + argc + 1;
-
pthread_attr_t thread_attr;
static pthread_internal_t thread;
static void* tls_area[BIONIC_TLS_SLOTS];
@@ -72,7 +79,19 @@ void __libc_init_common(uintptr_t *elfdata)
_init_thread(&thread, gettid(), &thread_attr, (void*)stackbottom);
__init_tls(tls_area, &thread);
- /* clear errno - requires TLS area */
+ tls_area[TLS_SLOT_BIONIC_PREINIT] = elfdata;
+}
+
+void __libc_init_common(uintptr_t *elfdata)
+{
+ int argc = *elfdata;
+ char** argv = (char**)(elfdata + 1);
+ char** envp = argv + argc + 1;
+
+ /* get the initial thread from TLS and add it to gThreadList */
+ _pthread_internal_add(__get_thread());
+
+ /* clear errno */
errno = 0;
/* set program name */
diff --git a/libc/bionic/libc_init_static.c b/libc/bionic/libc_init_static.c
index a2c11a9..f97961d 100644
--- a/libc/bionic/libc_init_static.c
+++ b/libc/bionic/libc_init_static.c
@@ -65,6 +65,11 @@ __noreturn void __libc_init(uintptr_t *elfdata,
int argc;
char **argv, **envp;
+ __libc_init_tls(NULL);
+
+ /* get the initial thread from TLS and add it to gThreadList */
+ _pthread_internal_add(__get_thread());
+
/* Initialize the C runtime environment */
__libc_init_common(elfdata);
diff --git a/libc/bionic/pthread.c b/libc/bionic/pthread.c
index fdfe508..5cad167 100644
--- a/libc/bionic/pthread.c
+++ b/libc/bionic/pthread.c
@@ -145,7 +145,7 @@ _pthread_internal_remove( pthread_internal_t* thread )
pthread_mutex_unlock(&gThreadListLock);
}
-static void
+__LIBC_ABI_PRIVATE__ void
_pthread_internal_add( pthread_internal_t* thread )
{
pthread_mutex_lock(&gThreadListLock);
@@ -157,7 +157,7 @@ _pthread_internal_add( pthread_internal_t* thread )
pthread_mutex_unlock(&gThreadListLock);
}
-pthread_internal_t*
+__LIBC_ABI_PRIVATE__ pthread_internal_t*
__get_thread(void)
{
void** tls = (void**)__get_tls();
@@ -217,6 +217,7 @@ void __thread_entry(int (*func)(void*), void *arg, void **tls)
pthread_exit( (void*)func(arg) );
}
+__LIBC_ABI_PRIVATE__
void _init_thread(pthread_internal_t * thread, pid_t kernel_id, pthread_attr_t * attr, void * stack_base)
{
if (attr == NULL) {
@@ -238,8 +239,6 @@ void _init_thread(pthread_internal_t * thread, pid_t kernel_id, pthread_attr_t *
thread->join_count = 0;
thread->cleanup_stack = NULL;
-
- _pthread_internal_add(thread);
}
@@ -371,6 +370,8 @@ int pthread_create(pthread_t *thread_out, pthread_attr_t const * attr,
_init_thread(thread, tid, (pthread_attr_t*)attr, stack);
+ _pthread_internal_add(thread);
+
if (!madestack)
thread->attr.flags |= PTHREAD_ATTR_FLAG_USER_STACK;
diff --git a/libc/bionic/pthread_internal.h b/libc/bionic/pthread_internal.h
index 655b8f3..268cacf 100644
--- a/libc/bionic/pthread_internal.h
+++ b/libc/bionic/pthread_internal.h
@@ -47,6 +47,8 @@ typedef struct pthread_internal_t
} pthread_internal_t;
extern void _init_thread(pthread_internal_t * thread, pid_t kernel_id, pthread_attr_t * attr, void * stack_base);
+void _pthread_internal_add( pthread_internal_t* thread );
+pthread_internal_t* __get_thread(void);
/* needed by posix-timers.c */
diff --git a/libc/private/bionic_tls.h b/libc/private/bionic_tls.h
index 008fd2f..af19554 100644
--- a/libc/private/bionic_tls.h
+++ b/libc/private/bionic_tls.h
@@ -134,6 +134,9 @@ extern void* __get_tls( void );
/* return the stack base and size, used by our malloc debugger */
extern void* __get_stack_base(int *p_stack_size);
+/* Initialize the TLS. */
+extern void __libc_init_tls(unsigned** elfdata);
+
__END_DECLS
#endif /* _SYS_TLS_H */
diff --git a/linker/linker.c b/linker/linker.c
index 9805b35..6b6282d 100644
--- a/linker/linker.c
+++ b/linker/linker.c
@@ -2054,10 +2054,6 @@ static void parse_preloads(const char *path, char *delim)
}
}
-#define ANDROID_TLS_SLOTS BIONIC_TLS_SLOTS
-
-static void * __tls_area[ANDROID_TLS_SLOTS];
-
/*
* This code is called after the linker has linked itself and
* fixed it's own GOT. It is safe to make references to externs
@@ -2076,18 +2072,6 @@ static unsigned __linker_init_post_relocation(unsigned **elfdata)
const char *ldpath_env = NULL;
const char *ldpreload_env = NULL;
- /* Setup a temporary TLS area that is used to get a working
- * errno for system calls.
- */
- __set_tls(__tls_area);
-
- pid = getpid();
-
-#if TIMING
- struct timeval t0, t1;
- gettimeofday(&t0, 0);
-#endif
-
/* NOTE: we store the elfdata pointer on a special location
* of the temporary TLS area in order to pass it to
* the C Library's runtime initializer.
@@ -2096,7 +2080,14 @@ static unsigned __linker_init_post_relocation(unsigned **elfdata)
* to point to a different location to ensure that no other
* shared library constructor can access it.
*/
- __tls_area[TLS_SLOT_BIONIC_PREINIT] = elfdata;
+ __libc_init_tls(elfdata);
+
+ pid = getpid();
+
+#if TIMING
+ struct timeval t0, t1;
+ gettimeofday(&t0, 0);
+#endif
/* Initialize environment functions, and get to the ELF aux vectors table */
vecs = linker_env_init(vecs);