summaryrefslogtreecommitdiff
path: root/debian/patches/libpthread_tls.patch
diff options
context:
space:
mode:
Diffstat (limited to 'debian/patches/libpthread_tls.patch')
-rw-r--r--debian/patches/libpthread_tls.patch331
1 files changed, 331 insertions, 0 deletions
diff --git a/debian/patches/libpthread_tls.patch b/debian/patches/libpthread_tls.patch
new file mode 100644
index 00000000..245ef081
--- /dev/null
+++ b/debian/patches/libpthread_tls.patch
@@ -0,0 +1,331 @@
+Add TLS support
+TODO: drop threadvar support
+---
+ libpthread/pthread/pt-create.c | 7 ++++
+ libpthread/pthread/pt-exit.c | 3 ++
+ libpthread/pthread/pt-internal.h | 19 ++++++++++++
+ libpthread/sysdeps/mach/hurd/ia32/pt-machdep.c | 37 ++++++++++++++++++++++---
+ libpthread/sysdeps/mach/hurd/ia32/pt-setup.c | 7 +++-
+ libpthread/sysdeps/mach/hurd/pt-docancel.c | 4 +-
+ libpthread/sysdeps/mach/hurd/pt-sysdep.h | 10 ++++--
+ libthreads/alpha/thread.c | 1
+ libthreads/cprocs.c | 3 +-
+ libthreads/cthread_internals.h | 16 ++++++++++
+ libthreads/i386/thread.c | 32 +++++++++++++++++++--
+ 11 files changed, 122 insertions(+), 17 deletions(-)
+
+--- a/libpthread/pthread/pt-create.c
++++ b/libpthread/pthread/pt-create.c
+@@ -129,6 +129,11 @@ __pthread_create_internal (struct __pthr
+ if (err)
+ goto failed_thread_alloc;
+
++ pthread->tcb = _dl_allocate_tls (NULL);
++ if (!pthread->tcb)
++ goto failed_thread_tls_alloc;
++ pthread->tcb->tcb = pthread->tcb;
++
+ /* And initialize the rest of the machine context. This may include
+ additional machine- and system-specific initializations that
+ prove convenient. */
+@@ -194,6 +199,8 @@ __pthread_create_internal (struct __pthr
+ failed_sigstate:
+ __pthread_sigstate_destroy (pthread);
+ failed_setup:
++ _dl_deallocate_tls (pthread->tcb, 1);
++ failed_thread_tls_alloc:
+ __pthread_thread_dealloc (pthread);
+ __pthread_thread_halt (pthread);
+ failed_thread_alloc:
+--- a/libpthread/pthread/pt-exit.c
++++ b/libpthread/pthread/pt-exit.c
+@@ -70,6 +70,9 @@ pthread_exit (void *status)
+ if (self->cancel_state == PTHREAD_CANCEL_ENABLE && self->cancel_pending)
+ status = PTHREAD_CANCELED;
+
++ if (self->tcb)
++ _dl_deallocate_tls (self->tcb, 1);
++
+ switch (self->state)
+ {
+ default:
+--- a/libpthread/pthread/pt-internal.h
++++ b/libpthread/pthread/pt-internal.h
+@@ -54,6 +54,14 @@ enum pthread_state
+ # define PTHREAD_SYSDEP_MEMBERS
+ #endif
+
++/* Type of the TCB. */
++typedef struct
++{
++ void *tcb; /* Points to this structure. */
++ void *dtv; /* Vector of pointers to TLS data. */
++ thread_t self; /* This thread's control port. */
++} tcbhead_t;
++
+ /* This structure describes a POSIX thread. */
+ struct __pthread
+ {
+@@ -89,6 +97,8 @@ struct __pthread
+
+ PTHREAD_SYSDEP_MEMBERS
+
++ tcbhead_t *tcb;
++
+ struct __pthread *next, **prevp;
+ };
+
+@@ -287,4 +297,13 @@ const struct __pthread_rwlockattr __pthr
+ /* Default condition attributes. */
+ const struct __pthread_condattr __pthread_default_condattr;
+
++
++/* From glibc. */
++
++/* Dynamic linker TLS allocation. */
++extern void *_dl_allocate_tls(void *);
++
++/* Dynamic linker TLS deallocation. */
++extern void _dl_deallocate_tls(void *, int);
++
+ #endif /* pt-internal.h */
+--- a/libpthread/sysdeps/mach/hurd/pt-docancel.c
++++ b/libpthread/sysdeps/mach/hurd/pt-docancel.c
+@@ -52,8 +52,8 @@ __pthread_do_cancel (struct __pthread *p
+ err = __thread_abort (p->kernel_thread);
+ assert_perror (err);
+
+- err = __thread_set_pcsp (p->kernel_thread,
+- 1, (void *) call_exit, 0, 0);
++ err = __thread_set_pcsptp (p->kernel_thread,
++ 1, (void *) call_exit, 0, 0, 0, 0);
+ assert_perror (err);
+
+ err = __thread_resume (p->kernel_thread);
+--- a/libpthread/sysdeps/mach/hurd/pt-sysdep.h
++++ b/libpthread/sysdeps/mach/hurd/pt-sysdep.h
+@@ -60,11 +60,13 @@ __pthread_stack_dealloc (void *stackaddr
+ __vm_deallocate (__mach_task_self (), (vm_offset_t) stackaddr, stacksize);
+ }
+
+-/* Change thread THREAD's program counter to PC if SET_PC is true and
+- its stack pointer to SP if SET_IP is true. */
+-extern int __thread_set_pcsp (thread_t thread,
++/* Change thread THREAD's program counter to PC if SET_PC is true,
++ its stack pointer to SP if SET_IP is true, and its thread pointer
++ to TP if SET_TP is true. */
++extern int __thread_set_pcsptp (thread_t thread,
+ int set_pc, void *pc,
+- int set_sp, void *sp);
++ int set_sp, void *sp,
++ int set_tp, void *tp);
+
+
+ #endif /* pt-sysdep.h */
+--- a/libpthread/sysdeps/mach/hurd/ia32/pt-machdep.c
++++ b/libpthread/sysdeps/mach/hurd/ia32/pt-machdep.c
+@@ -21,12 +21,28 @@
+
+ #include <mach.h>
+ #include <mach/i386/thread_status.h>
++#include <mach/i386/mach_i386.h>
++#include <mach/mig_errors.h>
+ #include <mach/thread_status.h>
+
++#define HURD_TLS_DESC_DECL(desc, tcb) \
++ struct descriptor desc = \
++ { /* low word: */ \
++ 0xffff /* limit 0..15 */ \
++ | (((unsigned int) (tcb)) << 16) /* base 0..15 */ \
++ , /* high word: */ \
++ ((((unsigned int) (tcb)) >> 16) & 0xff) /* base 16..23 */ \
++ | ((0x12 | 0x60 | 0x80) << 8) /* access = ACC_DATA_W|ACC_PL_U|ACC_P */ \
++ | (0xf << 16) /* limit 16..19 */ \
++ | ((4 | 8) << 20) /* granularity = SZ_32|SZ_G */ \
++ | (((unsigned int) (tcb)) & 0xff000000) /* base 24..31 */ \
++ }
++
+ int
+-__thread_set_pcsp (thread_t thread,
++__thread_set_pcsptp (thread_t thread,
+ int set_ip, void *ip,
+- int set_sp, void *sp)
++ int set_sp, void *sp,
++ int set_tp, void *tp)
+ {
+ error_t err;
+ struct i386_thread_state state;
+@@ -34,7 +50,7 @@ __thread_set_pcsp (thread_t thread,
+
+ state_count = i386_THREAD_STATE_COUNT;
+
+- err = __thread_get_state (thread, i386_THREAD_STATE,
++ err = __thread_get_state (thread, i386_REGS_SEGS_STATE,
+ (thread_state_t) &state, &state_count);
+ if (err)
+ return err;
+@@ -43,8 +59,21 @@ __thread_set_pcsp (thread_t thread,
+ state.uesp = (unsigned int) sp;
+ if (set_ip)
+ state.eip = (unsigned int) ip;
++ if (set_tp) {
++ HURD_TLS_DESC_DECL(desc, tp);
++ int sel;
++
++ asm ("mov %%gs, %w0" : "=q" (sel) : "0" (0));
++ if (__builtin_expect (sel, 0x48) & 4) /* LDT selector */
++ err = __i386_set_ldt (thread, sel, &desc, 1);
++ else
++ err = __i386_set_gdt (thread, &sel, desc);
++ if (err)
++ return err;
++ state.gs = sel;
++ }
+
+- err = __thread_set_state (thread, i386_THREAD_STATE,
++ err = __thread_set_state (thread, i386_REGS_SEGS_STATE,
+ (thread_state_t) &state,
+ i386_THREAD_STATE_COUNT);
+ if (err)
+--- a/libpthread/sysdeps/mach/hurd/ia32/pt-setup.c
++++ b/libpthread/sysdeps/mach/hurd/ia32/pt-setup.c
+@@ -91,12 +91,15 @@ __pthread_setup (struct __pthread *threa
+ thread->mcontext.pc = entry_point;
+ thread->mcontext.sp = stack_setup (thread, start_routine, arg);
+
++ thread->tcb->self = thread->kernel_thread;
++
+ ktid = __mach_thread_self ();
+ if (thread->kernel_thread != ktid)
+ {
+- err = __thread_set_pcsp (thread->kernel_thread,
++ err = __thread_set_pcsptp (thread->kernel_thread,
+ 1, thread->mcontext.pc,
+- 1, thread->mcontext.sp);
++ 1, thread->mcontext.sp,
++ 1, thread->tcb);
+ assert_perror (err);
+ }
+ __mach_port_deallocate (__mach_task_self (), ktid);
+--- a/libthreads/cprocs.c
++++ b/libthreads/cprocs.c
+@@ -730,10 +730,11 @@ cproc_create(void)
+ spin_lock(&n_kern_lock);
+ if (cthread_max_kernel_threads == 0 ||
+ cthread_kernel_threads < cthread_max_kernel_threads) {
++ tcbhead_t *tcb = _dl_allocate_tls(NULL);
+ cthread_kernel_threads++;
+ spin_unlock(&n_kern_lock);
+ MACH_CALL(thread_create(mach_task_self(), &n), r);
+- cproc_setup(child, n, cthread_body); /* machine dependent */
++ cproc_setup(child, n, tcb, cthread_body); /* machine dependent */
+ MACH_CALL(thread_resume(n), r);
+ #ifdef STATISTICS
+ spin_lock(&ready_lock);
+--- a/libthreads/cthread_internals.h
++++ b/libthreads/cthread_internals.h
+@@ -166,6 +166,14 @@
+ # endif
+ #endif
+
++/* Type of the TCB. */
++typedef struct
++{
++ void *tcb; /* Points to this structure. */
++ void *dtv; /* Vector of pointers to TLS data. */
++ thread_t self; /* This thread's control port. */
++} tcbhead_t;
++
+ /*
+ * Low-level thread implementation.
+ * This structure must agree with struct ur_cthread in cthreads.h
+@@ -312,4 +320,10 @@ extern void cproc_prepare(cproc_t _chil
+ void (*cthread_body_pc)());
+
+ extern void cproc_setup(cproc_t _child, thread_t _mach_thread,
+- void (*_routine)(cproc_t));
++ tcbhead_t *tcb, void (*_routine)(cproc_t));
++
++
++/* From glibc. */
++
++/* Dynamic linker TLS allocation. */
++extern void *_dl_allocate_tls(void *);
+--- a/libthreads/alpha/thread.c
++++ b/libthreads/alpha/thread.c
+@@ -74,6 +74,7 @@ void
+ cproc_setup(
+ register cproc_t child,
+ thread_t thread,
++ tcbhead_t *tcb, /* TODO */
+ void (*routine)(cproc_t))
+ {
+ register integer_t *top;
+--- a/libthreads/i386/thread.c
++++ b/libthreads/i386/thread.c
+@@ -75,6 +75,21 @@ char rcs_id[] = "$Header: /cvsroot/hurd/
+ #include <cthreads.h>
+ #include "cthread_internals.h"
+ #include <mach.h>
++#include <mach/i386/mach_i386.h>
++#include <mach/mig_errors.h>
++
++#define HURD_TLS_DESC_DECL(desc, tcb) \
++ struct descriptor desc = \
++ { /* low word: */ \
++ 0xffff /* limit 0..15 */ \
++ | (((unsigned int) (tcb)) << 16) /* base 0..15 */ \
++ , /* high word: */ \
++ ((((unsigned int) (tcb)) >> 16) & 0xff) /* base 16..23 */ \
++ | ((0x12 | 0x60 | 0x80) << 8) /* access = ACC_DATA_W|ACC_PL_U|ACC_P */ \
++ | (0xf << 16) /* limit 16..19 */ \
++ | ((4 | 8) << 20) /* granularity = SZ_32|SZ_G */ \
++ | (((unsigned int) (tcb)) & 0xff000000) /* base 24..31 */ \
++ }
+
+ /*
+ * Set up the initial state of a MACH thread
+@@ -82,7 +97,7 @@ char rcs_id[] = "$Header: /cvsroot/hurd/
+ * when it is resumed.
+ */
+ void
+-cproc_setup(register cproc_t child, thread_t thread, void (*routine)(cproc_t))
++cproc_setup(register cproc_t child, thread_t thread, tcbhead_t *tcb, void (*routine)(cproc_t))
+ {
+ extern unsigned int __hurd_threadvar_max; /* GNU */
+ register int *top = (int *)
+@@ -95,13 +110,15 @@ cproc_setup(register cproc_t child, thre
+ register struct i386_thread_state *ts = &state;
+ kern_return_t r;
+ unsigned int count;
++ HURD_TLS_DESC_DECL(desc, tcb);
++ int sel;
+
+ /*
+ * Set up i386 call frame and registers.
+ * Read registers first to get correct segment values.
+ */
+ count = i386_THREAD_STATE_COUNT;
+- MACH_CALL(thread_get_state(thread,i386_THREAD_STATE,(thread_state_t) &state,&count),r);
++ MACH_CALL(thread_get_state(thread,i386_REGS_SEGS_STATE,(thread_state_t) &state,&count),r);
+
+ ts->eip = (int) routine;
+ *--top = (int) child; /* argument to function */
+@@ -109,7 +126,16 @@ cproc_setup(register cproc_t child, thre
+ ts->uesp = (int) top; /* set stack pointer */
+ ts->ebp = 0; /* clear frame pointer */
+
+- MACH_CALL(thread_set_state(thread,i386_THREAD_STATE,(thread_state_t) &state,i386_THREAD_STATE_COUNT),r);
++ asm ("mov %%gs, %w0" : "=q" (sel) : "0" (0));
++ tcb->tcb = tcb;
++ tcb->self = thread;
++ if (__builtin_expect (sel, 0x48) & 4) /* LDT selector */
++ __i386_set_ldt (thread, sel, &desc, 1);
++ else
++ __i386_set_gdt (thread, &sel, desc);
++ ts->gs = sel;
++
++ MACH_CALL(thread_set_state(thread,i386_REGS_SEGS_STATE,(thread_state_t) &state,i386_THREAD_STATE_COUNT),r);
+ }
+
+ #if defined(cthread_sp)