musl/src/internal/pthread_impl.h

110 lines
2.5 KiB
C
Raw Normal View History

2011-02-12 00:22:29 -05:00
#ifndef _PTHREAD_IMPL_H
#define _PTHREAD_IMPL_H
#include <pthread.h>
#include <sched.h>
#include <signal.h>
#include <unistd.h>
#include <sys/mman.h>
#include <errno.h>
#include <limits.h>
#include <inttypes.h>
#include <setjmp.h>
#include <string.h>
#include <time.h>
2011-05-30 01:41:23 -04:00
#include <locale.h>
2011-02-12 00:22:29 -05:00
#include "libc.h"
#include "syscall.h"
#include "atomic.h"
#include "futex.h"
#define pthread __pthread
struct pthread {
struct pthread *self;
unsigned long tlsdesc[4];
2011-02-12 00:22:29 -05:00
pid_t tid, pid;
int tsd_used, errno_val, *errno_ptr;
volatile uintptr_t cp_sp, cp_ip;
volatile int cancel, canceldisable, cancelasync;
2011-02-12 00:22:29 -05:00
unsigned char *map_base;
size_t map_size;
void *start_arg;
void *(*start)(void *);
void *result;
int detached;
int exitlock;
struct __ptcb *cancelbuf;
void **tsd;
pthread_attr_t attr;
volatile int dead;
struct {
void **head;
long off;
void *pending;
} robust_list;
int unblock_cancel;
int delete_timer;
2011-05-30 01:41:23 -04:00
locale_t locale;
int killlock;
2011-02-12 00:22:29 -05:00
};
struct __timer {
int timerid;
pthread_t thread;
};
#define __SU (sizeof(size_t)/sizeof(int))
#define _a_stacksize __u.__s[0]
#define _a_guardsize __u.__s[1]
#define _a_detach __u.__i[2*__SU+0]
#define _m_type __u.__i[0]
#define _m_lock __u.__i[1]
#define _m_waiters __u.__i[2]
#define _m_prev __u.__p[3]
#define _m_next __u.__p[4]
#define _m_count __u.__i[5]
#define _c_block __u.__i[0]
#define _c_clock __u.__i[1]
#define _rw_wrlock __u.__i[0]
#define _rw_readers __u.__i[1]
#define _rw_waiters __u.__i[2]
#define _rw_owner __u.__i[3]
#define _b_inst __u.__p[0]
#define _b_limit __u.__i[2]
#define _b_lock __u.__i[3]
#define _b_waiters __u.__i[4]
#include "pthread_arch.h"
2011-02-12 00:22:29 -05:00
#define SIGTIMER 32
#define SIGCANCEL 33
new attempt at making set*id() safe and robust changing credentials in a multi-threaded program is extremely difficult on linux because it requires synchronizing the change between all threads, which have their own thread-local credentials on the kernel side. this is further complicated by the fact that changing the real uid can fail due to exceeding RLIMIT_NPROC, making it possible that the syscall will succeed in some threads but fail in others. the old __rsyscall approach being replaced was robust in that it would report failure if any one thread failed, but in this case, the program would be left in an inconsistent state where individual threads might have different uid. (this was not as bad as glibc, which would sometimes even fail to report the failure entirely!) the new approach being committed refuses to change real user id when it cannot temporarily set the rlimit to infinity. this is completely POSIX conformant since POSIX does not require an implementation to allow real-user-id changes for non-privileged processes whatsoever. still, setting the real uid can fail due to memory allocation in the kernel, but this can only happen if there is not already a cached object for the target user. thus, we forcibly serialize the syscalls attempts, and fail the entire operation on the first failure. this *should* lead to an all-or-nothing success/failure result, but it's still fragile and highly dependent on kernel developers not breaking things worse than they're already broken. ideally linux will eventually add a CLONE_USERCRED flag that would give POSIX conformant credential changes without any hacks from userspace, and all of this code would become redundant and could be removed ~10 years down the line when everyone has abandoned the old broken kernels. i'm not holding my breath...
2011-07-29 22:59:44 -04:00
#define SIGSYNCCALL 34
#define SIGPT_SET ((sigset_t *)(unsigned long [1+(sizeof(long)==4)]){ \
[sizeof(long)==4] = 3UL<<(32*(sizeof(long)>4)) })
#define SIGTIMER_SET ((sigset_t *)(unsigned long [1+(sizeof(long)==4)]){ \
0x80000000 })
2011-02-12 00:22:29 -05:00
pthread_t __pthread_self_init(void);
int __set_thread_area(void *);
2011-02-12 00:22:29 -05:00
int __libc_sigaction(int, const struct sigaction *, struct sigaction *);
int __libc_sigprocmask(int, const sigset_t *, sigset_t *);
void __lock(volatile int *);
void __unmapself(void *, size_t);
int __timedwait(volatile int *, int, clockid_t, const struct timespec *, int);
int __timedwait_cp(volatile int *, int, clockid_t, const struct timespec *, int);
2011-02-12 00:22:29 -05:00
void __wait(volatile int *, volatile int *, int, int);
void __wake(volatile int *, int, int);
new attempt at making set*id() safe and robust changing credentials in a multi-threaded program is extremely difficult on linux because it requires synchronizing the change between all threads, which have their own thread-local credentials on the kernel side. this is further complicated by the fact that changing the real uid can fail due to exceeding RLIMIT_NPROC, making it possible that the syscall will succeed in some threads but fail in others. the old __rsyscall approach being replaced was robust in that it would report failure if any one thread failed, but in this case, the program would be left in an inconsistent state where individual threads might have different uid. (this was not as bad as glibc, which would sometimes even fail to report the failure entirely!) the new approach being committed refuses to change real user id when it cannot temporarily set the rlimit to infinity. this is completely POSIX conformant since POSIX does not require an implementation to allow real-user-id changes for non-privileged processes whatsoever. still, setting the real uid can fail due to memory allocation in the kernel, but this can only happen if there is not already a cached object for the target user. thus, we forcibly serialize the syscalls attempts, and fail the entire operation on the first failure. this *should* lead to an all-or-nothing success/failure result, but it's still fragile and highly dependent on kernel developers not breaking things worse than they're already broken. ideally linux will eventually add a CLONE_USERCRED flag that would give POSIX conformant credential changes without any hacks from userspace, and all of this code would become redundant and could be removed ~10 years down the line when everyone has abandoned the old broken kernels. i'm not holding my breath...
2011-07-29 22:59:44 -04:00
void __synccall_lock();
void __synccall_unlock();
2011-02-12 00:22:29 -05:00
#define DEFAULT_STACK_SIZE (16384-PAGE_SIZE)
#define DEFAULT_GUARD_SIZE PAGE_SIZE
#endif