From 4cd6a4a5d7e49d54d53dcf4a6f3393d50bd88e8b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gwenol=C3=A9=20Beauchesne?= Date: Wed, 4 Jun 2003 18:44:09 +0000 Subject: Import dietlibc 0.22 + other fixes for AMD64 --- mdk-stage1/dietlibc/libpthread/pthread_equal.c | 3 + mdk-stage1/dietlibc/libpthread/pthread_errno.c | 5 + mdk-stage1/dietlibc/libpthread/pthread_fdglue2.c | 16 + mdk-stage1/dietlibc/libpthread/pthread_fgetc.c | 10 + mdk-stage1/dietlibc/libpthread/pthread_flockfile.c | 5 + mdk-stage1/dietlibc/libpthread/pthread_fputc.c | 9 + .../dietlibc/libpthread/pthread_funlockfile.c | 5 + .../dietlibc/libpthread/pthread_getschedparam.c | 22 ++ mdk-stage1/dietlibc/libpthread/pthread_internal.c | 359 +++++++++++++++++++++ mdk-stage1/dietlibc/libpthread/pthread_key.c | 48 +++ .../dietlibc/libpthread/pthread_setschedparam.c | 21 ++ mdk-stage1/dietlibc/libpthread/pthread_sigmask.c | 8 + .../dietlibc/libpthread/pthread_sys_fdatasync.c | 10 + 13 files changed, 521 insertions(+) create mode 100644 mdk-stage1/dietlibc/libpthread/pthread_equal.c create mode 100644 mdk-stage1/dietlibc/libpthread/pthread_errno.c create mode 100644 mdk-stage1/dietlibc/libpthread/pthread_fdglue2.c create mode 100644 mdk-stage1/dietlibc/libpthread/pthread_fgetc.c create mode 100644 mdk-stage1/dietlibc/libpthread/pthread_flockfile.c create mode 100644 mdk-stage1/dietlibc/libpthread/pthread_fputc.c create mode 100644 mdk-stage1/dietlibc/libpthread/pthread_funlockfile.c create mode 100644 mdk-stage1/dietlibc/libpthread/pthread_getschedparam.c create mode 100644 mdk-stage1/dietlibc/libpthread/pthread_internal.c create mode 100644 mdk-stage1/dietlibc/libpthread/pthread_key.c create mode 100644 mdk-stage1/dietlibc/libpthread/pthread_setschedparam.c create mode 100644 mdk-stage1/dietlibc/libpthread/pthread_sigmask.c create mode 100644 mdk-stage1/dietlibc/libpthread/pthread_sys_fdatasync.c (limited to 'mdk-stage1/dietlibc/libpthread') diff --git a/mdk-stage1/dietlibc/libpthread/pthread_equal.c b/mdk-stage1/dietlibc/libpthread/pthread_equal.c new file mode 100644 index 000000000..d054d86ed --- /dev/null +++ b/mdk-stage1/dietlibc/libpthread/pthread_equal.c @@ -0,0 +1,3 @@ +#include + +int pthread_equal(pthread_t thread1, pthread_t thread2) { return (thread1==thread2); } diff --git a/mdk-stage1/dietlibc/libpthread/pthread_errno.c b/mdk-stage1/dietlibc/libpthread/pthread_errno.c new file mode 100644 index 000000000..d035544ad --- /dev/null +++ b/mdk-stage1/dietlibc/libpthread/pthread_errno.c @@ -0,0 +1,5 @@ +int errno; + +#include "dietwarning.h" + +link_warning("errno","\e[1;33;41m>>> your multithreaded code uses errno! <<<\e[0m"); diff --git a/mdk-stage1/dietlibc/libpthread/pthread_fdglue2.c b/mdk-stage1/dietlibc/libpthread/pthread_fdglue2.c new file mode 100644 index 000000000..d73c84220 --- /dev/null +++ b/mdk-stage1/dietlibc/libpthread/pthread_fdglue2.c @@ -0,0 +1,16 @@ +#include "dietstdio.h" +#include +#include +#include +#include +#include +#include + +extern int __stdio_atexit; +extern FILE* __stdio_init_file_nothreads(int fd,int closeonerror); + +FILE* __stdio_init_file(int fd,int closeonerror) { + FILE *tmp=__stdio_init_file_nothreads(fd,closeonerror); + if (tmp) pthread_mutex_init(&tmp->m,0); + return tmp; +} diff --git a/mdk-stage1/dietlibc/libpthread/pthread_fgetc.c b/mdk-stage1/dietlibc/libpthread/pthread_fgetc.c new file mode 100644 index 000000000..34e79e0fe --- /dev/null +++ b/mdk-stage1/dietlibc/libpthread/pthread_fgetc.c @@ -0,0 +1,10 @@ +#include "dietstdio.h" +#include + +int fgetc(FILE *stream) { + int tmp; + pthread_mutex_lock(&stream->m); + tmp=fgetc_unlocked(stream); + pthread_mutex_unlock(&stream->m); + return tmp; +} diff --git a/mdk-stage1/dietlibc/libpthread/pthread_flockfile.c b/mdk-stage1/dietlibc/libpthread/pthread_flockfile.c new file mode 100644 index 000000000..72131ffb1 --- /dev/null +++ b/mdk-stage1/dietlibc/libpthread/pthread_flockfile.c @@ -0,0 +1,5 @@ +#include "dietstdio.h" + +void flockfile(FILE* f) { + pthread_mutex_lock(&f->m); +} diff --git a/mdk-stage1/dietlibc/libpthread/pthread_fputc.c b/mdk-stage1/dietlibc/libpthread/pthread_fputc.c new file mode 100644 index 000000000..82344b107 --- /dev/null +++ b/mdk-stage1/dietlibc/libpthread/pthread_fputc.c @@ -0,0 +1,9 @@ +#include + +int fputc(int c, FILE *stream) { + int tmp; + pthread_mutex_lock(&stream->m); + tmp=fputc_unlocked(c,stream); + pthread_mutex_unlock(&stream->m); + return tmp; +} diff --git a/mdk-stage1/dietlibc/libpthread/pthread_funlockfile.c b/mdk-stage1/dietlibc/libpthread/pthread_funlockfile.c new file mode 100644 index 000000000..beae058af --- /dev/null +++ b/mdk-stage1/dietlibc/libpthread/pthread_funlockfile.c @@ -0,0 +1,5 @@ +#include "dietstdio.h" + +void funlockfile(FILE* f) { + pthread_mutex_unlock(&f->m); +} diff --git a/mdk-stage1/dietlibc/libpthread/pthread_getschedparam.c b/mdk-stage1/dietlibc/libpthread/pthread_getschedparam.c new file mode 100644 index 000000000..aaaba4458 --- /dev/null +++ b/mdk-stage1/dietlibc/libpthread/pthread_getschedparam.c @@ -0,0 +1,22 @@ +#include +#include + +#include +#include "thread_internal.h" + +int pthread_getschedparam(pthread_t target_thread, int *policy, struct sched_param *param) +{ + int p; + __THREAD_INIT(); + + if (__find_thread_id(target_thread)<0) { + return ESRCH; + } + + if (((p=sched_getscheduler(target_thread))==-1)|| + (sched_getparam(target_thread,param) ==-1)) { + return (*(__errno_location())); + } + *policy=p; + return 0; +} diff --git a/mdk-stage1/dietlibc/libpthread/pthread_internal.c b/mdk-stage1/dietlibc/libpthread/pthread_internal.c new file mode 100644 index 000000000..7bb4e16cb --- /dev/null +++ b/mdk-stage1/dietlibc/libpthread/pthread_internal.c @@ -0,0 +1,359 @@ +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include "thread_internal.h" + +static struct _pthread_fastlock __thread_struct_lock = {PTHREAD_SPIN_UNLOCKED}; +static struct _pthread_descr_struct threads[PTHREAD_THREADS_MAX]; +static int _max_used_thread_id=1; +pthread_once_t __thread_inited; + +static struct _pthread_fastlock __manager_thread_signal_lock = {PTHREAD_SPIN_UNLOCKED}; +static struct _pthread_fastlock __manager_thread_data_lock = {PTHREAD_SPIN_LOCKED}; +static struct _pthread_fastlock __manager_thread_data_go_lock = {PTHREAD_SPIN_LOCKED}; + +//#define DEBUG + +/* find thread */ +int __find_thread_id(int pid) +{ + register int i; + for (i=0; i<_max_used_thread_id; i++) + if (threads[i].pid==pid) + return i; + return -1; +} + +/* get thread */ +_pthread_descr __get_thread_struct(int id) +{ + return threads+id; +} + +/* thread errno location */ +int *__errno_location(void) +{ + int id=0; + if (__thread_inited) id=__find_thread_id(getpid()); + if (id<0) + return 0; + else + return &threads[id].errno; +} + +/* thread self */ +_pthread_descr __thread_self() +{ + register int i=__find_thread_id(getpid()); + if (i<0) + return 0; + else + return threads+i; +} + +/* allocate a thread slot */ +_pthread_descr __thread_get_free() +{ + _pthread_descr ret=0; + int i; + + __NO_ASYNC_CANCEL_BEGIN; + __pthread_lock(&__thread_struct_lock); + + for (i=0; ipid=1; /* mark as taken */ + if (i>=_max_used_thread_id) _max_used_thread_id=i+1; + break; + } + } + + __pthread_unlock(&__thread_struct_lock); + __NO_ASYNC_CANCEL_END; + return ret; +} + +/* sleep a little (reschedule for this time) */ +void __thread_wait_some_time() +{ + struct timespec reg; + reg.tv_sec=0; + reg.tv_nsec=SPIN_SLEEP_DURATION; + __libc_nanosleep(®,0); +} + +/* cleanup/join a thread */ +int __thread_join(_pthread_descr th, void**return_value) +{ + /* mark thread th as joined */ + if (__testandset(&(th->joined))) return EINVAL; + /* wait for thread to exit */ + while(!th->exited) __thread_wait_some_time(); + /* put return value to caller */ + if (return_value) *return_value=th->retval; + /* cleanup thread */ + if (th->stack_begin) free(th->stack_begin); + th->joined=0; + th->pid=0; + return 0; +} + +/* SIGHUP handler (thread cancel) PTHREAD_CANCEL_ASYNCHRONOUS */ +static void __thread_cancel_handler(int sig) +{ + _pthread_descr this; + this = __thread_self(); + this->canceled=1; + if (this->canceltype==PTHREAD_CANCEL_ASYNCHRONOUS) + pthread_exit(PTHREAD_CANCELED); + signal( SIGHUP, __thread_cancel_handler ); +} + +/* kill ALL threads / other then prime task and manager thread */ +static void __kill_all_threads() +{ + int i; + + for (i=2; i<_max_used_thread_id; i++) { + if (threads[i].pid>1) { +#ifdef DEBUG + printf("CANCEL ! %d\n",threads[i].pid); +#endif + threads[i].canceled=1; + kill(threads[i].pid, SIGHUP); /* cancel thread */ + } + } + + __thread_wait_some_time(); + + for (i=2; i<_max_used_thread_id; i++) { + if (threads[i].pid>1) { +#ifdef DEBUG + printf("KILL ! %d\n",threads[i].pid); +#endif + kill(threads[i].pid, SIGTERM); /* KILL thread */ + } + } +} + +__attribute__((weak)) volatile void __thread_start__key(int id); +__attribute__((weak)) volatile void __thread_start__key(int id) { return; } +__attribute__((weak,alias("__thread_start__key"))) volatile void __thread_exit__key(int id); + +/* support for manager */ +static void *__mthread_starter(void *arg) +{ + _pthread_descr td = (_pthread_descr)arg; + int i = td->stack_size-4096; + + /* just to be sure */ + td->pid=getpid(); + + /* signal handling for a thread */ + signal(SIGTERM, _exit); + signal(SIGCHLD, SIG_DFL); + signal(SIGHUP, __thread_cancel_handler ); + + /* limit stack so that we NEVER have to worry */ + setrlimit(RLIMIT_STACK, (struct rlimit *)(&i)); + + /* set scheduler */ + if (td->policy!=SCHED_OTHER) { + struct sched_param sp; + sp.sched_priority=td->priority; + sched_setscheduler(td->pid,td->policy, &sp); + } + + /* thread_key glue */ + __thread_start__key(td-threads); + +#ifdef DEBUG + printf("in starter %d, parameter %8p\n", td->pid, td->func); +#endif + do { + __thread_wait_some_time(); + if (td->canceled) return (void*)42; + } while (__pthread_trylock(&td->go)); + +#ifdef DEBUG + printf("post starter %d, parameter %8p\n", td->pid, td->func); +#endif + + if (!td->canceled) { + if (!(setjmp(td->jmp_exit))) { + td->retval=td->func(td->arg); +#ifdef DEBUG + } else { + printf("pthread_exit called in %d\n", td->pid); +#endif + } + } + pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED,0); + + /* thread_key glue */ + __thread_exit__key(td-threads); + +#ifdef DEBUG + printf("end starter %d, retval %8p\n", td->pid, td->retval); +#endif + + /* execute all functions on the cleanup-stack */ + for (i=PTHREAD_MAX_CLEANUP;i;) { + if (td->cleanup_stack[--i].func) { + td->cleanup_stack[i].func(td->cleanup_stack[i].arg); + } + } + + return 0; +} + + +/* manager thread and signal handler */ +static char __manager_thread_stack[12*1024]; +static volatile _pthread_descr __manager_thread_data; +static void __manager_SIGCHLD(int sig) +{ + int pid, status, i; + + while(1) { + pid = __libc_waitpid (-1, &status, WNOHANG); + if (pid <= 0) break; + + for (i=0; i<_max_used_thread_id; i++) { + if (threads[i].pid==pid) { + ++threads[i].exited; + if (threads[i].detached) { + threads[i].joined=0; + __thread_cleanup(threads+i); + } + break; + } + } + } +} + +static void __manager_SIGTERM(int sig) +{ + __kill_all_threads(); + _exit(0); +} + +static void* __manager_thread(void *arg) +{ + struct sigaction sig_action_chld; + sig_action_chld.sa_handler = __manager_SIGCHLD; + sigemptyset(&sig_action_chld.sa_mask); + sig_action_chld.sa_flags = SA_RESTART; + + sigaction(SIGCHLD, &sig_action_chld, 0); + signal(SIGTERM, __manager_SIGTERM); + signal(SIGHUP, SIG_IGN); + + __pthread_unlock(&__manager_thread_data_go_lock); /* release init */ + while(1) { + do { + __thread_wait_some_time(); + if (getppid()<2) __manager_SIGTERM(0); + } while (__pthread_trylock(&__manager_thread_data_lock)); + + __manager_thread_data->pid = + __clone(__mthread_starter, + __manager_thread_data->stack_addr, + CLONE_VM | CLONE_FS | CLONE_FILES | SIGCHLD, + __manager_thread_data); + __thread_wait_some_time(); + __thread_wait_some_time(); + __pthread_unlock(&__manager_thread_data->go); +#ifdef DEBUG + printf("manager new thread %d\n",__manager_thread_data->pid); +#endif + __pthread_unlock(&__manager_thread_data_go_lock); /* release sender */ + } + return 0; +} + +/* pthread_create bottom half */ +int signal_manager_thread(_pthread_descr td) +{ + __NO_ASYNC_CANCEL_BEGIN; + + __pthread_lock(&__manager_thread_signal_lock); /* lock */ + + __manager_thread_data = td; + __thread_wait_some_time(); + __pthread_unlock(&__manager_thread_data_lock); /* signal manager to start */ + __thread_wait_some_time(); + __pthread_lock(&__manager_thread_data_go_lock); /* wait for manager */ + + __pthread_unlock(&__manager_thread_signal_lock); /* unlock */ + + __NO_ASYNC_CANCEL_END; + + return td->pid; +} + + +/* thread stop */ +static void __thread_main_exit() +{ + if (getpid()!=threads[0].pid) { +#ifdef DEBUG + printf("A THREAD ? %d\n",getpid()); +#endif + kill(threads[0].pid, SIGTERM); + while(1) __thread_wait_some_time(); + } +#ifdef DEBUG + else + printf("EXIT ! %d\n",getpid()); +#endif + + /* stop ALL threads */ + kill(threads[1].pid, SIGTERM); + __thread_wait_some_time(); + __kill_all_threads(); +} + +/* thread intern init */ +void __thread_init() +{ + if (atexit(__thread_main_exit)==-1) + exit(42); + +#ifdef DEBUG + printf("INIT ! %d\n",getpid()); + memset(threads,0,sizeof(threads)); +#endif + + threads[0].pid = getpid(); + + ++_max_used_thread_id; + threads[1].stack_size=sizeof(__manager_thread_stack); +#ifdef __parisc__ + threads[1].stack_addr=__manager_thread_stack; +#else + threads[1].stack_addr=&__manager_thread_stack[sizeof(__manager_thread_stack)]; +#endif + threads[1].stack_begin=0; + threads[1].func=__manager_thread; + + threads[1].pid = __clone(__mthread_starter, threads[1].stack_addr, + CLONE_VM | CLONE_FS | CLONE_FILES, threads+1); + +#ifdef DEBUG + printf("manager thread @ : %d\n",threads[1].pid); +#endif + __pthread_lock(&__manager_thread_data_go_lock); /* wait for manager to be ready */ +} + diff --git a/mdk-stage1/dietlibc/libpthread/pthread_key.c b/mdk-stage1/dietlibc/libpthread/pthread_key.c new file mode 100644 index 000000000..8a77f281a --- /dev/null +++ b/mdk-stage1/dietlibc/libpthread/pthread_key.c @@ -0,0 +1,48 @@ +#include +#include + +#include +#include "thread_internal.h" + +struct _pthread_fastlock __thread_keys_lock; +struct _thread_key __thread_keys[PTHREAD_KEYS_MAX]; + +void __thread_start__key(int id); +void __thread_exit__key(int id); + +void __thread_start__key(int id) +{ + int i; + + if (id<2) return; + + __NO_ASYNC_CANCEL_BEGIN; + __pthread_lock(&__thread_keys_lock); + + for (i=0; i +#include + +#include +#include "thread_internal.h" + +int pthread_setschedparam(pthread_t target_thread, int policy, const struct sched_param *param) +{ + __THREAD_INIT(); + + if (__find_thread_id(target_thread)<0) { + return ESRCH; + } + + if (((policy == SCHED_OTHER) && (param->sched_priority==0)) || + (((policy == SCHED_RR) || (policy == SCHED_FIFO)) && + ((param->sched_priority > 0) && (param->sched_priority <100)))) + return sched_setscheduler(target_thread, policy, param); + + return EINVAL; +} diff --git a/mdk-stage1/dietlibc/libpthread/pthread_sigmask.c b/mdk-stage1/dietlibc/libpthread/pthread_sigmask.c new file mode 100644 index 000000000..691e9e51a --- /dev/null +++ b/mdk-stage1/dietlibc/libpthread/pthread_sigmask.c @@ -0,0 +1,8 @@ +#include +#include + +#include + +int pthread_sigmask(int how, const sigset_t*newset, sigset_t *oldset) { + return (sigprocmask(how,newset,oldset)==-1)?(*(__errno_location())):0; +} diff --git a/mdk-stage1/dietlibc/libpthread/pthread_sys_fdatasync.c b/mdk-stage1/dietlibc/libpthread/pthread_sys_fdatasync.c new file mode 100644 index 000000000..69857c7b3 --- /dev/null +++ b/mdk-stage1/dietlibc/libpthread/pthread_sys_fdatasync.c @@ -0,0 +1,10 @@ +#include + +#include +#include "thread_internal.h" + +int fdatasync(int fd) +{ + __TEST_CANCEL(); + return __libc_fdatasync(fd); +} -- cgit v1.2.1